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

Re: Changing the way implicits scope (and associated ideas)

4 replies
odersky
Joined: 2008-07-29,
User offline. Last seen 45 weeks 6 days ago.

Hi David,

Interesting thoughts. There are a number of things happening in trunk
that come somewhat close to what you suggest:

Implicit shadowing is still by name, but in case of ambiguity implicits
defined in (companion objects of) subclasses take precedence over
implicits defined in (companion objects of) superclasses. In fact,
that now holds for all overloaded members.

Predef in trunk contains a method `evidence' which has the same
signature and usage as your `implicitly'. Actually, I think I like
`implicitly' better as a name, so I'll probably rename the method.

As to your other suggestions, I think these would significantly
increase the spec footprint, so I don't really see them happening.
Right now, the beauty of implicits is that they are normal members
subject to the same scope resolution rules as all other members. If
you start introducing a class of things with different scope
resolution rules you have dramatically increased the footprint of your
spec!

Cheers

Raphael Jolly
Joined: 2009-02-27,
User offline. Last seen 1 year 27 weeks ago.
Re: Changing the way implicits scope (and associated ideas)

martin odersky wrote:
> Hi David,
>
> Interesting thoughts. There are a number of things happening in trunk
> that come somewhat close to what you suggest:
>
> Implicit shadowing is still by name, but in case of ambiguity implicits
> defined in (companion objects of) subclasses take precedence over
> implicits defined in (companion objects of) superclasses. In fact,
> that now holds for all overloaded members.
>
> Predef in trunk contains a method `evidence' which has the same
> signature and usage as your `implicitly'. Actually, I think I like
> `implicitly' better as a name, so I'll probably rename the method.
>
> As to your other suggestions, I think these would significantly
> increase the spec footprint, so I don't really see them happening.
> Right now, the beauty of implicits is that they are normal members
> subject to the same scope resolution rules as all other members. If
> you start introducing a class of things with different scope
> resolution rules you have dramatically increased the footprint of your
> spec!

Martin, thanks for responding (to David, but still !)

What I could do then is:

class Mod(val mod: Int) {
class Element(_value: Int) {
val value = _value%mod
def +(that: Element) = Element.apply(this.value+that.value)
override def toString = value.toString
}
object Element {
implicit def apply(value: Int) = new Element(value)
}
}

val Mod7 = new Mod(7)
val a = Mod7.Element(4)

a+4 // 1
4+a // fails

, but I never understood why the last line fails. This is the same for
scala.BigInt : without importing anything, one has that:

BigInt(1)+1 // works
1+BigInt(1) // fails

One needs to import BigInt._ for the second one to work. This seems to
me to be highly dissymetrical and unfortunate. Without the import, I
would rather have both to work or none at all. Preferably both. Would it
be hard to implement ?

Raphael

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Re: Changing the way implicits scope (and associated ideas

On Fri, Sep 18, 2009 at 11:56:37PM +0200, Raphael Jolly wrote:
> BigInt(1)+1 // works
> 1+BigInt(1) // fails
>
> One needs to import BigInt._ for the second one to work. This seems to
> me to be highly dissymetrical and unfortunate. Without the import, I
> would rather have both to work or none at all. Preferably both.

(1: BigInt) + BigInt(1) works without any import. Without an annotation
that would be inherently ambiguous because of the unpleasantly hacky
any2stringadd, which sticks a "+" method on everything under the sun.

But ignoring that, I don't see why you would expect symmetric behavior
here. This is OO-land where "x op y" means "x.op(y)", not "op(x, y)",
and so it is natural that x.op(y) and y.op(x) each do their own thing.

Raphael Jolly
Joined: 2009-02-27,
User offline. Last seen 1 year 27 weeks ago.
Re: Changing the way implicits scope (and associated ideas)

Paul Phillips wrote:
> On Fri, Sep 18, 2009 at 11:56:37PM +0200, Raphael Jolly wrote:
>> BigInt(1)+1 // works
>> 1+BigInt(1) // fails
>>
>> One needs to import BigInt._ for the second one to work. This seems to
>> me to be highly dissymetrical and unfortunate. Without the import, I
>> would rather have both to work or none at all. Preferably both.
>
> (1: BigInt) + BigInt(1) works without any import. Without an annotation
> that would be inherently ambiguous because of the unpleasantly hacky
> any2stringadd, which sticks a "+" method on everything under the sun.
>
> But ignoring that, I don't see why you would expect symmetric behavior
> here. This is OO-land where "x op y" means "x.op(y)", not "op(x, y)",
> and so it is natural that x.op(y) and y.op(x) each do their own thing.

ok then I need to use imports, and find a workaround to the fact that
implicits are shadowing themselves. What I could do is to use an import
selector:

import Mod7.{apply => mod7}
import Mod2.{apply => mod2}

, but this turns out to remove the implicit nature of the value:

object A { implicit val x = 1 }
import A.x
implicitly[Int] // 1

// restart

object A { implicit val x = 1 }
import A.{x => y}
implicitly[Int] // error: could not find implicit value for parameter e: Int
y // 1
x // error: not found: value x [as expected]

Is that what is expected ?
Raphael

Raphael Jolly
Joined: 2009-02-27,
User offline. Last seen 1 year 27 weeks ago.
Re: Changing the way implicits scope (and associated ideas)

Raphael Jolly wrote:
> Paul Phillips wrote:
>> On Fri, Sep 18, 2009 at 11:56:37PM +0200, Raphael Jolly wrote:
>>> BigInt(1)+1 // works
>>> 1+BigInt(1) // fails
>>>
>>> One needs to import BigInt._ for the second one to work. This seems
>>> to me to be highly dissymetrical and unfortunate. Without the import,
>>> I would rather have both to work or none at all. Preferably both.
>>
>> (1: BigInt) + BigInt(1) works without any import. Without an
>> annotation that would be inherently ambiguous because of the
>> unpleasantly hacky any2stringadd, which sticks a "+" method on
>> everything under the sun.
>>
>> But ignoring that, I don't see why you would expect symmetric behavior
>> here. This is OO-land where "x op y" means "x.op(y)", not "op(x, y)",
>> and so it is natural that x.op(y) and y.op(x) each do their own thing.
>
> ok then I need to use imports, and find a workaround to the fact that
> implicits are shadowing themselves. What I could do is to use an import
> selector:
>
> import Mod7.{apply => mod7}
> import Mod2.{apply => mod2}
>
> , but this turns out to remove the implicit nature of the value:
>
> object A { implicit val x = 1 }
> import A.x
> implicitly[Int] // 1
>
> // restart
>
> object A { implicit val x = 1 }
> import A.{x => y}
> implicitly[Int] // error: could not find implicit value for parameter e:
> Int
> y // 1
> x // error: not found: value x [as expected]
>
> Is it on purpose ?

I have filled a bug report:

import selector removes implicit nature of value
http://lampsvn.epfl.ch/trac/scala/ticket/2405

Raphael

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