Define a method which accepts types: List[_ <: AnyVal]
def foo(x : List[_ <: AnyVal]) = x
Try to use an AnyRef:
foo(List(new Test))
error: type mismatch;
found : Test
required: AnyVal
Note that implicit conversions are not applicable because they are ambiguous:
both method ArrowAssoc in object Predef of type [A](self: A)ArrowAssoc[A]
and method Ensuring in object Predef of type [A](self: A)Ensuring[A]
are possible conversion functions from Test to AnyVal
Question 1: In the warning message, why does the compiler ignore the other two "generic to AnyVal" implicit conversions defined in Predef.scala?
final implicit class StringFormat[A] extends AnyVal
final implicit class any2stringadd[A] extends AnyVal
Removing the previous ambiguity and forcing compiler to use the ArrowAssoc implicit conversion:
foo(List(new Test -> 1))
error: the result type of an implicit conversion must be more specific than AnyVal
Question 2: What is this error message implying? Its confusing. The method def -> [B](y: B): Tuple2[A, B] = Tuple2(self, y) in the ArrowAssoc class returns a Tuple2 which is of AnyRef type. So, a more useful error message could have been found Tuple2 required AnyVal?
To answer your second question first. Try this:
class Temp
implicit class Arrow[T](a:T) extends Temp{
def -->[B](b:B) = (a,b)
}
def foo(x : List[_ <: Temp]) = x
scala> foo(List(1 --> 2))
res0: List[Temp] = List(Arrow#2e17a321)
This works as expected. It is not complaining because it was searching for Temp and not Tuple2.
Now introduce ambiguity:
implicit class OtherTemp[T](a:T) extends Temp{}
foo(List(1 --> 2)) //compile error
It fails complaining collisions. So to answer your question on why it didn't show AnyRef is because:
Remember ArrowAssoc is being called to get AnyVal representation. With ->, it has a Tuple2 and is trying to retrieve a AnyVal. And because it is unable to retrieve AnyVal, it marks it as error as failure on inability to convert to AnyVal. Its true identity is irrelevant.
For first question:
In my understanding, implicits go as first search basis. So once it finds two and there is ambiguity, it quits complaining. May be this is why it doesn't try with StringFormat etc. This can be confirmed on repl by re-ordering implicit order
implicit class OtherTemp2[T](a:T) extends Temp{
}
implicit class OtherTemp[T](a:T) extends Temp{
}
foo(List[Temp]("asdf"))
Compiler complains as Arrow and OtherTemp2 as collisions. If you re-order and run repl again, it complains based on which implicit was found first.
But I cant find an official source which confirms this.
Related
Consider the following example:
sealed trait ST
object ST{
case class ST1() extends ST
case class ST2() extends ST
}
trait TypeClass[A]{
def doSome(a: A): Unit
}
case class Test[T](t: T)
implicit val tp: TypeClass[Test[_ <: ST]] = ??? //the implicit
def foo[A: TypeClass](a: A) = implicitly[TypeClass[A]].doSome(a)
val v: Test[_ <: ST] = ???
foo(v) //error: implicit not found
SCASTIE
As can be seen the required implicit is in scope while it is not recognized by the compile.
Why does that happen and is there a workaround to call foo?
If you change foo(v) to foo(v)(tp) it'll explain (a little bit) better why it doesn't want to use tp.
In a nutshell, def foo[A : TypeClass] wants an implicit of type TypeClass[A].
When you do foo(v), A becomes Test[_ <: ST] which means "Test of some specific but unknown subtype of ST". So, foo wants an implicit for that specific type.
But tp is not that. It is a "TypeClass for Test or any subclass of ST" (apparently _ means slightly different things in these two contexts, because v is a concrete instance, that must have a specific type).
Long story short, Test[_ <: ST] is not the actual type of v, but a supertype of its type. So, to make it work, you just need to make the TypeClass contravariant (TypeClass[-A]) - that'll make foo accept tp as the implicit, because its type will be a subtype of what it expects.
Existential types are not inferred during implicit resolution so f(v) fails because it is looking for an implicit value with non-inferred type
TypeClass[Test[_$4]]]
|
existential not inferred
however whey you explicitly provide the type variable instance foo[Test[_ <: ST]](v) then implicit resolution should work because we are past inference stage.
It works in Scala 3 probably because internally it rewrites existential types to refined types.
In the following example, it seems that the Scala compiler only recognizes an implicit class when it is defined to take the higher-kinded representation of Wrapper. Why is that?
scala> case class Nested(n: Int)
defined class Nested
scala> case class Wrapper[A <: Product](nested: A)
defined class Wrapper
scala> implicit class I1[W <: Wrapper[A], A <: Product](underlying: W) {
| def ok1() = true
| }
defined class I1
scala> Wrapper(Nested(5)).ok1()
<console>:26: error: value ok1 is not a member of Wrapper[Nested]
Wrapper(Nested(5)).ok1()
^
scala> implicit class I2[W <: Wrapper[_]](underlying: W) {
| def ok2() = true
| }
defined class I2
scala> Wrapper(Nested(5)).ok2()
res1: Boolean = true
Is there a workaround for implicit resolution that maintains full information about the nested type, allowing typeclass evidence, e.g., TypeTag, to be attached to it?
Note: the example above shows Nested and Wrapper to be case classes but that's not integral to the question. It's simply a convenience for a shorter and simpler console session.
This is happening because of a limitation in Scala's type inference. See SI-2272.
The implicit fails to resolve because the compiler cannot properly infer A. We can see this if we enable -Xlog-implicits. Notice that A is inferred as Nothing:
I1 is not a valid implicit value for Test.w.type => ?{def ok: ?} because:
inferred type arguments [Wrapper[Nested],Nothing] do not conform to method I1's type parameter bounds [W <: Wrapper[A],A <: Product]
The same thing happens if we try to instantiate I1 manually:
scala> val w = Wrapper(Nested(5))
w: Wrapper[Nested] = Wrapper(Nested(5))
scala> new I1(w)
<console>:21: error: inferred type arguments [Wrapper[Nested],Nothing] do not conform to class I1's type parameter bounds [W <: Wrapper[A],A <: Product]
new I1(w)
^
<console>:21: error: type mismatch;
found : Wrapper[Nested]
required: W
new I1(w)
^
Now, the work-arounds.
First, Wrapper is a case class, so there shouldn't be a reason for it to have sub-types. You can remove the W type parameter, and change underlying to a Wrapper[A]:
implicit class I1[A <: Product](underlying: Wrapper[A]) {
def ok = true
}
If you still wish to require two type parameters, you can also require implicit evidence that W <:< Wrapper[A], while removing the upper-bound on the type parameter W:
implicit class I1[W, A <: Product](underlying: W)(implicit ev: W <:< Wrapper[A]) {
def ok = true
}
Everything Michael said is true. Here is some extra perspective on this issue.
Because of the way you wrote your implicit class it looks like you want the implicit class to work on all subtypes of Wrapper and have as specific information about all types involved as possible. (99% of the time it's a bad idea to extend case classes, but it is possible, and these tricks also work for non case classes).
The trick basically is to make sure that all the type parameters that you want inferred are present somewhere in the value parameter lists. Another thing to keep in mind is this:
scala> trait Foo[A]; trait Bar extends Foo[Int]
defined trait Foo
defined trait Bar
scala> implicitly[Bar with Foo[Int] =:= Bar]
res0: =:=[Bar with Foo[Int],Bar] = <function1>
Take these two pieces of knowledge and you can rewrite your implicit class like this:
implicit class I1[Y, A <: Product](underlying: Y with Wrapper[A]) {
def ok1(): (Y, A) = ???
}
And see it at work:
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class Nested(n: Int)
case class Wrapper[A <: Product](nested: A)
class Crazy(override val nested: Nested) extends Wrapper[Nested](nested)
implicit class I1[Y, A <: Product](underlying: Y with Wrapper[A]) {
def ok1(): (Y, A) = ???
}
// Exiting paste mode, now interpreting.
scala> :type Wrapper(Nested(5)).ok1()
(Wrapper[Nested], Nested)
scala> :type new Crazy(Nested(5)).ok1()
(Crazy, Nested)
Note that the last solution Michael gave is based on the same thing: by moving the upper bound to the implicit parameter list, A is now present in the value parameter lists and can be inferred by the compiler.
The toArray call in following code does not compile
trait A[T] {
def create:T
def foo(a:Array[Int]) = {
for(b <- a) yield create
}.toArray
}
It throws the following errors:
not enough arguments for method toArray: (implicit evidence$1: scala.reflect.ClassTag[T])Array[T]. Unspecified value parameter evidence$1.
No ClassTag available for T
How do I fix it?
As Sergey said, Java arrays need to know the type of T, but T is eliminated by type erasure.
In scala you can "preserve" a type information at runtime using a ClassTag.
Here's a more in-depth discussion about arrays.
As per fixing it, you need to provide evidence of a ClassTag for T. Here's a possible solution:
import scala.reflect.ClassTag
trait A[T] {
def create: T
def foo(a: Array[Int])(implicit ev: ClassTag[T]) = {
for(b <- a) yield create
}.toArray
}
The implicit ev parameter is filled in automatically by the compiler.
The problem is that you can't create an Array[T] without knowing T. The ClassTag is Scala's way of representing this information. The simple fix would be to change trait A[T] to abstract class A[T: ClassTag] (class is needed because traits can't have any constructor parameters, including implicit ones). If you then create it with a specific type, e.g. class B extends A[Int], the compiler will insert the correct ClassTag itself, with a generic you need to pass the ClassTag through: class C[T: ClassTag] extends A[T].
The simplest way is to remove toArray call. Because you iterate over array so your result will be array too.
I'm trying to call this set method documented here, in the Java library jOOQ, with signature:
<T> ... set(Field<T> field, T value)
This Scala line is a problem:
.set(table.MODIFIED_BY, userId)
MODIFIED_BY is a Field<Integer> representing the table column. userId is Int. Predef has an implicit conversion from Int to Integer, so why doesn't it use it? I get this:
type mismatch; found: org.jooq.TableField[gen.tables.records.DocRecord,Integer]
required: org.jooq.Field[Any]
Note: Integer <: Any
(and org.jooq.TableField[gen.tables.records.DocRecord,Integer] <:
org.jooq.Field[Integer]), but Java-defined trait Field is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
Update - About Vinicius's Example
Rather than try to explain this in comments, here is a demonstration that there is no implicit conversion being called when you use a type with covariant parameter, like List[+T]. Let's say I put this code in a file, compile, and run it...
case class Foo(str: String)
object StackOver1 extends App {
implicit def str2Foo(s: String): Foo = {
println("In str2Foo.")
new Foo(s)
}
def test[T](xs: List[T], x: T): List[T] = {
println("test " + x.getClass)
xs
}
val foo1 = new Foo("foo1")
test(List(foo1), "abc")
}
You'll see that it calls test, but never the implicit conversion from String "abc" to Foo. Instead it's picking a T for test[T] that is a common base class between String and Foo. When you use Int and Integer it picks Any, but it's confusing because the runtime representation of the Int in the list is Integer. So it looks like it used the implicit conversion, but it didn't. You can verify by opening a Scala prompt...
scala> :type StackOver1.test(List(new java.lang.Integer(1)), 2)
List[Any]
I don't know anything aboutjOOQ, but I think the issue is that Scala does not understand java generics very well. Try:
scala> def test[T](a : java.util.ArrayList[T], b: T) = { println(a,b) }
scala> val a = new java.util.ArrayList[Integer]()
scala> val b = 12
scala> test(a,b)
<console>:11: error: type mismatch;
found : java.util.ArrayList[Integer]
required: java.util.ArrayList[Any]
Note: Integer <: Any, but Java-defined class ArrayList is invariant in type E.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
test(a,b)
Sounds familiar??
And to fix, just inform the type T to call the method: test[Integer](a,b) works fine.
EDIT:
There a few things involved here:
Erasure -> When compiled the type of the generic will disappear by erasure. The compiler will use Object which Scala, will treat as Any. However a ArrayList[Integer] is not an ArrayList[Any], even though Integer is any. The same way that TableField[gen.tables.records.DocRecord,Integer] is not a Field[Any].
Type inference mechanism -> it will figure out what type T should be and to do that it will use the intersection dominator of the types passed (in our case the first common ancestor). Page 36 of Scala Language Spec, which in our examples above will lead use to Any.
Implicit conversion -> it is the last step and would be called if there was some type to be converted to another one, but since the type of the arguments were determined to be the first common ancestor, there is no need to convert and we will never have a implicit conversion if we don't force the type T.
A example to show how the common ancestor is used to determine T:
scala> def test[T](a: T, b: T): T = a
scala> class Foo
scala> class Boo extends Foo
scala> test(new Boo,new Foo)
res2: Foo = Boo#139c2a6
scala> test(new Boo,new Boo)
res3: Boo = Boo#141c803
scala> class Coo extends Foo
scala> test(new Boo,new Coo)
res4: Foo = Boo#aafc83
scala> test(new Boo,"qsasad")
res5: Object = Boo#16989d8
Summing up, the implicit method does not get called, because the type inference mechanism, determines the types before getting the argument and since it uses the common ancestor, there is no need for a implicit conversion.
Your code produces an error due to erasure mechanism which disappear with the type information that would be important to determine the correct type of the argument.
#RobN, thanks for questioning my answer, I learned a lot with the process.
Scala 2.8.1
Take the following class hierarchy
abstract class A
class B extends A
class C extends A
Why is the scala compiler unable to find the implicit parameter for send when sending an instance of B below
implicit def routingKeyFor[T <: A](value: T) =
value.getClass.getSimpleName
implicit def routingKeyFor(value: C) = "custom C"
def send[T <: A](value: T)(implicit createRoutingKey: T => String):
Validation[Throwable, String] = Success(createRoutingKey(value))
val resultOfSendingB = send(new B)
val resultOfSendingC = send(new C)
Why is the compiler able to locate the value for the implicit parameter when the generic version of routingKeyFor is renamed?
implicit def someOtherName[T <: A](value: T) =
value.getClass.getSimpleName
The second implicit is shadowing the first one. Why is anyone's guess, and you might open an issue for it (after verifying that this wasn't reported before), but it might just be one of those things that throw a spanner into the works of type inference.