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

Oddity with implicit conversion and objects in objects

2 replies
Chris Reeves
Joined: 2009-10-26,
User offline. Last seen 42 years 45 weeks ago.

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

Chris Reeves
Joined: 2009-10-26,
User offline. Last seen 42 years 45 weeks ago.
Re: Oddity with implicit conversion and objects in objects

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

Lex
Joined: 2010-02-28,
User offline. Last seen 42 years 45 weeks ago.
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:
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

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