Given classes Parent and Child.
scala> class Parent
defined class Parent
scala> class Child extends Parent
defined class Child
Define implicits for Parent and Child
scala> implicit val a = new Parent
a: Parent = Parent#5902f207
scala> implicit val b = new Child
b: Child = Child#3f7d8bac
Use implicitly to find out which implicit gets resolved.
scala> implicitly[Child]
res1: Child = Child#3f7d8bac
illustration of my understanding:
Parent
|
Child -- implicit resolution gets the most specific, lowest sub-type
Now, let's use a contravariant type.
scala> trait A[-T]
defined trait A
scala> case class Concrete[T]() extends A[T]
defined class Concrete
Then define a Parent and Child class.
scala> class Parent
defined class Parent
scala> class Kid extends Parent
defined class Kid
Create implicits for them too.
scala> implicit val x = Concrete[Parent]
x: Concrete[Parent] = Concrete()
scala> implicit val y = Concrete[Kid]
y: Concrete[Kid] = Concrete()
scala> implicitly[A[Parent]]
res1: A[Parent] = Concrete()
scala> implicitly[A[Kid]]
<console>:21: error: ambiguous implicit values:
both value x of type => Concrete[Parent]
and value y of type => Concrete[Kid]
match expected type A[Kid]
implicitly[A[Kid]]
^
In the first example (without contravariance), Scala was able to resolve the implicit Child for implicitly[Parent]. It seems to me that it's picking the lowest sub-type.
However, when using contravariance, the behavior changes. Why?
Your implicits are typed Concrete and that is invariant here.
Try either
case class Concrete[-T]() extends A[T]
or
implicit val x: A[Parent] = Concrete[Parent]
More words:
Implicits (values or views) should have an explicit type so you're never surprised by the inferred type. Picking the implicit is all about the type.
It picks one of your implicits using the same rules as the overloading resolution conversion that is used to pick alternatives of an overloaded symbol.
For simple values (not function calls), that comes down to conformance or subtyping.
There is also the rule that a definition in a "derived type" (usually a subclass) is preferred.
Here is a test you can do using only commonly available household materials:
scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'. **
** scala.tools.nsc._ has been imported **
** global._, definitions._ also imported **
** Try :help, :vals, power.<tab> **
scala> trait A[-T]
defined trait A
scala> case class Concrete[T](i: Int) extends A[T]
defined class Concrete
scala> class Parent ; class Kid extends Parent
defined class Parent
defined class Kid
// it will pick X if X isAsSpecific as Y but not conversely
scala> typer.infer.isAsSpecific(typeOf[Concrete[Kid]],typeOf[Concrete[Parent]])
res0: Boolean = false
scala> typer.infer.isAsSpecific(typeOf[Concrete[Parent]],typeOf[Concrete[Kid]])
res1: Boolean = false
scala> case class Concrete[-T](i: Int) extends A[T]
defined class Concrete
scala> typer.infer.isAsSpecific(typeOf[Concrete[Kid]],typeOf[Concrete[Parent]])
res2: Boolean = false
scala> typer.infer.isAsSpecific(typeOf[Concrete[Parent]],typeOf[Concrete[Kid]])
res3: Boolean = true
Edit:
Another view of why it matters what type you're testing:
scala> trait A[-T]
defined trait A
scala> case class Concrete[T](i: Int) extends A[T] // invariant
defined class Concrete
scala> class Parent ; class Kid extends Parent
defined class Parent
defined class Kid
scala> implicitly[Concrete[Parent] <:< Concrete[Kid]]
<console>:13: error: Cannot prove that Concrete[Parent] <:< Concrete[Kid].
implicitly[Concrete[Parent] <:< Concrete[Kid]]
^
scala> implicit val x: Concrete[Parent] = Concrete[Parent](3) // the inferred type
x: Concrete[Parent] = Concrete(3)
scala> implicit val y = Concrete[Kid](4)
y: Concrete[Kid] = Concrete(4)
// both values conform to A[Kid] (because A is contravariant)
// but when it puts x and y side-by-side to see which is more specific,
// it no longer cares that you were looking for an A. All it knows is
// that the values are Concrete. The same thing happens when you overload
// a method; if there are two candidates, it doesn't care what the expected
// type is at the call site or how many args you passed.
scala> implicitly[A[Kid]]
<console>:15: error: ambiguous implicit values:
both value x of type => Concrete[Parent]
and value y of type => Concrete[Kid]
match expected type A[Kid]
implicitly[A[Kid]]
^
Give them explicit types and the variance of Concrete won't matter. You always supply explicit types for your implicits, right? Just like retronym tells us to?
scala> implicit val x: A[Parent] = Concrete[Parent](3)
x: A[Parent] = Concrete(3)
scala> implicit val y: A[Kid] = Concrete[Kid](4)
y: A[Kid] = Concrete(4)
scala> implicitly[A[Kid]]
res2: A[Kid] = Concrete(3)
Related
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.
I'm implementing some expressions using Scala type system. To determine the type of if-then-else expression I need to be able to implement the following function
def leastUpperBound(thenPartType: Type, elsePartType: Type): Type
Is there a function somewhere in scala.reflect._ to perform the evaluation? Or do I have to implement the search with those *TypeApi extractors?
Thanks in advance
Yes, the universe has a method lub just for that:
import reflect.runtime.universe._
def leastUpperBound(thenPartType: Type, elsePartType: Type): Type =
lub(List(thenPartType, elsePartType))
Using it:
trait Base
class A extends Base
class B extends Base
scala> com.Main.leastUpperBound(typeOf[A], typeOf[B])
res0: reflect.runtime.universe.Type = Base
scala> com.Main.leastUpperBound(typeOf[A], typeOf[String])
res1: reflect.runtime.universe.Type = java.lang.Object
scala> com.Main.leastUpperBound(typeOf[A], typeOf[Int])
res1: reflect.runtime.universe.Type = Any
I'm playing with Scala's type system with the following example:
scala> sealed trait A
defined trait A
scala> case class A1(n: Int) extends A
defined class A1
scala> case class A2(n: Int) extends A
defined class A2
scala> case class MyCase[+P <: A](a: A, y: String)
defined class MyCase
scala> val l = List(MyCase[A1](A1(1), "A1"), MyCase[A2](A2(2), "A2"))
Now, when I do the following:
scala> l.head.asInstanceOf[MyCase[A2]]
res2: MyCase[A2] = MyCase(A1(1),A1)
How can a MyCase[A1] instance be assigned to a MyCase[A2] reference? I mean MyCase[A1] and MyCase[A2] are at the same level in the object hierarchy!
As I understand you're wondering why you didn't get an error here in runtime, when you did l.head.asInstanceOf[MyCase[A2]]. So the answer is simple - type erasure. For JVM both types are equal as it ignores generic parameter - it simply doesn't know about them as they exist on compiler level only, so only compiler can give you an exception:
scala> val mcA2: MyCase[A2] = l.head
<console>:15: error: type mismatch;
found : MyCase[Product with Serializable with A]
required: MyCase[A2]
val mcA2: MyCase[A2] = l.head
^
However, asInstanceOf ignores this check. So when you do
case class MyCase[+P <: A](a: P) //P instead of A
scala> val k = MyCase[A1](A1(0)).asInstanceOf[MyCase[A2]]
k: MyCase[A2] = MyCase(A1(0))
scala> val a: A2 = k.a
java.lang.ClassCastException: A1 cannot be cast to A2
... 33 elided
But in your example - you never really used P in runtime (and it's impossible), so you never gonna get ClassCastException. Actually, under these conditions (no real instances), you can do type-level copy like here, but it safer to use traits for that.
I'm just checking structural type equality in scala.
I create a foo instance from annonymous class immediately and a Q type .
I intend them to differing with method name, so that hoping them regarded as a different type structurally.
code snippet:
scala> val foo = new {def foo=1}
a: AnyRef{def foo: Int} = $anon$1#3885c37f
scala> type Q = {def q:Unit}
defined type alias Q
scala> foo.isInstanceOf[Q]
<console>:14: warning: a pattern match on a refinement type is unchecked
foo.isInstanceOf[Q]
^
res55: Boolean = true
The checking returns true.
Q1:
I don't understand WHY foo is an instance of Q.
That's nonsense. Are not they different in sense of type structure?
Q2:
So what is the formal way to checking the structural type?
isInstanceOf is according to class info. In your case, you need type info:
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> val foo = new {def foo=1}
foo: AnyRef{def foo: Int} = $anon$1#15ab47
scala> type Q = {def q:Unit}
defined type alias Q
scala> def getType[T : TypeTag](t: T) = implicitly[TypeTag[T]].tpe
getType: [T](t: T)(implicit evidence$1:reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.Type
scala> getType(foo) =:= typeOf[Q]
res9: Boolean = false
The following Scala code, using the recursive type A does not compile:
package reflection.scala.stackOverflow
import scala.reflect.runtime.universe._
class A[T<:A[T]]
class Question(root:A[_]) {
val rtmMirror =runtimeMirror(getClass.getClassLoader)
val instanceMirror : InstanceMirror =rtmMirror.reflect(root)
}
It gives the following compilation error:
Error:(9, 50) type arguments [_$1] do not conform to class A's type parameter bounds [T <: reflection.scala.stackOverflow.A[T]]
val instanceMirror : InstanceMirror =rtmMirror.reflect(root)
^
Error:(9, 57) type arguments [_$1] do not conform to class A's type parameter bounds [T <: reflection.scala.stackOverflow.A[T]]
val instanceMirror : InstanceMirror =rtmMirror.reflect(root)
^
Why does the compilation fail?
What is the type argument $1 here ?
Where does $1 come from ?
Why does $1 not conform to A's type parameter bounds ?
How can this code be modified so that it compiles while preserving compile time type checking of root to be a type of A ?
If you don't tell it that the argument of A is of the right type, it will fill in an anonymous type parameter (the _$1 is an anonymous type used for the argument of A) and won't necessarily make it as specific as it needs to be . Just specify a valid type yourself instead:
class Question[T <: A[T]](root: A[T])
and the compiler will be happy.
If you really don't care:
scala> import scala.reflect.runtime._
import scala.reflect.runtime._
scala> import universe._
import universe._
scala> class A[T<:A[T]] { def a: T = null.asInstanceOf[T] }
defined class A
scala> def f(x: A[_]) = currentMirror reflect[A[_]] x
f: (x: A[_])reflect.runtime.universe.InstanceMirror
scala> f(new A)
res0: reflect.runtime.universe.InstanceMirror = instance mirror for A#5b369cb9
scala> typeOf[A[_]].member(TermName("a")).asMethod
res1: reflect.runtime.universe.MethodSymbol = method a
scala> res0 reflectMethod res1
res2: reflect.runtime.universe.MethodMirror = method mirror for A.a: T (bound to A#5b369cb9)
scala> res2()
res3: Any = null
I want a black distressed tee that has on the front X[_] and on the back, I dont care what type you think I am. Maybe more strongly worded.