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)

1 reply
Raphael Jolly
Joined: 2009-02-27,
User offline. Last seen 1 year 27 weeks ago.

David MacIver wrote:
> This email is more of a brain dump than a concrete proposal. It may be
> that this is a terrible idea, but I'd like to hear what other people
> think of it and possibly be convinced that it's a terrible idea. :-)
> Or it may be that even if it's a good idea no one other than me cares
> and/or it's too much work to implement.
>
> The way implicit scoping works currently bothers me. In particular the
> way they are shadowed.
>
> I'd like to change the behaviour so that implicits are shadowed by
> type and not by name. Take the following example:
>
> object Foo{
> implicit val bar : Bar = stuff;
>
> def thingy = {
> val bar : Bar = otherstuff;
>
> implicitly[Bar]; // compiler error because the local bar shadows
> the implicit bar
> }
> }
>
> (implicitly is a function I often define for demoing these things.
> It's def implicitly[T](implicit t : T) = t; So it gives the implicit
> value of T currently in scope)
>
> What I'd instead like to happen is
>
> object Foo{
> implicit val bar : Bar = stuff;
>
> def thingy = {
> val bar : Bar = otherstuff;
>
> assert (implicitly[Bar] == stuff);
> assert bar == otherstuff
> }
> }
>
> So the local variable shadows the identifier but not the implicit.
>
> Here's another example of where the behaviour is contrary to what I'd
> like (it bothers me less, but I feel this would help consistency):
>
> object Foo{
> implicit val bar : Bar = stuff;
>
> def thingy = {
> implicit val squirrel : Bar = otherstuff;
>
> assert (implicitly[Bar] == otherstuff); // Instead get compiler
> error due to ambiguous implicit value
> assert (bar == stuff)
> assert (squirrel == otherstuff)
> }
> }
>
>
> So what I'd like is that the fact that squirrel is implicitly Bar
> shadows the fact that bar is, but does not shadow the identifier for
> bar.
>
> Both these behaviours seem wrong to me. They force you to care about
> the name of the implicit, which seems counter to their purpose.
>
> Moreover, there are a few cases where this is actively harmful. For
> example, I've run into this issue a number of times when trying to use
> objects as modules style programming. i.e. I have some class which
> describes a module signature, and objects extending it are modules (an
> example I've speculated about for this is retargetable SBinary
> backends - e.g one using Java serialization, one using the current
> approach). But I can't usefully use implicits on this and use multiple
> instances of these at once, because if I have two in scope the
> implicits of one will shadow the implicits of the other.
>
> Does this make sense? Does it seem useful to you? It just seems like
> much saner behaviour to me.
>
> Other things I'd like on top of this (but which are not required for
> the basic proposal to make sense):
>
> Have implicitly as a compiler builtin. Possibly reusing the implicit
> keyword. So implicit[T] would be an expression evaluating to the
> implicit value of T currently in scope. You would additionally be
> allowed to do:
>
> - myObject.implicit[Foo] (equivalent to { import myObject._; implicit[Foo] }
> - import myObject.implicit[Foo] // brings only the fact that Foo is
> available implicitly into scope, not the identifier for Foo.
>
> Allow implicits with no identifier. e.g.
>
> implicit val = "jimbob"
>
> (Possibly this might look better as val implicit = "jimbob" ? Not sure)
>
> This would create an implicit but no name for it. The availability of
> the implicit would scope as above, but you wouldn't be able to access
> it by identifier. This would mainly be useful for weirdo projects like
> SBinary and ScalaCheck where you define a large number of implicit
> values for different types and it's generally very unlikely that you'd
> want to access them by name.
>
> Thoughts? Comments? Random abuse?

I have exactly the same need. I am trying to introduce so called
"dependent types" in a computer algebra project, see
http://krum.rz.uni-mannheim.de/kredel/jas-ascm2007.pdf , 3.3 Dependent
types, p. 7 for a reference. It is very uneasy to do Java, and hence
interesting to investigate in Scala.

Here is my code:

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

class Mod7 extends Mod[Mod7](7)
val Mod7 = new Mod7

import Mod7._

val a = Mod7(4)

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

This breaks as soon as I introduce another type, like:

class Mod2 extends Mod[Mod2](2)
val Mod2 = new Mod2

import Mod2._

val b = Mod2(1)

b+1 // 0
1+b // 0

a+4 // fails due to Mod2.apply shadowed
4+a // fails due to Mod2.apply shadowed

My question : Is this request being considered for a future release ?

Many thanks !
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:
> David MacIver wrote:
>> This email is more of a brain dump than a concrete proposal. It may be
>> that this is a terrible idea, but I'd like to hear what other people
>> think of it and possibly be convinced that it's a terrible idea. :-)
>> Or it may be that even if it's a good idea no one other than me cares
>> and/or it's too much work to implement.
>>
>> The way implicit scoping works currently bothers me. In particular the
>> way they are shadowed.
>>
>> I'd like to change the behaviour so that implicits are shadowed by
>> type and not by name. Take the following example:

[...]

> I have exactly the same need. I am trying to introduce so called
> "dependent types" in a computer algebra project, see
> http://krum.rz.uni-mannheim.de/kredel/jas-ascm2007.pdf , 3.3 Dependent
> types, p. 7 for a reference. It is very uneasy to do Java, and hence
> interesting to investigate in Scala.

My example can be simplified. I believe it will make clearer what I want
to do:

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

val Mod7 = new Mod(7)
import Mod7._
val a = Mod7(4)

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

// everything fine up to there. Then define:

val Mod2 = new Mod(2)
import Mod2._
val b = Mod2(1)

b+1 // 0
1+b // 0

a+4 // fails due to Mod7.apply shadowed
4+a // fails due to Mod7.apply shadowed

Raphael

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