Scala to JavaScript DSL ...

18 views
Skip to first unread message

Marius Danciu

unread,
Dec 12, 2009, 5:07:08 AM12/12/09
to lif...@googlegroups.com
All,

I just want to see if there is any interest in the approach discussed here. As you know Lift has some interesting support for building JavaScript constructs from Scala code usig JsExp, JsCmd etc classes. I used quite a lot this support and it's great but if your JS code that you want to send down to the browser (say as an Ajax or Comet partial update response) gets a bit more complicated then constructing the JS fragment leads IMO to some cumbersome Scala code. I found myselft in quite a few situation to use JsRaw to write the JavaScript fragment in order for the code reader to understand what JavaScript code will be generated. But of course with JsRaw we put everything into a String so I'm not a big fan of this approach. So I started to define a JavaScript like "DSL" that IMO is closer to JavaScript form. Attached is a source code smaple of how this looks like, so for instance we can have something like:


val js = JsFunc('myFunc, 'param1, 'param2) {
    JsIf('param1 __< 30) {
        Var('home) := Wrap(234 __- 3) __/ 2 `;`
        Var('someArray) := JsArray(1, 2, 3, 4, 5) `;`
        'myFunc(1, 2, "do it", 'home) `;`
        $("#myID") >> 'attr("value", "123") `;`
      } ~
      JsForEach(Var('i) in 'someArray) {
        'console >> 'log("Hi there " __+ 'i) `;`
      } ~
      JsAnonFunc('arg1, 'arg2) {
       'alert("Anonymous function " __+ 'arg1 __+ 'arg2)
      }(1, 2) `;`
    }

    println(js.toJs)

this yields the following JavaScript code:


function myFunc( param1, param2 ) {
if (param1 < 30) {
var home = ( 234 - 3 ) / 2;
var someArray = [ 1, 2, 3, 4, 5 ];
myFunc(1, 2, "do it", home);
$("#myID").attr("value", "123");
}
for (var i in someArray) {
console.log("Hi there " + i);
}
function ( arg1, arg2 ) {
alert("Anonymous function " + arg1 + arg2)
}(1, 2);
}


... ok I just droped nonsense code in there for exemplification. A few words:

1. JsIf, JsForEach describe JavaScript if and for(each) statements
2. Functions like __<, __>, ... __+, __- are function that alows definition of boolean and/or algebraic expressions.
3. Wrap just wraps an expression into ()
4. Var defined a variable
5 := defines an assignment
6. JsFunc declares a JS function
7. JsAnonFunc declares an anonymous function
8. 'myFunc(1, 2, "do it", 'home)  is simply a javascript function invocation by providing 4 parameter.
9. ~ is just a function that chains statements that don;t necessarily end in ;


Do you think that something like this would be usable in Lift?

Br's,
Marius
App.scala

Timothy Perrett

unread,
Dec 12, 2009, 5:34:31 AM12/12/09
to lif...@googlegroups.com
Hey Marius,

Within this DSL will you be using JsObj under the hood or lift-json?

I would be very reluctant about adding new things to lift that don't
unify our Js and JSON libs.

On this note, will this unification take place before 2.0?

Cheers, Tim

Sent from my iPhone
> --
>
> You received this message because you are subscribed to the Google
> Groups "Lift" group.
> To post to this group, send email to lif...@googlegroups.com.
> To unsubscribe from this group, send email to liftweb+u...@googlegroups.com
> .
> For more options, visit this group at http://groups.google.com/group/liftweb?hl=en
> .
> <App.scala>

Marius

unread,
Dec 12, 2009, 6:09:43 AM12/12/09
to Lift
My notes inline.

On Dec 12, 12:34 pm, Timothy Perrett <timo...@getintheloop.eu> wrote:
> Hey Marius,
>
> Within this DSL will you be using JsObj under the hood or lift-json?

I was thinking to use lift-json in this case ... but I'd also of
prefer having a lift-js project.

>
> I would be very reluctant about adding new things to lift that don't  
> unify our Js and JSON libs.

Depends what you mean by unify. lift-json is not the same with js
support, js should utilize lift-json to build json constructs being
part of the javascript generated but lift-json has nothing to to with
a potential lift-js project. Therefore I would keep lift-json and lift-
js separated and have lift-js utilize lift-json whenever possible.

>
> On this note, will this unification take place before 2.0?

Too soon to tell. I'm not sure yet if people like this proposal so we
first need acceptance and then talk schedules.

>
> Cheers, Tim
>
> Sent from my iPhone
>

Indrajit Raychaudhuri

unread,
Dec 12, 2009, 11:44:04 AM12/12/09
to lif...@googlegroups.com

On 12/12/09 4:39 PM, Marius wrote:
> My notes inline.
>
> On Dec 12, 12:34 pm, Timothy Perrett<timo...@getintheloop.eu> wrote:
>> Hey Marius,
>>
>> Within this DSL will you be using JsObj under the hood or lift-json?
>
> I was thinking to use lift-json in this case ... but I'd also of
> prefer having a lift-js project.
>
>>
>> I would be very reluctant about adding new things to lift that don't
>> unify our Js and JSON libs.
>
> Depends what you mean by unify. lift-json is not the same with js
> support, js should utilize lift-json to build json constructs being
> part of the javascript generated but lift-json has nothing to to with
> a potential lift-js project. Therefore I would keep lift-json and lift-
> js separated and have lift-js utilize lift-json whenever possible.

I would be hugely in favor of lift-js. I see lift-json deal with the
data container related functionality. This would be clearly demarcated
from lift-js (the scripting, method calls etc.) that is primarily used
for deeper framework level integration for building (mostly web)
applications.

In that sense, lift-webkit could also shed some weight in favor of
lift-js (parts of net.liftweb.http.js, for example). On one hand we
would have a neatly composed package with focused purpose and on the
other hand lift-webkit would feel 'lighter' to projects that don't need
any of the js functionality at all.

The dependency tree could look like (lower components depend on one or
more above them):

lift-common
lift-actor [1]
lift-json [1]
lift-util [2]
lift-js [2]
lift-webkit [3]

[1] Independent of each other currently.
[2] Can interchange depending on how things go.
[3] In some sense lift-webkit still ends up depending on lift-js
transitively. But that's better than 2.7M monolith :) It can even create
opportunity for marking lift-js as 'optional dependency' for lift-webkit.

In any case, this is a derived profit and doesn't have to be the primary
goal.

Marius

unread,
Dec 12, 2009, 1:09:21 PM12/12/09
to Lift
I agree. Although to be more specific I guess my proposal can be split
in 2:

1. The syntax style proposed that would probably evolve depending on
the feedback.
2. The existence of lift-js project.

Br's,
Marius

Alex Boisvert

unread,
Dec 12, 2009, 1:42:14 PM12/12/09
to lif...@googlegroups.com
Personally, I would rather go with a JavaScript literal and a simple templating mechanism for substitution/binding of Javascript literals + Json objects that would drive dynamic code (if conditionals, for-loops, ...).

Taking your example,

def myFunc = {"""

  function myFunc( param1, param2 ) {
    if (param1 < ${limit}) {
      var home = ( ${max} - 3 ) / 2;
      var someArray = ${array};

      myFunc(1, 2, "do it", home);
      $("#myID").attr("value", "123");
    }
    for (var i in ${someArray}) {

      console.log("Hi there " + i);
    }
    function ( arg1, arg2 ) {
      alert("Anonymous function " + arg1 + arg2)
    }(1, 2);
  }""".jsBind(
    "max" -> max,
    "array" -> array,
    "someArray" -> someArray,
    ...
  )

Not a fully fleshed out example but you get the idea.  You'd still be able to bind existing JsExp/JsCmds  so some parts could still be abstracted and typed checked. 

I would find this more readable and simpler that learning a quirky DSL syntax.  And I could still copy/paste Javascript code to/from the browser and test it easily.

alex

--

Marius

unread,
Dec 12, 2009, 2:06:51 PM12/12/09
to Lift
That is certainly one way to go but personally I'm not at all a fan of
this string literals approach,. For instance if Scala would not have
had built in XML support using XML as string literals Lift would
probably loose some of its attractions... but that's my opinion.
Furthermore a DSL like language allows better compositionality than
concatenating strings when we want to iteratively add JS code ... for
instance calling the same function multiple times with different
arguments, or collecting code fragments generated by different
application components etc.

Also it seems to me that your approach (somehow similar with
Velocity's) is more expensive but I admit that this is not at all a
strong argument because we're talking about small javascript fragments
so the delta is negligible.

Br's,
Marius
> > liftweb+u...@googlegroups.com<liftweb%2Bunsu...@googlegroups.com>
> > .

Alex Boisvert

unread,
Dec 13, 2009, 9:54:09 PM12/13/09
to lif...@googlegroups.com
On Sat, Dec 12, 2009 at 11:06 AM, Marius <marius...@gmail.com> wrote:
That is certainly one way to go but personally I'm not at all a fan of
this string literals approach,. For instance if Scala would not have
had built in XML support using XML as string literals Lift would
probably loose some of its attractions... but that's my opinion.

Agreed, XML is baked-in.  It's not a DSL built on top of other features.
 
Furthermore a DSL like language allows better compositionality than
concatenating strings when we want to iteratively add JS code ... for
instance calling the same function multiple times with different
arguments, or collecting code fragments generated by different
application components etc.

There's no guarantee of compositionality for DSLs.   You have to design it to be, and it's quite difficult to get right.   And then you pretty much reinvent another language.  First you have Scala, then you have Javascript, then you have something in between which is FrankenScalaScript.    Just my opinion :)

 
Also it seems to me that your approach (somehow similar with
Velocity's) is more expensive but I admit that this is not at all a
strong argument because we're talking about small javascript fragments
so the delta is negligible.

I would beg to differ but we're so far from any implementation of either to judge performance at this stage.

alex

Marius

unread,
Dec 14, 2009, 2:46:00 AM12/14/09
to Lift


On Dec 14, 4:54 am, Alex Boisvert <alex.boisv...@gmail.com> wrote:
> On Sat, Dec 12, 2009 at 11:06 AM, Marius <marius.dan...@gmail.com> wrote:
> > That is certainly one way to go but personally I'm not at all a fan of
> > this string literals approach,. For instance if Scala would not have
> > had built in XML support using XML as string literals Lift would
> > probably loose some of its attractions... but that's my opinion.
>
> Agreed, XML is baked-in.  It's not a DSL built on top of other features.
>
> > Furthermore a DSL like language allows better compositionality than
> > concatenating strings when we want to iteratively add JS code ... for
> > instance calling the same function multiple times with different
> > arguments, or collecting code fragments generated by different
> > application components etc.
>
> There's no guarantee of compositionality for DSLs.   You have to design it
> to be, and it's quite difficult to get right.   And then you pretty much
> reinvent another language.  First you have Scala, then you have Javascript,
> then you have something in between which is FrankenScalaScript.    Just my
> opinion :)

Yeah ... I'm also a little concerned about the "new syntax" but I
don't think that's such a big impediment. What I meant by
compositionality is that you can easily put together code fragments by
naturally using ~ or `;` functions and that's supported by the above
code. Similar with JsCmd & function. Also most function are taking JS
parameters which allows us to pass JS code (calls to other JS
functions or even pass functions and have higher order javascript
functions) as arguments to JS functions.

I know it's your opinion and I do respect it. To be honest I'm not a
huge DSL fun but in this context I really think it can help writing
JavaScript fragments from Scala code.

>
> > Also it seems to me that your approach (somehow similar with
> > Velocity's) is more expensive but I admit that this is not at all a
> > strong argument because we're talking about small javascript fragments
> > so the delta is negligible.
>
> I would beg to differ but we're so far from any implementation of either to
> judge performance at this stage.

Not judging ... just that the style you mentioned inherently implies
string parsing that is not necessary in the DSL approach.


Are there any other opinions out there?

>
> alex
Reply all
Reply to author
Forward
0 new messages