Sunday, January 4, 2009

Tapestry 5 with Scala

I just tested to use Scala for the code used in components for Tapestry 5. For now, all seems to work great !

I just created a default project with the quick-start archetype, changed Index.java and AppModule.java to Index.scala and AppModule.scala respectively, added some render-phase handler in Index, add a filter in AppModule, and all worked fine...

Expect one crucial thing: T5 requires that properties annotated @Persist are not initialized with a default value.

This is due to the fact that T5 components / pages are pooled, and so are instantiated prior to their used, and after use are cleaned and send back to the pool.
The problem is the clean stage: T5 as to know what is a "clean" value for the one managed by the framework - @Persist-ed one the first. That's hard to know for statefull object... as for example a collection of phone numbers, or some credential: T5 can not know effectively if a statefull object state changed, so it can only let it as it is, or nullify it. Nullify it expose you to NPE (because as a developer, you thought the initialization was done on class instantiation), and you don't want to see this kind of information to be badly cleaned and so, maybe leaked elsewhere, when the class in pool is used again.

OK, so it's a good thing that T5 does not let you fire on your foot, and throws an exception if you try to set a default value to such a managed property.
Except... that Scala requires that variable or values have a default value. So for now, I can't use persisted field for components, what is quite a limit :/

I'm going to continue the experiment, to if Scala and Tapestry 5 can be used together, or if I will have to use Scala only for deeper layers of my application (and well, perhaps at last, I will have to try Groovy for the upper layer...)


UPDATE: there seems to be some problem with the IOC, so that will be hard...
Symptoms are that the field is read-only, I will have to look more carefully at the difference between Scala var and Java properties...

EDIT: Thanks a lot too James Iry who pointed to me that the variable initialization should be done with "_" : that's the solution. So just use "Persist var name:String = _", and it works.

2 comments:

James Iry

Use private fields and Java style getter/setters and the bytecode should be essentially identical to what Java produces except that Scala also automatically generates its own style of getters and setters.

~/test> cat Test.scala
class Test {
private var foo : String = _
def setFoo(foo : String) = this.foo = foo
def getFoo : String = foo
}
~/test> scalac Test.scala
~/test> javap -c -private Test
Compiled from "Test.scala"
public class Test extends java.lang.Object implements scala.ScalaObject{
private java.lang.String foo;

public Test();
Code:
0: aload_0
1: invokespecial #12; //Method java/lang/Object."<init>":()V
4: return

public java.lang.String getFoo();
Code:
0: aload_0
1: invokespecial #18; //Method foo:()Ljava/lang/String;
4: areturn

public void setFoo(java.lang.String);
Code:
0: aload_0
1: aload_1
2: invokespecial #23; //Method foo_$eq:(Ljava/lang/String;)V
5: return

private void foo_$eq(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #28; //Field foo:Ljava/lang/String;
5: return

private java.lang.String foo();
Code:
0: aload_0
1: getfield #28; //Field foo:Ljava/lang/String;
4: areturn

public int $tag() throws java.rmi.RemoteException;
Code:
0: aload_0
1: invokestatic #36; //Method scala/ScalaObject$class.$tag:(Lscala/ScalaObject;)I
4: ireturn

}

James Iry

Oh, also note the use of _ to initialize the foo field.

  © Blogger template 'Minimalist G' by Ourblogtemplates.com 2008

Back to TOP