Scope of Scala's implicit class conversion

52 views
Skip to first unread message

ron

unread,
May 23, 2012, 6:35:08 PM5/23/12
to scala-language
Hello List,

Please help me clarify the following (carbon copied from Stackoverflow
http://stackoverflow.com/questions/10727508/scope-of-scalas-implicit-class-conversion#comment13936013_10727508):

Scala seems to apply the implicit class conversion on the largest
possible expression, as in the following example:

----repl----
scala> class B { def b = { println("bb"); true } }
scala> class A { def a = { println("aa"); new B } }
scala> (new A).a.b
aa
bb
res16: Boolean = true

scala> class XXX(b: => Boolean) { def xxx = 42 }
scala> implicit def toXXX(b: => Boolean) = new XXX(b)
scala> (new A).a.b.xxx
res18: Int = 42
----repl----

Which part of the specification addresses this behavior? What prevents
the compiler from converting into val x = (new A).a.b; toXXX(x).xxx ?

Thank you,
Robin

Ryan Hendrickson

unread,
May 23, 2012, 7:02:00 PM5/23/12
to scala-l...@googlegroups.com
> Scala seems to apply the implicit class conversion on the largest
> possible expression, as in the following example:
>
> ----repl----
> scala> class B { def b = { println("bb"); true } }
> scala> class A { def a = { println("aa"); new B } }
> scala> (new A).a.b
> aa
> bb
> res16: Boolean = true
>
> scala> class XXX(b: => Boolean) { def xxx = 42 }
> scala> implicit def toXXX(b: => Boolean) = new XXX(b)
> scala> (new A).a.b.xxx
> res18: Int = 42
> ----repl----
>
> Which part of the specification addresses this behavior? What prevents
> the compiler from converting into val x = (new A).a.b; toXXX(x).xxx ?

You don't have a largest/smallest problem here; in fact, what you describe is *almost* equivalent to what the compiler is doing. The exact equivalent would be:

toXXX((new A).a.b).xxx

Because your toXXX method takes a by-name parameter (and the XXX constructor does as well), Scala never needs to invoke the body of the thing being converted in order to yield the result 42. If you took away the '=>' in toXXX or the XXX constructor, you'd see the aa/bb side effects again. You can find out more by Googling 'scala by-name parameters'.





(please forgive me my corporate legal disclaimer)

----------------------------------------

This message is intended exclusively for the individual(s) or entity to
which it is addressed. It may contain information that is proprietary,
privileged or confidential or otherwise legally exempt from disclosure.
If you are not the named addressee, you are not authorized to read,
print, retain, copy or disseminate this message or any part of it.
If you have received this message in error, please notify the sender
immediately by e-mail and delete all copies of the message.

ron

unread,
May 23, 2012, 7:20:51 PM5/23/12
to scala-language
I understand what happens, and also by-name parameters, but it is
still not clear why does the compiler choose to apply the implicit
conversion to the whole expression (putting it wholly into the by-name
param), versus generating code to evaluate the result of the
expression and putting only the result into the conversion. Maybe this
is something trivial, but still it would be nice if someone could
point it out exactly.

BR,
Robin

On máj. 24, 01:02, Ryan Hendrickson <Ryan.Hendrick...@bwater.com>
wrote:

Ryan Hendrickson

unread,
May 23, 2012, 7:26:27 PM5/23/12
to scala-l...@googlegroups.com
Ah, forgive me. In that case, the language you're looking for is in Section 7.3, in the list of the three situations in which views are applied:

2. In a selection e.m with e of type T , if the selector does not denote a member
of T. In this case, a view v is searched which is applicable to e and whose result
contains a member named m. The search proceeds as in the case of implicit
parameters, where the implicit scope is the one of T. If such a view is found,
the selection e.m is converted to v(e).m.

So the compiler can only generate something that is semantically equivalent to v(e).m, and as you've demonstrated, when by-name parameters are involved

val x = e
v(x).m

is not semantically equivalent to v(e).m.

Som Snytt

unread,
May 24, 2012, 4:18:27 AM5/24/12
to scala-l...@googlegroups.com
It's way past midnight here, so no good can come of this, but by 6.4 Designators:

For other expressions e, e.x is typed as if it was { val y = e; y.x }, for some fresh name y.

Immediately, this has consequences for how the prefix is typed:

The expected type of a designator’s prefix is always undefined.

But that would also imply that the e in 7.3 is y from 6.4, and goes to the OP's intuition that the prefix should be evaluated before y is wrapped in a thunk for the implicit conversion v(y) for v(y).x  where v(=>Y).

Ryan Hendrickson

unread,
May 24, 2012, 11:42:01 AM5/24/12
to scala-l...@googlegroups.com
'Typed as if' != 'evaluated as if'. It seems to me that the language in 6.4 that you point out is just talking about how typing should proceed for e.x, but e.x can't be typed if x is not a member of the type of e. So the 7.3 rules translate the expression into one that can be typed, and then v(e).x is typed as if it were { val y = v(e); y.x } per the 6.4 rules. I'm not terribly confident I'm not missing some implication of the rest of the spec, though.
Reply all
Reply to author
Forward
0 new messages