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

Ambiguity in the presence of both overloading and conversion

2 replies
paulbutcher
Joined: 2010-03-08,
User offline. Last seen 10 weeks 6 days ago.

Continuing on from my previous type erasure question, I've just run into another issue (which is no longer anything to do with type erasure).

I was under the impression that Scala only ever applied a single implicit conversion in order to avoid ambiguities. But I seem to have found an occasion where that's not the case.

This works just fine:

> object A {
> def m(x: Int) = "x is: "+ x
> def m(x: Double) = "x is: "+ x
> def m(x: String) = "x is: "+ x
> }
>
> A.m(42)
> A.m(1.23)
> A.m("foo")

As does this:

> case class WrappedInt(x: Int)
> case class WrappedDouble(x: Double)
> case class WrappedString(x: String)
>
> object B {
> def m(x: WrappedInt) = "x is: "+ x
> def m(x: WrappedDouble) = "x is: "+ x
> def m(x: WrappedString) = "x is: "+ x
> }
>
> implicit def wrap(x: Int) = new WrappedInt(x)
> implicit def wrap(x: Double) = new WrappedDouble(x)
> implicit def wrap(x: String) = new WrappedString(x)
>
> B.m(1.23)
> B.m("foo")

But given the above, this:

> B.m(42)

gives:

> error: ambiguous reference to overloaded definition,
> both method m in object B of type (x: this.WrappedDouble)java.lang.String
> and method m in object B of type (x: this.WrappedInt)java.lang.String
> match argument types (Int)
> B.m(42)
> ^
> one error found

I'm guessing that the conversion from Int to Double isn't considered to be an implicit conversion for the purposes of the "only one implicit conversion" rule? Any suggestions for ways to get around this?

--
paul.butcher->msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: paul@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher

Paulo Siqueira
Joined: 2011-04-13,
User offline. Last seen 42 years 45 weeks ago.
Re: Ambiguity in the presence of both overloading and conversio
Nice 'puzzle' hehe =D

I'm guessing the compiler verifies all overloaded versions of the methods for a match and finds that your '42' can be converted to both WrappedInt and WrappedDouble - and then can't choose which one to call. This won't happen in the 'A' case because its a direct call.

Now, I get confused with implicits from time to time, so an expert's voice here would be great =D

[]s,

2011/6/28 Paul Butcher <paul@paulbutcher.com>
Continuing on from my previous type erasure question, I've just run into another issue (which is no longer anything to do with type erasure).

I was under the impression that Scala only ever applied a single implicit conversion in order to avoid ambiguities. But I seem to have found an occasion where that's not the case.

This works just fine:

> object A {
>   def m(x: Int) = "x is: "+ x
>   def m(x: Double) = "x is: "+ x
>   def m(x: String) = "x is: "+ x
> }
>
> A.m(42)
> A.m(1.23)
> A.m("foo")

As does this:

> case class WrappedInt(x: Int)
> case class WrappedDouble(x: Double)
> case class WrappedString(x: String)
>
> object B {
>   def m(x: WrappedInt) = "x is: "+ x
>   def m(x: WrappedDouble) = "x is: "+ x
>   def m(x: WrappedString) = "x is: "+ x
> }
>
> implicit def wrap(x: Int) = new WrappedInt(x)
> implicit def wrap(x: Double) = new WrappedDouble(x)
> implicit def wrap(x: String) = new WrappedString(x)
>
> B.m(1.23)
> B.m("foo")


But given the above, this:

> B.m(42)


gives:

> error: ambiguous reference to overloaded definition,
> both method m in object B of type (x: this.WrappedDouble)java.lang.String
> and  method m in object B of type (x: this.WrappedInt)java.lang.String
> match argument types (Int)
> B.m(42)
>   ^
> one error found


I'm guessing that the conversion from Int to Double isn't considered to be an implicit conversion for the purposes of the "only one implicit conversion" rule? Any suggestions for ways to get around this?

--
paul.butcher->msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: paul@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher




--
Paulo "JCranky" Siqueira
Visit my blog: http://www.jcranky.com/
dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
Re: Ambiguity in the presence of both overloading and conversio

On Tue, Jun 28, 2011 at 05:25, Paul Butcher wrote:
> Continuing on from my previous type erasure question, I've just run into another issue (which is no longer anything to do with type erasure).
>
> I was under the impression that Scala only ever applied a single implicit conversion in order to avoid ambiguities. But I seem to have found an occasion where that's not the case.

I think, perhaps, it would be more precise to say Scala do not chain
implicit views. A lot of implicit stuff can go on on a single
statement, however.

> But given the above, this:
>
>> B.m(42)
>
> gives:
>
>> error: ambiguous reference to overloaded definition,
>> both method m in object B of type (x: this.WrappedDouble)java.lang.String
>> and  method m in object B of type (x: this.WrappedInt)java.lang.String
>> match argument types (Int)
>> B.m(42)
>>   ^
>> one error found
>
>
> I'm guessing that the conversion from Int to Double isn't considered to be an implicit conversion for the purposes of the "only one implicit conversion" rule? Any suggestions for ways to get around this?

It is not an implicit view, it is type widening. Int can be widened to
Long, Float or Double, according to 6.26.1 and 12.2.1. Not that Int
weekly conforms to Double (3.5.3), so it can be a parameter to both
WrappedInt and WrappedDouble.

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