- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Oddity with implicit conversion and objects in objects
Thu, 2012-02-09, 02:14
Greetings,
I have a wrapper class that has an implicit conversion to the class
that it is wrapping, but it doesn't behave consistently. When using
the implicit conversion on anything but a nested object, a println in
the implicit def will be executed. For objects in objects, the
conversion apparently happens, as it doesn't error and returns the
object, but the println doesn't execute. Can anyone shed some light on
this behavior? Here's the misbehaving example:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Wrapper[A](val item: A)
object Wrapper {
implicit def unwrap[A](in: Wrapper[A]): A = {
println("unwrapping...")
in.item
}
}
object Foo {
object foo extends Object
val int = 10
def str = "test"
}
class Bippy {
object foo extends Object
val int = 10
def str = "test"
}
// Exiting paste mode, now interpreting.
defined class Wrapper
defined module Wrapper
defined module Foo
defined class Bippy
scala> val cw = new Wrapper(new Bippy)
cw: Wrapper[Bippy] = Wrapper@394d4138
scala> cw.foo
unwrapping...
res0: object Bippy#foo = Bippy$foo$@55b4fea9
scala> cw.int
unwrapping...
res2: Int = 10
scala> cw.str
unwrapping...
res3: java.lang.String = test
scala> val ow = new Wrapper(Foo)
ow: Wrapper[Foo.type] = Wrapper@a67ca87
scala> ow.int
unwrapping...
res4: Int = 10
scala> ow.str
unwrapping...
res5: java.lang.String = test
scala> ow.foo
res6: Foo.foo.type = Foo$foo$@3a4449c2
Thanks, Chris
Thu, 2012-02-09, 23:21
#2
Re: Re: Oddity with implicit conversion and objects in objects
If there are side effects, then this inlining is incorrect. You should make a simple test case and file a bug report.
On Thu, Feb 9, 2012 at 12:11 AM, Chris Reeves <evschris@gmail.com> wrote:
On Thu, Feb 9, 2012 at 12:11 AM, Chris Reeves <evschris@gmail.com> wrote:
Further poking with :javap seems to indicate that the compiler is
optimizing the implicit out completely and sticking a straight field
access in the code. Is that correct behavior? I know a side-effecting
conversion is probably not the best idea, but I'd like to be able to
do some stupid dsl tricks with it.
class UseWrapper(val ow: Wrapper[Foo.type]) {
def test1 = ow.foo
def test2 = ow.str
}
:javap -v UseWrapper says the two methods come out as:
public Foo$foo$ test1();
Code:
Stack=1, Locals=1, Args_size=1
0: getstatic #22; //Field Foo$foo$.MODULE$:LFoo$foo$;
3: areturn
LineNumberTable:
line 14: 0
public java.lang.String test2();
Code:
Stack=2, Locals=1, Args_size=1
0: getstatic #29; //Field Wrapper$.MODULE$:LWrapper$;
3: aload_0
4: invokevirtual #31; //Method ow:()LWrapper;
7: invokevirtual #35; //Method
Wrapper$.unwrap:(LWrapper;)Ljava/lang/Object;
10: checkcast #37; //class Foo$
13: invokevirtual #40; //Method Foo$.str:()Ljava/lang/String;
16: areturn
LineNumberTable:
line 15: 0
Thanks, Chris
Further poking with :javap seems to indicate that the compiler is
optimizing the implicit out completely and sticking a straight field
access in the code. Is that correct behavior? I know a side-effecting
conversion is probably not the best idea, but I'd like to be able to
do some stupid dsl tricks with it.
class UseWrapper(val ow: Wrapper[Foo.type]) {
def test1 = ow.foo
def test2 = ow.str
}
:javap -v UseWrapper says the two methods come out as:
public Foo$foo$ test1();
Code:
Stack=1, Locals=1, Args_size=1
0: getstatic #22; //Field Foo$foo$.MODULE$:LFoo$foo$;
3: areturn
LineNumberTable:
line 14: 0
public java.lang.String test2();
Code:
Stack=2, Locals=1, Args_size=1
0: getstatic #29; //Field Wrapper$.MODULE$:LWrapper$;
3: aload_0
4: invokevirtual #31; //Method ow:()LWrapper;
7: invokevirtual #35; //Method
Wrapper$.unwrap:(LWrapper;)Ljava/lang/Object;
10: checkcast #37; //class Foo$
13: invokevirtual #40; //Method Foo$.str:()Ljava/lang/String;
16: areturn
LineNumberTable:
line 15: 0
Thanks, Chris
On Wed, Feb 8, 2012 at 8:13 PM, Chris Reeves wrote:
> Greetings,
>
> I have a wrapper class that has an implicit conversion to the class
> that it is wrapping, but it doesn't behave consistently. When using
> the implicit conversion on anything but a nested object, a println in
> the implicit def will be executed. For objects in objects, the
> conversion apparently happens, as it doesn't error and returns the
> object, but the println doesn't execute. Can anyone shed some light on
> this behavior? Here's the misbehaving example:
>
> scala> :paste
> // Entering paste mode (ctrl-D to finish)
>
> class Wrapper[A](val item: A)
> object Wrapper {
> implicit def unwrap[A](in: Wrapper[A]): A = {
> println("unwrapping...")
> in.item
> }
> }
> object Foo {
> object foo extends Object
> val int = 10
> def str = "test"
> }
> class Bippy {
> object foo extends Object
> val int = 10
> def str = "test"
> }
>
> // Exiting paste mode, now interpreting.
>
> defined class Wrapper
> defined module Wrapper
> defined module Foo
> defined class Bippy
>
> scala> val cw = new Wrapper(new Bippy)
> cw: Wrapper[Bippy] = Wrapper@394d4138
>
> scala> cw.foo
> unwrapping...
> res0: object Bippy#foo = Bippy$foo$@55b4fea9
>
> scala> cw.int
> unwrapping...
> res2: Int = 10
>
> scala> cw.str
> unwrapping...
> res3: java.lang.String = test
>
> scala> val ow = new Wrapper(Foo)
> ow: Wrapper[Foo.type] = Wrapper@a67ca87
>
> scala> ow.int
> unwrapping...
> res4: Int = 10
>
> scala> ow.str
> unwrapping...
> res5: java.lang.String = test
>
> scala> ow.foo
> res6: Foo.foo.type = Foo$foo$@3a4449c2
>
> Thanks, Chris