Macro Annotations for upcoming talk

49 views
Skip to first unread message

Sebastian Nozzi

unread,
Sep 12, 2013, 5:59:41 PM9/12/13
to jscal...@googlegroups.com
Hi Alex,

in our upcoming meetup I'll talk about (and demo) JScala:


I would also like to mention and talk about upcoming features, such as the macro annotations.

Could you give me an idea (code snippet) of what such a code would look like? Note that I'm not asking about how you would implement it, but how it would be used (from a "user" / "developer using JScala" perspective).

Thanks!

Sebastian

Eugene Burmako

unread,
Sep 12, 2013, 6:00:41 PM9/12/13
to Sebastian Nozzi, jscal...@googlegroups.com
I second this motion!
> --
> You received this message because you are subscribed to the Google Groups "jscala-user" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jscala-user...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>

Alexander Nemish

unread,
Sep 13, 2013, 10:15:28 AM9/13/13
to jscal...@googlegroups.com, Sebastian Nozzi
Hi Sebastian,

Glad to hear about the meetup, I'm very interested in all the feedback. Is the meetup going to be a video?

Well, the basic idea would be that you write Scala code that could be run as Scala code and as a JavaScript.

I have an example of AES cipher implementation in Scala that using the same code I can encrypt a message in JavaScript and decrypt it using Scala. Yes, I know I shouldn't implement ciphers, that's just an example and it is fun :)

Basically, I write

@JavaScript
class AES(val key: Array[Int]) {
 // here goes Scala implementation
}

def main(args: Array[String]) {
   val data = "Kill all humans"
   val key = "secret key"
   val aes = new Aes(key)
   val encrypted = aes.encrypt(data)
    val aesJs = AES.javaScript
   val js = javascript {
     AES.javaScript
     val aes = new AES(inject(key))
     aes.decrypt(inject(encrypted))
   }
   decryptedInJs = js.eval()
   assert(decryptedInJs == data)
}


Also, you'll be able to share data and serialize/deserialize it to JSON automatically: 

@JavaScript
case class User(id: Int, name: String, birthdat: Date)

def getUser = {
  val newborn = new User(1, "Alex", new Date())
  newborn.asJson
}
def updateUser(json: String) {
 val user = User.fromJson(json)
 ...
}

javascript {
 val newborn = new User(1, "Alex", new Date())
 $.getJSON('ajax/getUser', (user: User) => $("#user").text(user.name));
 user.birthday = new Date();
 $.ajax(url = "ajax/updateUser", data = user.asJson(), dataType = "json")
}


You'll be able to write your both client-side and server-side code in Scala with its type safety, trait decomposition, IDE support (refactoring, navigation).

So, summary would be "Write once in Scala, run everywhere" :)

Cheers,
Alex Nemish
Twitter: @atlanter

Sergii Starodubtsev

unread,
Sep 13, 2013, 1:46:28 PM9/13/13
to jscal...@googlegroups.com, Sebastian Nozzi
This is very promising idea. Indeed! 

So, this project may safe my days. Hopefully.

Sergii Starodubtsev

unread,
Sep 13, 2013, 1:49:51 PM9/13/13
to jscal...@googlegroups.com, Sebastian Nozzi
I mean "save my days" 

Sebastian Nozzi

unread,
Sep 14, 2013, 6:14:50 AM9/14/13
to Alexander Nemish, JScala Mailing List
2013/9/13 Alexander Nemish <ane...@gmail.com>
Hi Sebastian,

Glad to hear about the meetup, I'm very interested in all the feedback. Is the meetup going to be a video?

Normally we don't record all of our talks. But I'll ask and arrange something.
 
Well, the basic idea would be that you write Scala code that could be run as Scala code and as a JavaScript.

I am missing something in the code snippet below... 
* What do you do with aesJs? (it was forgotten, right?)
* What do you do with the lone "AES.javaScript" line?
* What happens with js.eval()? The JS is executed by a JS engine on the Scala process? If yes, which one?

Thanks for sharing the example! When will we be able to enjoy this? ;-)
 

@JavaScript
class AES(val key: Array[Int]) {
 // here goes Scala implementation
}

def main(args: Array[String]) {
   val data = "Kill all humans"
   val key = "secret key"
   val aes = new Aes(key)
   val encrypted = aes.encrypt(data)
    val aesJs = AES.javaScript   // forgotten?
   val js = javascript {
     AES.javaScript  // why is this line needed?
     val aes = new AES(inject(key))
     aes.decrypt(inject(encrypted))
   }
   decryptedInJs = js.eval()  // what happens here exactly?
   assert(decryptedInJs == data)
}


Wow, this is a great feature also. Pretty much needed for web-development / Ajax calls... And a lot easier than what Play offers... 

Also, you'll be able to share data and serialize/deserialize it to JSON automatically: 

@JavaScript
case class User(id: Int, name: String, birthdate: Date)

def getUser = {
  val newborn = new User(1, "Alex", new Date())
  newborn.asJson
}
def updateUser(json: String) {
 val user = User.fromJson(json)
 ...
}

javascript {
 val newborn = new User(1, "Alex", new Date())
 $.getJSON('ajax/getUser', (user: User) => $("#user").text(user.name));
 user.birthday = new Date();
 $.ajax(url = "ajax/updateUser", data = user.asJson(), dataType = "json")
}
You'll be able to write your both client-side and server-side code in Scala with its type safety, trait decomposition, IDE support (refactoring, navigation).

So, summary would be "Write once in Scala, run everywhere" :)

+10000!!!

Thanks a lot for the "teaser" ;-)

Cheers,
Sebastian

Alexander Nemish

unread,
Sep 14, 2013, 2:17:34 PM9/14/13
to jscal...@googlegroups.com, Alexander Nemish, sebn...@googlemail.com


On Saturday, September 14, 2013 1:14:50 PM UTC+3, Sebastian Nozzi wrote:
2013/9/13 Alexander Nemish <ane...@gmail.com>
Hi Sebastian,

Glad to hear about the meetup, I'm very interested in all the feedback. Is the meetup going to be a video?

Normally we don't record all of our talks. But I'll ask and arrange something.

That would be just great.
 
 
Well, the basic idea would be that you write Scala code that could be run as Scala code and as a JavaScript.

I am missing something in the code snippet below... 
* What do you do with aesJs? (it was forgotten, right?)

Absolutely right, it was forgotten. I was writing the example directly in Google Groups, sorry.
 
* What do you do with the lone "AES.javaScript" line?

AES would be a generated companion object for class AES, that has the javaScript function (or whatever it will be called) that returns AES class JsAst representation.
Currently, JScala implicitly injects any function call that returns JsAst, so calling AES.javaScript inside javascript macro is equal to writing
val aesJsAst = () => AES.javaScript
javascript
{
  inject
(aesJsAst)
  val aes
= new AES(...)
}

This inject will basically include AES class definition into a JsAst returned by this javascript macro invocation. 
Here are some notes on injection: https://github.com/nau/jscala/wiki/Injection

 
* What happens with js.eval()? The JS is executed by a JS engine on the Scala process? If yes, which one?

Yes, the JS will be executed using standard Java ScriptEngine JavaScript implementation, Rhino. That was just an example, think as this code is passed to a browser and is executed there.

Updated example:

@JavaScript
class AES(val key: String) {
// here goes Scala implementation
}

def main(args: Array[String]) {
  val data = "Kill all humans"
  val key = "secret key"
  val aes = new Aes(key)
  val encrypted = aes.encrypt(data)
  val aesJsAst = () => AES.javaScript
  val js = javascript {
    inject(aesJsAst) /*include AES implementation into generated JavaScript*/
    val aes = new AES(inject(key))
    aes.decrypt(inject(encrypted))
  }
  decryptedInJs = js.eval()  /* generated JavaScript is executed using Java ScriptEngine, just as an example */
  assert(decryptedInJs == data) /* validate we got the same data we encripted */
}


 

Thanks for sharing the example! When will we be able to enjoy this? ;-)

Heh, good question. I'm working on this, though it's an "evening" project and I've got busy evenings recently :-/
Also, there are several differences working with def macros and annotation macros. Basically, macro annotation AST is not typechecked, so I don't have types for all the subtrees I need to generate valid JavaScript AST. I'll discuss these issues with Eugene Burmako, hopefully we'll be able to fix them eventually.
Thank you for your interest.

Cheers,
Alex Nemish
Twitter: @atlanter

 

Eugene Burmako

unread,
Sep 14, 2013, 3:14:31 PM9/14/13
to Alexander Nemish, jscal...@googlegroups.com, sebn...@googlemail.com
Looking forward to our discussion! I'll be travelling next week, but we could chat the week after next (if this works for you, of course).

By the way, why not auto-inject all companions of all @JavaScript classes used in the javascript block?


--

Sebastian Nozzi

unread,
Sep 14, 2013, 3:14:50 PM9/14/13
to Alexander Nemish, JScala Mailing List
Thanks for the updated snippets and the explanations!

Some additional comments / questions below:

2013/9/14 Alexander Nemish <ane...@gmail.com>
Yes, the JS will be executed using standard Java ScriptEngine JavaScript implementation, Rhino. That was just an example, think as this code is passed to a browser and is executed there.

Great. Can you imagine using this feature to unit-test the JS code from within Scala? :-O
 

Thanks for sharing the example! When will we be able to enjoy this? ;-)

Heh, good question. I'm working on this, though it's an "evening" project and I've got busy evenings recently :-/
Also, there are several differences working with def macros and annotation macros. Basically, macro annotation AST is not typechecked, so I don't have types for all the subtrees I need to generate valid JavaScript AST. I'll discuss these issues with Eugene Burmako, hopefully we'll be able to fix them eventually.

Hehe, I see... Now that you mention, which Scala version will this work on? Still 2.10? Or will 2.11 be needed?

Thanks again,
Sebastian
 

Eugene Burmako

unread,
Sep 14, 2013, 3:16:21 PM9/14/13
to sebn...@googlemail.com, Alexander Nemish, JScala Mailing List
Macro annotations are implemented in macro paradise which is a compiler plugin for Scala 2.10.


--

Naftoli Gugenheim

unread,
Sep 18, 2013, 3:18:04 AM9/18/13
to Eugene Burmako, jscal...@googlegroups.com, sebn...@googlemail.com, Alexander Nemish


On Sep 14, 2013 3:14 PM, "Eugene Burmako" <eugene....@epfl.ch> wrote:
>
> Looking forward to our discussion! I'll be travelling next week, but we could chat the week after next (if this works for you, of course).
>
> By the way, why not auto-inject all companions of all @JavaScript classes used in the javascript block?
>

Wouldn't that potentially result in duplicate definitions if it's used in multiple javascript blocks?

I was thinking of an analogue to inject, so you'd manually output in one place
javascript {
    define[AES]
}

Also I would rather that the method added to the companion have a more private, less collidable name, like __jscala_definition_ast. It would not be referenced by user source code, only be inserted to replace the call to define.

I'm hoping, G-d willing, to add at some point to reactive a javascript component dependency management capability, which might be in a better position to automate such things.

Anyway it really looks great and exciting!

Alexander Nemish

unread,
Sep 20, 2013, 6:22:11 AM9/20/13
to jscal...@googlegroups.com, Eugene Burmako, sebn...@googlemail.com, Alexander Nemish
Indeed, auto-injecting all companions could result in duplicate definitions.
Naftoli, I like your approach to injecting class definitions and agree on generating less collideable names, thank you.

Sebastian, as Eugene wrote, macro annotations will work on Scala 2.10 and Scala 2.11 with macro-paradise compiler plugin.
So, you'll need to add a following line in your sbt build definition:
settings = Seq(..., addCompilerPlugin("org.scala-lang.plugins" % "macro-paradise_2.10.3-RC1" % "2.0.0-SNAPSHOT"))
Reply all
Reply to author
Forward
0 new messages