Strange behaviour of Numeric[Int]/IntIsIntegral?

64 views
Skip to first unread message

Andrew Phillips

unread,
May 7, 2013, 12:26:22 AM5/7/13
to scala-l...@googlegroups.com
It would be great if someone could shed some light on the following REPL sessions (2.10.0) [1]:

They are two attempts to produce a situation with ambiguous implicits. The first works as expected:

trait Settings { def title: String }
implicit object DefaultSettings extends Settings { val title = "default" }
scala> println(implicitly[Settings].title)
default

implicit object TestSettings extends Settings { val title = "test" }
scala> println(implicitly[Settings].title)
<console>:11: error: ambiguous implicit values:

The second attempt - to reproduce the result using an existing trait, Numeric[Int] - is where it gets interesting:

// using default Numeric[Int]: IntIsIntegral
scala> implicitly[Numeric[Int]].times(3, 4)
res0: Int = 12
implicit object StrangeMath1 extends Numeric[Int] {
   |   def times(x: Int,y: Int): Int = x + y
   |   // ignore the remainder
   |   ...
   | }
scala> implicitly[Numeric[Int]].times(3, 4)
res1: Int = 7

OK, so no ambiguous implicits so far? Guess StrangeMath1 overrides IntIsIntegral somehow? To continue:

implicit object StrangeMath2 extends Numeric[Int] {
   |   def times(x: Int,y: Int): Int = x + y
   |   // ignore the remainder
   |   ...
   | }
 
scala> implicitly[Numeric[Int]].times(3, 4)
res2: Int = 12

OK, so now back to IntIsIntegral?!? Indeed:

scala> println(implicitly[Numeric[Int]])
scala.math.Numeric$IntIsIntegral$@129f8ab4

But then:

scala> implicitly[Numeric[Int]]
<console>:10: error: ambiguous implicit values:
 both object StrangeMath1 of type StrangeMath1.type
 and object StrangeMath2 of type StrangeMath2.type
 match expected type Numeric[Int]
              implicitly[Numeric[Int]]

A quick search through the issue list and otherwise online didn't turn up anything that appears to discuss this directly. Thoughts/pointers as to what might be going on here much appreciated!

Regards

ap

Som Snytt

unread,
May 7, 2013, 1:54:26 AM5/7/13
to scala-l...@googlegroups.com

I don't know about light, but with the change in seasons, my dog is happy to shed:


> Guess StrangeMath1 overrides IntIsIntegral somehow?

Not overrides but overloads, which is resolved because IntIsIntegral is defined by the companion of Numeric, and StrangeMath1 is derived from Numeric.  The derivation adds a point of relative weight.  My New Year's resolution is still to lose a point of relative weight.

With 2.11, the difference in behavior seems to have evaporated:

// Exiting paste mode, now interpreting.

defined object StrangeMath1
defined object StrangeMath2

scala> val a: Any = implicitly[Numeric[Int]]
<console>:9: error: ambiguous implicit values:

 both object StrangeMath1 of type StrangeMath1.type
 and object StrangeMath2 of type StrangeMath2.type
 match expected type Numeric[Int]
       val a: Any = implicitly[Numeric[Int]]
                              ^

scala> val b = implicitly[Numeric[Int]]
<console>:9: error: ambiguous implicit values:

 both object StrangeMath1 of type StrangeMath1.type
 and object StrangeMath2 of type StrangeMath2.type
 match expected type Numeric[Int]
       val b = implicitly[Numeric[Int]]
                         ^

// For completeness of copy/paste, 2.10.1 says:

scala> val a: Any = implicitly[Numeric[Int]]
a: Any = scala.math.Numeric$IntIsIntegral$@74131e8

scala> val b = implicitly[Numeric[Int]]
<console>:9: error: ambiguous implicit values:

 both object StrangeMath1 of type StrangeMath1.type
 and object StrangeMath2 of type StrangeMath2.type
 match expected type Numeric[Int]
       val b = implicitly[Numeric[Int]]
                         ^




--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Andrew Phillips

unread,
May 7, 2013, 2:08:36 AM5/7/13
to scala-l...@googlegroups.com
> Not overrides but overloads, which is resolved because IntIsIntegral is defined by the companion of Numeric, and 
> StrangeMath1 is derived from Numeric.  The derivation adds a point of relative weight.

Aha...thanks for the clarification! Careless choice of phrase there, sorry.

Does the dog have any more to shed on why, after defining StrangeMath1 and StrangeMath2,

scala> implicitly[Numeric[Int]].times(3, 4)
res2: Int = 12

but:

scala> implicitly[Numeric[Int]]
<console>:10: error: ambiguous implicit values:
 both object StrangeMath1 of type StrangeMath1.type
 and object StrangeMath2 of type StrangeMath2.type
 match expected type Numeric[Int]
              implicitly[Numeric[Int]]

? Here, I'm assuming (perhaps incorrectly) that the compiler cannot treat implicitly[Numeric[Int]].times(3, 4) as being of type Any, which would seem to be the reason why println(implicitly[Numeric[Int]]) succeeded in 2.10?

Thanks!

ap

Som Snytt

unread,
May 7, 2013, 2:47:24 AM5/7/13
to scala-l...@googlegroups.com
I think the same case (whatever that is) applies:

scala> val x: { def times(x: Int,y: Int): Int } =
     | implicitly[Numeric[Int]]
x: AnyRef{def times(x: Int,y: Int): Int} = scala.math.Numeric$IntIsIntegral$@22e33b0f


or in 2.11,

scala> :pa
// Entering paste mode (ctrl-D to finish)

val x: { def times(x: Int,y: Int): Int } =
implicitly[Numeric[Int]]


// Exiting paste mode, now interpreting.

<console>:10: error: ambiguous implicit values:
 both object StrangeMath1 of type StrangeMath1.type
 and object StrangeMath2 of type StrangeMath2.type
 match expected type Numeric[Int]
       implicitly[Numeric[Int]]


I hesitate to say more without looking at the change in behavior because I don't know anything about it. If the discussion were on scala-user, I would feel empowered to express whatever idiocy popped into my head.

Speaking of which, :pa is terribly useful.  On a hunt for Easter eggs, I tried:

scala> :paulp
paulp: no such command.  Type :help for help.

Which is kind of reassuring, in a way.


--

Andrew Phillips

unread,
May 7, 2013, 2:57:56 AM5/7/13
to scala-l...@googlegroups.com
> scala> :paulp
> paulp: no such command.  Type :help for help.

I sense a lengthy debate coming up on what :paulp should do. Play an ASCII art music video version of The Signs of Soundness, perhaps? ;-)

ap

Paul Phillips

unread,
May 8, 2013, 2:14:42 PM5/8/13
to scala-l...@googlegroups.com
https://issues.scala-lang.org/browse/SI-6667

"ambiguity in first phase of implicit argument search prevents second phase unless the method call has an expected type"


Andrew Phillips

unread,
May 8, 2013, 2:37:10 PM5/8/13
to scala-l...@googlegroups.com
"Fix Version/s: Scala 2.10.1", I see. Shouldn't have tested on an old version, sorry. Glad to see this has been resolved now.

Thanks for the link, Paul!

ap

Som Snytt

unread,
May 8, 2013, 8:03:11 PM5/8/13
to scala-l...@googlegroups.com
It was the middle of the night and all, but I noticed you were on 2.10.0 and tried it out on the one true and stable latest version, see previous reply.  I checked again if I was doing something in my sleep.

Sometimes you see strange things around midnight.

apm@mara:~/tmp$ scala
Welcome to Scala version 2.10.1 (OpenJDK 64-Bit Server VM, Java 1.7.0_21).
Type in expressions to have them evaluated.
Type :help for more information.
Type :paulp for information overload.



scala> val a: Any = implicitly[Numeric[Int]]
a: Any = scala.math.Numeric$IntIsIntegral$@7f028607


scala> val b = implicitly[Numeric[Int]]
<console>:9: error: ambiguous implicit values:

 both object StrangeMath1 of type StrangeMath1.type
 and object StrangeMath2 of type StrangeMath2.type
 match expected type Numeric[Int]
       val b = implicitly[Numeric[Int]]
                         ^

scala> util.Properties.scalaHome
res1: String = /media/Software/scala-2.10.1


But thanks to the :paulp command, this time I knew to try:

apm@mara:~/tmp$ scala -Xlint


scala> val a: Any = implicitly[Numeric[Int]]
<console>:9: warning: Search of in-scope implicits was ambiguous, and the implicit scope was searched. In Scala 2.11.0, this code will not compile. See SI-6667.
ambiguous implicit values:
 both object StrangeMath1 of type StrangeMath1.type
 and object StrangeMath2 of type StrangeMath2.type
 match expected type Numeric[Int]
       val a: Any = implicitly[Numeric[Int]]
                              ^


Now I know why they call him retronym.  This warning message reads like the scene in "A Night at the Opera" when Groucho Marx is reading the contract, "...the party of the first part" and so on.

Yes, yes, and "Xlint would have told you not to do that."





--
Reply all
Reply to author
Forward
0 new messages