Wednesday, February 6, 2008

Scala Bean Properties

First of all, Scala isn't Java even if it's interoperable. That's a pro or a con depending on your perspective. But that's how it is.

For example, take this class:

class Whatever {
var name = "Tom"
}


As I've mentioned before, that generates accessor methods, not a public field. Scala is way more object oriented than Java.

But the accessor methods are named "name()" and "name_$eq()". Way more sane than Java in some ways, but not compatible with say, Hibernate. So until/unless such tools add Scala support, you need to be compatible on your own.

Well, Scala makes this one not too bad. Just add an annotation to generate standard Java "getName()" and "setName()" (in addition to the Scala-conforming accessors):

class Whatever {
@scala.reflect.BeanProperty
var name = "Tom"
}


Et voila. Or 'import scala.reflect._' to cut that down to simply '@BeanProperty'. Could be worse. Could use an IDE to generate source code. *Shudder*

8 comments:

  1. Hi,

    So if the field is val, will there be a setter generated? And also, is there a way to generate let say, only getter or only setter?

    I like your articles, keep up the good work :).

    ReplyDelete
  2. mateusz - based on my very limited understanding if the field is a "val" it will have a public getter and a private setter.

    So if I did something like

    val something = new Whatever()

    and then tried to output something.Name it would work but if I tried to change the value of something.Name I'd get an error like:

    variable Name cannot be accessed in Whatever

    ----

    Tom:
    I really know very little of Scala and I am not particularly familiar with the syntax you show for the accessors, specifically this one:
    name_$eq()

    What purpose does that serve? Thanks

    ReplyDelete
  3. Mateusz, vals generate only getters.

    Bill, 'name_$eq' is the Java name of the standard generated setter. From Scala, it looks like 'name_='. Here's a sample of writing the Scala getters and setters explicitly:

    class Whatever {
    def name = _name
    def name_=(name: String) {
    _name = name
    }
    private var _name = ""
    }

    Sad thing is that Scala wouldn't let me override a 'var' definition in a super class with explicit methods in a subclass. I hope it works with traits at least.

    ReplyDelete
  4. Thanks for the answers :).

    One thing more. I have seen the sth_= notation in several places. Is it some kind of apply/update for fields only? It would be hard to create a special class for each primitive type each time when declaring field. I have seen some discussion about properties in Scala, and i know there will be probably some change in the language. Do you know how this relates to "scala bean properties" ?

    Thanks

    ReplyDelete
  5. I'm not sure I understand the first question.

    Concerning the second question (the direction of properties in future versions of Scala), my answer is that I don't know. I've seen a couple comments along these lines, and that's all I know, too. I'm actually an outsider of the Scala crowd. I'm posting my own experiments and studies, and my experience goes only so far. For this one, I'll have to recommend going to scala-lang.org and following their community links to their mailing lists.

    ReplyDelete
  6. You can override vars defined in a trait.

    trait Wrap { var x:int; }

    val o1=new Wrap{var x=1;}
    val o2=new Wrap{
    var internal=3;def x=internal; def x_=(y:int) { internal= 2*y }
    }

    ReplyDelete
  7. henry, thanks for the answer and example.

    ReplyDelete
  8. Although I can't spot it in the changelog for 2.7.0 RC1 (out now) there is also now a @BeanInfo annotation:

    http://www.nabble.com/constructing-Java-Bean-Class%27s-getter-and-setters-ts15220344.html#a15221879

    ReplyDelete