Why can a non-applicable implicit conversion introduce ambiguity? - scala

The setup for this example (Scala 2.10.3):
trait S[A]
trait T[A]
implicit class X[A : S](a: A) { def foo() { } }
implicit class Y[A : T](a: A) { def foo() { } }
implicit object I extends S[String]
This compiles:
new X("").foo()
This doesn't:
new Y("").foo()
because there is no implicit T[String].
could not find implicit value for evidence parameter of type T[String]
new Y("").foo()
^
Therefore, I would assume that scalac could unambiguously apply the implicit conversion from String to X:
"".foo()
But instead we get:
type mismatch;
found : String("")
required: ?{def foo: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method X of type [A](a: A)(implicit evidence$1: S[A])X[A]
and method Y of type [A](a: A)(implicit evidence$1: T[A])Y[A]
are possible conversion functions from String("") to ?{def foo: ?}
"".foo()
^
Is this intentional? Is scalac not supposed to consider whether each conversion would actually work when it enumerates the candidates?

My nonacademic view is that implicit is by design not meant to work everytime it seems that it should work. I think it's a good idea otherwise you could easily get into an implicit hell. You could extend your example by adding more layers of implicit conversions. It would be hard to tell which function is actually called just by looking at the code. There are well-defined rules, but I remember simply that if it's not obvious from the code what's going on, it doesn't work.
I would say that your code breaks One-at-a-time Rule which leads to breaking the Non-Ambiguity Rule. A : S is just a syntactic sugar, and can be rewritten to:
implicit class X[A](a: A)(implicit e: S[A]) { def foo() { } }
implicit class Y[A](a: A)(implicit e: T[A]) { def foo() { } }
Without resolution of the "second" implicit level (method argument e) both classes X and Y look the same to the compiler and therefore are ambiguous. As the linked document says: "For sanity's sake, the compiler does not insert further implicit conversions when it is already in the middle of trying another implicit."

Related

Scala class with a private constructor and implicit parameter

I would like to add an implicit parameter to a class with a private constructor. Here as a simplified example:
class A[T] private(a:Int){
def this()=this(0)
}
If I would like to apply Pimp my library pattern to T with Ordered[T], I would need to use (the deprecated) view bound like so:
class A[T <% Ordered[T]] private(a:Int){
def this()=this(0)
}
And this works. However, to avoid the deprecated syntactic sugar I would like to pass the implicit parameter to the class. Unfortunately, this is where I'm probably doing something wrong:
class A[T] private(a:Int)(implicit conv:T=>Ordered[T]){
def this()=this(0)
}
For the above code, the compiler generates the following error:
error: No implicit view available from T => Ordered[T].
def this()=this(0)
While if I try to pass the implicit parameter directly like so:
class A[T] private(a:Int)(implicit conv:T=>Ordered[T]){
def this()=this(0)(conv)
}
I get this:
error: not found: value conv
def this()=this(0)(conv)
How does one pass an implicit parameter in this case?
EDIT: After some more experimentation it seems that redefining the constructor with implicit parameter is the problem. Not the fact that the constructor is private.
I found an answer, it seems that I need to explicitly define the implicit parameter for the parameterless constructor, e.g.:
class A[T] private(a:Int)(implicit conv:T=>Ordered[T]){
def this()(implicit conv:T=>Ordered[T])=this(0)
}
I apologize for spamming SO, in any case I will accept any answer that provides a more in depth explanation.
Scala provides ordering in 2 flavours, one via inheritance with Ordered and the other one which is actually a lot more appropriate in here is via context bounds using the Ordering typeclass.
Your approach is not actually idiomatic, and if you had something that actually used the implicit you provided, you would get an ambiguous implicit exception at compile time, because both the constructor and the method define the same implicit.
What I would do is:
class A[T : Ordering] private(a: Int)
This is actually shorthand syntax for:
class A[T] private(a: Int)(implicit ev: Ordering[T])
You can then use this argument either explicitly or implicitly.
If you define it with the shorthand T : Ordering syntax.
class A[T : Ordering] private(a: Int) {
def revSorter(list: List[T]): List[T] = {
list.sorted(implicitly[Ordering[T]].reverse)
}
}
If you define it with the "explicit" syntax:
class A[T] private(a: Int)(implicit ev: Ordering[T]) {
def revSorter(list: List[T]): List[T] = {
list.sorted(ev.reverse)
}
}

Scala generics type mismatch

In Scala, I'm trying:
import scala.reflect.runtime.{universe => ru}
def foo[T <: Any]: ru.WeakTypeTag[T] = ru.weakTypeTag[String]
But this yields me:
<console>:34: error: type mismatch;
found : reflect.runtime.universe.WeakTypeTag[String]
required: reflect.runtime.universe.WeakTypeTag[T]
def foo[T <: Any]: ru.WeakTypeTag[T] = ru.weakTypeTag[String]
What's up here? I'm relatively sure String should satisfy T's type constraint of deriving from Any...
I guess String failed to bind to the T type parameter. In my use case other types may be returned as well though, and I'm not sure how I could get that answer to the compiler up-front before executing the function, if that's what it's expecting.
Your method foo claims that, for any T <: Any, it returns a WeakTypeTag[T]. That is, if T is (for instance) Int, it should return a WeakTypeTag[Int]. However, your method always returns a WeakTypeTag[String], hence the type mistmatch.
As an alternative you can use wildcard, anyway your type is extended from Any.
def foo[T <: Any]: ru.WeakTypeTag[_] = ru.weakTypeTag[String]
In general the problem is with definition of WeakTypeTag[T] class. It is defined invariantly. So you can not use it in covariant case.
Let's go with an examples.
def bom[T >: String]: List[T] = List[String]() // works fine
def foo[T >: String]: WeakTypeTag[T] = ru.weakTypeTag[String] // compilation fails
I'm defining T as any subtype of String and it works good for Lists but fails for WeakTypeTag that is invariant.
You can define sub type of WeakTypeTag and make it covariant so it will perfectly works.
trait WeakTypeTag1[+X] extends ru.WeakTypeTag {
}
def weakTypeTag1[T](implicit attag: WeakTypeTag1[T]) = attag
def foo[T >: String]: WeakTypeTag1[T] = weakTypeTag1[String] // no it's good

Scala generics not clear to me

class A {
def x(): Unit = {
println("tftf")
}
}
def t[A](x: A): Unit = {
x.x // <- error at this line
}
I get compile error - type mismatch; found : x.type (with underlying type A) required: ?{def x: ?} Note that implicit conversions are not applicable because they are ambiguous: both method any2Ensuring in object Predef of type [A](x: A)Ensuring[A] and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A] are possible conversion functions from x.type to ?{def x: ?}
- t
Can someone explain this in English, please? I am new to Scala.
t's generic parameter named A shadows the class named A.
What you've written is equivalent to:
class A {
def x(): Unit = {
println("tftf")
}
}
def t[B](x: B): Unit = {
x.x // <- error at this line
}
In your example, A is a concrete type (a class). But in the function t[A](x: A): Unit, you're trying to use it as a type parameter. There's nothing generic about it.
A simple example of using generics with the function would be something like:
def t[A](x: A): Unit = println("Here is the parameter x: " + x)
This function will accept any type, and simply print it to the console.
in your def t[A](x: A), A is a generic type parameter and has nothing to do with the class A you defined. you can name it whatever you want, like def t[T](x: T).
what you want to do actually is:
def t[B <: A](x: B): Unit = {
x.x // won't error
}
There are two sources of confusion here:
Your type parameter A shadows class type A.
Type parameter A is unconstrained, which implicitly means [A <: Any], and Any doesn't have the member x. The confusing error message comes from the compiler attempting to apply an implicit conversion from Any to something that has a member x.
You simply want a function that takes a parameter that is a subtype of A, but you don't need a type parameter for this since any subtype of class type A is a valid substitution for class type A as a function parameter.
Hence the solution is simply this:
def t(a: A) {
a.x()
}

Generic bounds, most of them are unclear

It's kind of complicated to learn Scala's generic bounds. I know that:
T : Tr - T has type of Tr, meaning it implements a trait Tr
T <: SuperClass - T is subclass of SuperClass
T :> ChildClass - T is superclass of ChildClass
However, there are also many more operators:
<% and %>
=:=
<:< and >:>
<% and %>
<%< and >%>
I read about them, but as I said, there was was not comprehensible explanations. Could you make it clearer?
I've used a few type constraints:
The easiest are <: and >:. These are simple bounds on the type hierarchy.
trait A
trait B extends A
trait C extends B
then for a method
def doSomething[T >:C <:B](data:T)
either B or C can be substituted instead of T
Then type constraints that involves an addition of implicit parameter to the method.
def doSmth1[T: MyTypeInfo] (data:T)
is rewritten during compilation as
def doSmth1[T] (data:T)(implicit ev: MyTypeInfo[T])
whereas
def doSmth2[T <% SomeArbitratyType] (data:T)
is rewritten as
def doSmth2[T] (data:T)(implicit ev: T => SomeArbitratyType)
Both of the methods can be called if in the scope there is an instance that fits the implicit parameter. If there is no appropriate instance then compiler issues an error.
The view bound (<%) requires an implicit conversion that converts T to an instance of the other type (SomeArbitratyType).
More powerful is using "type classes". Inside the type class instance one may put many useful methods that can deal with the type T. In particular, one may put a conversion method and achieve similar result as view bounds.
Examples:
trait MyTypeInfo[T] {
def convertToString(data:T):String
}
def printlnAdv[T : MyTypeInfo](data:T) {
val ev = implicitly[MyTypeInfo[T]]
println(ev.convertToString(data))
}
somewhere in the scope there should be implicit value of type MyTypeInfo[T]:
implicit val doubleInfo = new MyTypeInfo[Double] {
def convertToString(data:Double):String = data.toString
}
or
implicit def convertToString(data:T):String
def printlnAdv[T <% String](data:T) {
val conversionResult = data : String
println(conversionResult)
}
somewhere in the scope there should be implicit function:
implicit def convertDoubleToString(data:Double):String = data.toString
The next weird symbols are =:= and <:<. These are used in methods that wish to ensure that a type has some property. Of course, if you declare a generic parameter then it is enough to have <: and >: to specify the type. However, what to do with types that are not generic parameters? For instance, the generic parameter of an enclosing class, or some type that is defined within another type. The symbols help here.
trait MyAlmostUniversalTrait[T] {
def mySpecialMethodJustForInts(data:T)(implicit ev:T =:= Int)
}
The trait can be used for any type T. But the method can be called only if the trait is instantiated for Int.
Similar use case exists for <:<. But here we have not "equals" constraint, but "less than" (like T<: T2).
trait MyAlmostUniversalTrait[T] {
def mySpecialMethod(data:T)(implicit ev:T <:< MyParentWithInterestingMethods)
}
Again the method can only can called for types that are descendants of MyParentWithInterestingMethods.
Then <%< is very similar to <%, however it is used the same way as <:< — as an implicit parameter when the type is not a generic parameter. It gives a conversion to T2:
trait MyAlmostUniversalTrait[T] {
def mySpecialMethod(data:T)(implicit ev:T <%< String) {
val s = data:String
...
}
}
IMHO <%< can safely be ignored. And one may simply declare the required conversion function:
trait MyAlmostUniversalTrait[T] {
def mySpecialMethod(data:T)(implicit ev:T => String) {
val s = data:String
...
}
}

Conditional methods of Scala generic classes with restrictions for type parameters

I believe that a generic class may make one of its methods available only assuming that its type parameters conform to some additional restrictions, something like (syntax improvised on the spot):
trait Col[T] extends Traversable[T] {
def sum[T<:Int] :T = (0/:this)(_+_)
}
I guess I could use implicit parameters as evidence... Is there a language feature for this?
You can also use a type bound on the type parameter, which is enforced by an implicit argument:
trait Col[T] extends Traversable[T] {
def sum(implicit ev: T <:< Int) :T = (0/:this)(_+_)
}
<:< is actually a class, expressed in infix notation, defined in Predef.scala and explained in many places, including here
<:< means 'must be a subtype of'
You can also use =:= 'must be equal to' and X <%< Y 'must be viewable as' (ie. there is an implicit conversion to X from Y)
For a more detailed explanation of type constraints, see this SO question.
In this case you can only use an implicit parameter, as the type gets determined before the method call.
trait Col[T] extends Traversable[T] {
def sum(implicit num: Numeric[T]) :T = ???
}
If the method you are calling would be parameterized, you could use context bounds, which are just syntactic sugar for the implicit parameter bound to the type parameter:
def foo[A](implicit ev: Something[A]) = ???
is equivalent to
def foo[A : Something] = ???
there is another option involving implicit classes conversions
trait Col[T] extends Traversable[T]
implicit class ColInt[T <: Int](val v : Col[T]) extends AnyVal {
def sum : T = (0 /: v)(_ + _)
}
in this context you don't need the empty trait Col anymore, so you could further comprimize it to this:
implicit class ColInt[T <: Int](val v : Traversable[T]) extends AnyVal {
def sum : T = (0 /: v)(_ + _)
}
The advantage of this method is, that it tells the compiler, that type T is really a subtype of Int, so List[T] <: List[Int] is still valid in this context, and no explicit conversion needs to be added. The implicit parameter adds implicit conversions that wouldn't work on List[T], because it only introduces an implicit conversion from T to Int, not from List[T] to List[Int]