logo       

Re: addJavaBeanMethods: msg#00036

lang.scala

Subject: Re: addJavaBeanMethods

Hi Ross

In the LAMP we had the idea to introduce an attribute that one can apply
to a variable to designate it as having Java Beans getter/setter. I just
added the scala.runtime.compat.BeanProperty class to use for that
purpose. The nice thing is, it only required a small change in the code
generator. But it lets you write

[BeanProperty]
var MyProperty: ...

and the generated accessors will be named getMyProperty/setMyProperty. I
don't do any capitalization (as seen in your example) so 'name' will
obtain getname/setname accessors.

There is one caveat to this solution. Currently, the attributes are not
dumped in the classfile. So if you use such variable from Scala code
with separate compilation the compiler will generate calls to the
getter/setter methods according to the Scala convention. If you compile
them together there should be no problem. In any case, we are working on
an overhaul of Scala's attributes support. Dumping attributes to the
classfile is one of the goals and will fix this problem.

I'm very much interested in feedback on this solution because no one
here is doing Java Beans and I might be overlooking sth.

Nikolay


On Thu, 2006-02-09 at 08:11 -0500, Judson, Ross wrote:
> I was thinking about Scala's property support and how nice it is, and it
> bothered me that Java tools wouldn't be able to see it. So I added this
> to the Scala compiler as an experiment (Typers.scala) and called it
> right after addSyntheticMethods:
>
> private def addJavaBeanMethods(cd: ClassDef, templ: Template):
> Template = {
>
> def checkBody(body: List[Tree]): List[Tree] = body match {
> case (d1 @ DefDef(mods1, name1, tparams1, vparamss1, tpt1,
> rhs1)) ::
> (d2 @ DefDef(mods2, name2, tparams2, vparamss2, tpt2, rhs2)) ::
> rest
> if (mods1.isAccessor && mods2.isAccessor &&
> name2.toString() == (name1.toString() + "_$eq")) => {
> val n1s = d1.symbol.name.toString();
> val getter = newTermName("get" +
> Character.toUpperCase(n1s.charAt(0)) + n1s.substring(1));
> val getterSymbol = cd.symbol.newMethod(d1.pos, getter);
> getterSymbol.resetFlag(symtab.Flags.ACCESSOR);
> getterSymbol.owner.info.decls.enter(getterSymbol);
> val getMethod = DefDef(getterSymbol, Nil,
> Select(This(cd.symbol), d1.symbol));
> Console.println(getMethod);
> d1 :: d2 :: typed(getMethod) :: checkBody(rest)
> }
> case head :: tail => head :: checkBody(tail)
> case Nil => Nil
> }
>
> copy.Template(templ, templ.parents, checkBody(templ.body))
> }
>
> What I want to do is fairly simple -- find pairs of accessor methods
> (name and name_=), then generate two extra methods using Java naming
> conventions that call the first ones. In other words,
>
> class T {
> var name: String = _;
> }
>
> Becomes:
>
> class T {
> var name: String = _;
> def getName(): String = name;
> def setName(s: String);
> }
>
> Well, my first shot at it didn't work :) I never could seem to arrange
> things such that the code generator would accept the AST. My first
> attempt was to put a new phase in just prior to code generation, but
> doing it there required me to insert a lot of nonobvious type
> information. There's obviously a "right way" to do things like create
> synthetic methods. Hopefully we'll see a little "compiler cookbook" at
> some point to help us amateurs mangle our own private versions of Scala
> ;)
>
> RJ
>




<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

News | FAQ | advertise