This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Default arguments and reflection

5 replies
Tymon Tobolski
Joined: 2011-08-10,
User offline. Last seen 42 years 45 weeks ago.

The object: case class A(s: Foo = new Foo)

The problem:
When using reflection (im my concrete situation - retrieving objects
from NeoDatis database) it is very easy to create an object of type A
with field s = null. This breaks code that assumes that s will have a
value (at least the default one). As I looked at case class internals
it might be possible to add one improvement.

public String s() { return s; }

and in A$ class

public String init$default$1(){ return "default string value"; }

I can think of something like that:

public String s(){ if(s == null) return init$default$1(); else
return s; }

which would resolve my problem.

Since I have not much idea how to do it (as annotation or compiler
plugin) 'm asking here for opinions.

rytz
Joined: 2008-07-01,
User offline. Last seen 45 weeks 5 days ago.
Re: Default arguments and reflection


On Wed, Aug 10, 2011 at 21:27, Tymon Tobolski <tymon [dot] tobolski [at] monterail [dot] com> wrote:
The object: case class A(s: Foo = new Foo)

The problem:
When using reflection (im my concrete situation - retrieving objects
from NeoDatis database) it is very easy to create an object of type A
with field s = null. This breaks code that assumes that s will have a
value (at least the default one).

That code would also fail on "new A(null)"... 
As I looked at case class internals
it might be possible to add one improvement.

   public String s() { return s; }

and in A$ class

   public String init$default$1(){ return "default string value"; }

I can think of something like that:

    public String s(){ if(s == null) return init$default$1(); else
return s; }

which would resolve my problem.

This would conflict with the situation where you actually want "null".So this should probably not be enabled by default.

Since I have not much idea how to do it (as annotation or compiler
plugin) 'm asking here for opinions.

It's certainly possible to write a compiler plugin for that, probablyyou'd want it driven by an annotation on the class.You'd have to look at the getter method definitions and change the code. This could be done in a separate phase.
Lukas
Tymon Tobolski
Joined: 2011-08-10,
User offline. Last seen 42 years 45 weeks ago.
Re: Default arguments and reflection

Sure, I didn't mean that to be the default behavior.

Do you know any resources that could help me creating such a plugin?

On Aug 11, 9:24 am, Lukas Rytz wrote:
> On Wed, Aug 10, 2011 at 21:27, Tymon Tobolski
> wrote:
>
> > The object: case class A(s: Foo = new Foo)
>
> > The problem:
> > When using reflection (im my concrete situation - retrieving objects
> > from NeoDatis database) it is very easy to create an object of type A
> > with field s = null. This breaks code that assumes that s will have a
> > value (at least the default one).
>
> That code would also fail on "new A(null)"...
>
>
>
>
>
>
>
>
>
> > As I looked at case class internals
> > it might be possible to add one improvement.
>
> >    public String s() { return s; }
>
> > and in A$ class
>
> >    public String init$default$1(){ return "default string value"; }
>
> > I can think of something like that:
>
> >     public String s(){ if(s == null) return init$default$1(); else
> > return s; }
>
> > which would resolve my problem.
>
> This would conflict with the situation where you actually want "null".
> So this should probably not be enabled by default.
>
> > Since I have not much idea how to do it (as annotation or compiler
> > plugin) 'm asking here for opinions.
>
> It's certainly possible to write a compiler plugin for that, probably
> you'd want it driven by an annotation on the class.
> You'd have to look at the getter method definitions and change
> the code. This could be done in a separate phase.
>
> Lukas

Tymon Tobolski
Joined: 2011-08-10,
User offline. Last seen 42 years 45 weeks ago.
Re: Default arguments and reflection

I have created a simple compiler plugin for my problem -
https://github.com/monterail/knight
For now it "just works", but it is a bit hacky - matching methods by
name and copying its body.
I would be grateful if one could give some hints on how to find those
apply$default$X methods in a better way and just call them instead of
copying its body.
Other thing is that body of default arguments methods are called every
time the field is accessed, so it should be some kind of cache for it
(but since val is final variable it can be set after constructiong an
object).

On Aug 11, 10:13 am, Tymon Tobolski
wrote:
> Sure, I didn't mean that to be the default behavior.
>
> Do you know any resources that could help me creating such a plugin?
>
> On Aug 11, 9:24 am, Lukas Rytz wrote:
>
>
>
>
>
>
>
> > On Wed, Aug 10, 2011 at 21:27, Tymon Tobolski
> > wrote:
>
> > > The object: case class A(s: Foo = new Foo)
>
> > > The problem:
> > > When usingreflection(im my concrete situation - retrieving objects
> > > from NeoDatis database) it is very easy to create an object of type A
> > > with field s = null. This breaks code that assumes that s will have a
> > > value (at least the default one).
>
> > That code would also fail on "new A(null)"...
>
> > > As I looked at case class internals
> > > it might be possible to add one improvement.
>
> > >    public String s() { return s; }
>
> > > and in A$ class
>
> > >    public String init$default$1(){ return "default string value"; }
>
> > > I can think of something like that:
>
> > >     public String s(){ if(s == null) return init$default$1(); else
> > > return s; }
>
> > > which would resolve my problem.
>
> > This would conflict with the situation where you actually want "null".
> > So this should probably not be enabled by default.
>
> > > Since I have not much idea how to do it (as annotation or compiler
> > > plugin) 'm asking here for opinions.
>
> > It's certainly possible to write a compiler plugin for that, probably
> > you'd want it driven by an annotation on the class.
> > You'd have to look at the getter method definitions and change
> > the code. This could be done in a separate phase.
>
> > Lukas

rytz
Joined: 2008-07-01,
User offline. Last seen 45 weeks 5 days ago.
Re: Re: Default arguments and reflection


On Wed, Aug 24, 2011 at 09:45, Tymon Tobolski <tymon [dot] tobolski [at] monterail [dot] com> wrote:
I have created a simple compiler plugin for my problem -
https://github.com/monterail/knight
For now it "just works", but it is a bit hacky - matching methods by
name and copying its body.
I would be grateful if one could give some hints on how to find those
apply$default$X methods in a better way and just call them instead of
copying its body.

In NamesDefaults.scala, there's a method called "defaultGetter", which willfind the apply$default$X method symbol for a given parameter. Is this what you're looking for?
Have a look at NamesDefaults.scala which generates calls to these "defaultgetters" whenever a default is used. 
Other thing is that body of default arguments methods are called every
time the field is accessed, so it should be some kind of cache for it
(but since val is final variable it can be set after constructiong an
object).

That's true, i guess you'd have to introduce a new private variable field. 




On Aug 11, 10:13 am, Tymon Tobolski <tymon [dot] tobol [dot] [dot] [dot] [at] monterail [dot] com>
wrote:
> Sure, I didn't mean that to be the default behavior.
>
> Do you know any resources that could help me creating such a plugin?
>
> On Aug 11, 9:24 am, Lukas Rytz <lukas [dot] r [dot] [dot] [dot] [at] epfl [dot] ch> wrote:
>
>
>
>
>
>
>
> > On Wed, Aug 10, 2011 at 21:27, Tymon Tobolski
> > <tymon [dot] tobol [dot] [dot] [dot] [at] monterail [dot] com>wrote:
>
> > > The object: case class A(s: Foo = new Foo)
>
> > > The problem:
> > > When usingreflection(im my concrete situation - retrieving objects
> > > from NeoDatis database) it is very easy to create an object of type A
> > > with field s = null. This breaks code that assumes that s will have a
> > > value (at least the default one).
>
> > That code would also fail on "new A(null)"...
>
> > > As I looked at case class internals
> > > it might be possible to add one improvement.
>
> > >    public String s() { return s; }
>
> > > and in A$ class
>
> > >    public String init$default$1(){ return "default string value"; }
>
> > > I can think of something like that:
>
> > >     public String s(){ if(s == null) return init$default$1(); else
> > > return s; }
>
> > > which would resolve my problem.
>
> > This would conflict with the situation where you actually want "null".
> > So this should probably not be enabled by default.
>
> > > Since I have not much idea how to do it (as annotation or compiler
> > > plugin) 'm asking here for opinions.
>
> > It's certainly possible to write a compiler plugin for that, probably
> > you'd want it driven by an annotation on the class.
> > You'd have to look at the getter method definitions and change
> > the code. This could be done in a separate phase.
>
> > Lukas

Todd Vierling
Joined: 2011-04-27,
User offline. Last seen 42 years 45 weeks ago.
Re: Default arguments and reflection
On Wednesday, August 10, 2011 3:27:52 PM UTC-4, Tymon Tobolski wrote:
The object: case class A(s: Foo = new Foo)

The problem:
When using reflection (im my concrete situation - retrieving objects
from NeoDatis database) it is very easy to create an object of type A
with field s = null.

[older thread, but I just noted that no one proposed this]
How about, rather than using a default argument, adding a secondary constructor that provides the no-args overload?
case class A(s: Foo) {  def this() = this(new Foo)}
If you're worried about reflection safety, this is likely a lot safer for you than a default argument.

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland