Can anybody provide some details on <:< operator in scala.
I think:
if(apple <:< fruit) //checks if apple is a subclass of fruit.
Are there any other explanations? I see many definitions in the scala source file.
The <:< type is defined in Predef.scala along with the related types =:= and <%< as follows:
// used, for example, in the encoding of generalized constraints
// we need a new type constructor `<:<` and evidence `conforms`, as
// reusing `Function2` and `identity` leads to ambiguities (any2stringadd is inferred)
// to constrain any abstract type T that's in scope in a method's argument list (not just the method's own type parameters)
// simply add an implicit argument of type `T <:< U`, where U is the required upper bound (for lower-bounds, use: `U <: T`)
// in part contributed by Jason Zaugg
sealed abstract class <:<[-From, +To] extends (From => To)
implicit def conforms[A]: A <:< A = new (A <:< A) {def apply(x: A) = x} // not in the <:< companion object because it is also intended to subsume identity (which is no longer implicit)
This uses the Scala feature that a generic type op[T1, T2] can be written T1 op T2. This can be used, as noted by aioobe, to provide an evidence parameter for methods that only apply to some instances of a generic type (the example given is the toMap method that can only be used on a Traversable of Tuple2). As noted in the comment, this generalizes a normal generic type constraint to allow it to refer to any in-scope abstract type/type parameter. Using this (implicit ev : T1 <:< T2) has the advantage over simply using an evidence parameter like (implicit ev: T1 => T2) in that the latter can lead to unintended in-scope implicit values being used for the conversion.
I'm sure I'd seen some discussion on this on one of the Scala mailing lists, but can't find it at the moment.
<:< is not an operator - it is an identifier and is therefore one of:
the name of a type (class, trait, type alias etc)
the name of a method/val or var
In this case, <:< appears twice in the library, once in Predef as a class and once as a method on Manifest.
For the method on Manifest, it checks whether the type represented by this manifest is a subtype of that represented by the manifest argument.
For the type in Predef, this is relatively new and I am also slightly confused about it because it seems to be part of a triumvirate of identical declarations!
class <%<[-From, +To] extends (From) ⇒ To
class <:<[-From, +To] extends (From) ⇒ To
class =:=[From, To] extends (From) ⇒ To
I asked around, and this is the explanation I got:
<:< is typically used as an evidence parameter. For example in TraversableOnce, toMap is declared as def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U]. This expresses the constraint that the toMap method only works if the traversable contains 2-tuples. flatten is another example. <:< is used to express the constraint that you can only flatten a traversable of traversables.
Actually, it checks if the class represented by the Manifest apple is a subclass of the class represented by the manifest fruit.
For instance:
manifest[java.util.List[String]] <:< manifest[java.util.ArrayList[String]] == false
manifest[java.util.ArrayList[String]] <:< manifest[java.util.List[String]] == true
Copy from scala.Predef.scala:
// Type Constraints --------------------------------------------------------------
// used, for example, in the encoding of generalized constraints
// we need a new type constructor `<:<` and evidence `conforms`, as
// reusing `Function2` and `identity` leads to ambiguities (any2stringadd is inferred)
// to constrain any abstract type T that's in scope in a method's argument list (not just the method's own type parameters)
// simply add an implicit argument of type `T <:< U`, where U is the required upper bound (for lower-bounds, use: `U <: T`)
// in part contributed by Jason Zaugg
sealed abstract class <:<[-From, +To] extends (From => To)
implicit def conforms[A]: A <:< A = new (A <:< A) {def apply(x: A) = x}
To better understand the implementation.
sealed abstract class <:<[-From, +To] extends (From => To)
implicit def conforms[A]: A <:< A = new (A <:< A) {def apply(x: A) = x}
I tried to devise a simpler implementation. The following did not work.
sealed class <:<[-From <: To, +To]
implicit def conforms[A <: B, B]: A <:< B = new (A <:< B)
At least because it won't type check in all valid use cases.
case class L[+A]( elem: A )
{
def contains[B](x: B)(implicit ev: A <:< B) = elem == x
}
error: type arguments [A,B] do not conform to class <:<'s
type parameter bounds [-From <: To,+To]
def contains[B](x: B)(implicit ev: A <:< B) = elem == x
^
Hmm... I can't seem to find "<:<" anywhere as well, but "<:" denotes subtyping.
From http://jim-mcbeath.blogspot.com/2008/09/scala-syntax-primer.html#types :
List[T] forSome { type T <: Component }
In the above example, we are saying T is some type which is a subtype of Component.
From the sources we have the following explanation:
/**
* An instance of `A <:< B` witnesses that `A` is a subtype of `B`.
* Requiring an implicit argument of the type `A <:< B` encodes
* the generalized constraint `A <: B`.
*
* #note we need a new type constructor `<:<` and evidence `conforms`,
* as reusing `Function1` and `identity` leads to ambiguities in
* case of type errors (`any2stringadd` is inferred)
*
* To constrain any abstract type T that's in scope in a method's
* argument list (not just the method's own type parameters) simply
* add an implicit argument of type `T <:< U`, where `U` is the required
* upper bound; or for lower-bounds, use: `L <:< T`, where `L` is the
* required lower bound.
*
* In part contributed by Jason Zaugg.
*/
#implicitNotFound(msg = "Cannot prove that ${From} <:< ${To}.")
sealed abstract class <:<[-From, +To] extends (From => To) with Serializable
private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x }
// The dollar prefix is to dodge accidental shadowing of this method
// by a user-defined method of the same name (SI-7788).
// The collections rely on this method.
implicit def $conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]
#deprecated("Use `implicitly[T <:< U]` or `identity` instead.", "2.11.0")
def conforms[A]: A <:< A = $conforms[A]
/** An instance of `A =:= B` witnesses that the types `A` and `B` are equal.
*
* #see `<:<` for expressing subtyping constraints
*/
#implicitNotFound(msg = "Cannot prove that ${From} =:= ${To}.")
sealed abstract class =:=[From, To] extends (From => To) with Serializable
private[this] final val singleton_=:= = new =:=[Any,Any] { def apply(x: Any): Any = x }
object =:= {
implicit def tpEquals[A]: A =:= A = singleton_=:=.asInstanceOf[A =:= A]
}
Related
There are two similar shapeless polymorphic functions in the following example. The only difference between them is that deserSucceeding's implicit case definition has an additional subtyping evidence (implicit e: FS <: FromStr[T]). Scala fails to derive an implicit Aux.Case for deserFailing, but succeeds for deserSucceeding.
Why? Is this a limitation of the scala compiler or can deserSucceeding lead to an ambiguity in the implicit derivation / type inference?
import shapeless._
type FromStr[T] = String => T
object FromDouble extends FromStr[Double] {
override def apply(v1: String): Double = v1.toDouble
}
object deserFailing extends Poly2 {
implicit def kase[T, FS <: FromStr[T]]: Case.Aux[String, FS, T] = at((s, fs) => fs(s))
}
// fails to derive a `Case.Aux`
deserFailing("1.0", FromDouble)
object deserSucceeding extends Poly2 {
implicit def kase[T, FS](implicit e: FS <:< FromStr[T]): Case.Aux[String, FS, T] = at((s, fs) => fs(s))
}
deserSucceeding("1.0", FromDouble)
The TL;DR; is how type inference works.
When you do [T, FS <: FromStr[T]] the compiler tries to infer both at the same type and as such it probably end up inferring Any or Nothing from one of those to make the subtype constraint to type-check.
Whereas the second option doesn't force any subtype restriction during inference which makes the compiler to infer better types and then after that it will check the subtyping constraint.
It is similar to this example:
def tupleIfSubtype1[T <: U, U](t: T, u: U) = (t, u)
def tupleIfSubtype2[T, U](t: T, u: U)(implicit ev: T <:< U) = (t, u)
tupleIfSubtype1("Foo", 3) // compiles, it infers Any for the second element.
tupleIfSubtype2("Foo", 3) // doesn't compile.
More in-depth explanation, here.
I'm a scala newbie...so assume ignorance.
so if I look at the definition of <:<
sealed abstract class <:<[-From, +To] extends (From => To)
implicit def conforms[A]: A <:< A = new (A <:< A) {def apply(x: A) = x}
and this is used to define evidence that a type A is a subtype of B.
A <: B
...but what if I want to have evidence that;
forall T. A[T] <: B[T]
?
ok....so I try to follow the same recipe
abstract class Foo[-A[_],+B[_]] { def apply[C](x : A[C]) : B[C] }
implicit def conforms[A[_]] : Foo[A,A] = new Foo[A,A] { def apply[C](x : A[C]) : A[C] = x }
I can use this constraint an manually apply the conversion, but I can't get the compiler to implicitly "apply" it. (because it doesn't extend A=>B?)
so for example if I define;
abstract class FooInt[-A[_],+B[_]] extends (A[Int] => B[Int])
implicit def conformsInt[A[Int]] : FooInt[A,A] = new FooInt[A,A] { def apply(x : A[Int]) : A[Int] = x }
then the compiler will automatically apply the conversion to values of type A[Int]
I just want to generalise this to A[T]
thoughts?
sealed abstract class <:< - this tells you that you cannot construct "new evidence". You have to rely on the compiler confirming that two existing types do meet the existing evidence. This should work for all types already, if not, you try to proof something that is wrong.
You state you want proof that A[T] <: B[T] forAll { type T }. This will depend on the variance of A's and B's type parameter. If you want to ignore that parameter, you can only ask for evidence A[_] <:< B[_]. E.g.
trait Animal; trait Cat extends Animal
trait Foo[A]
trait Bar[A] extends Foo[A]
implicitly[Bar[Cat] <:< Foo[Cat]] // ok, A is fixed
implicitly[Bar[Cat] <:< Foo[Animal]] // not possible
implicitly[Bar[Animal] <:< Foo[Cat]] // not possible
implicitly[Bar[_] <:< Foo[_]] // ok, we forget about A
If you had variances, you could preserve A:
trait Breeds[+A] // covariant, can "produce" A
trait Feeds [-A] // contravariant, can "consume" A
class Baz[A] extends Breeds[A] with Feeds[A]
implicitly[Baz[Cat] <:< Feeds[Animal]] // nope
implicitly[Baz[Animal] <:< Feeds[Cat]] // ok
implicitly[Baz[Cat] <:< Breeds[Animal]] // ok
implicitly[Baz[Animal] <:< Breeds[Cat]] // nope
In Scala there's a class <:< that witnesses a type constraint. From Predef.scala:
sealed abstract class <:<[-From, +To] extends (From => To) with Serializable
private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x }
implicit def $conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]
An example of how it's used is in the toMap method of TraversableOnce:
def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] =
What I don't understand is how this works. I understand that A <:< B is syntactically equivalent to the type <:<[A, B]. But I don't get how the compiler can find an implicit of that type if and only if A <: B. I assume that the asInstanceOf call in the definition of $conforms is making this possible somehow, but how? Also, is it significant that a singleton instance of an abstract class is used, instead of just using an object?
Suppose we've got the following simple type hierarchy:
trait Foo
trait Bar extends Foo
We can ask for proof that Bar extends Foo:
val ev = implicitly[Bar <:< Foo]
If we run this in a console with -Xprint:typer, we'll see the following:
private[this] val ev: <:<[Bar,Foo] =
scala.this.Predef.implicitly[<:<[Bar,Foo]](scala.this.Predef.$conforms[Bar]);
So the compiler has picked $conforms[Bar] as the implicit value we've asked for. Of course this value has type Bar <:< Bar, but because <:< is covariant in its second type parameter, this is a subtype of Bar <:< Foo, so it fits the bill.
(There's some magic involved here in the fact that the Scala compiler knows how to find subtypes of the type it's looking for, but it's a fairly generic mechanism and isn't too surprising in its behavior.)
Now suppose we ask for proof that Bar extends String:
val ev = implicitly[Bar <:< String]
If you turn on -Xlog-implicits, you'll see this:
<console>:9: $conforms is not a valid implicit value for <:<[Bar,String] because:
hasMatchingSymbol reported error: type mismatch;
found : <:<[Bar,Bar]
required: <:<[Bar,String]
val ev = implicitly[Bar <:< String]
^
<console>:9: error: Cannot prove that Bar <:< String.
val ev = implicitly[Bar <:< String]
^
The compiler tries the Bar <:< Bar again, but since Bar isn't a String, this isn't a subtype of Bar <:< String, so it's not what we need. But $conforms is the only place the compiler can get <:< instances (unless we've defined our own, which would be dangerous), so it quite properly refuses to compile this nonsense.
To address your second question: the <:<[-From, +To] class is necessary because we need the type parameters for this type class to be useful. The singleton Any <:< Any value could just as well be defined as an object—the decision to use a val and an anonymous class is arguably a little simpler, but it's an implementation detail that you shouldn't ever need to worry about.
I already know that:
<: is the Scala syntax type constraint
while <:< is the type that leverage the Scala implicit to reach the type constrait
for example:
object Test {
// the function foo and bar can have the same effect
def foo[A](i:A)(implicit ev : A <:< java.io.Serializable) = i
foo(1) // compile error
foo("hi")
def bar[A <: java.io.Serializable](i:A) = i
bar(1) // compile error
bar("hi")
}
but I want to know when we need to use <: and <:< ?
and if we already have <:, why we need <:< ?
thanks!
The main difference between the two is, that the <: is a constraint on the type, while the <:< is a type for which the compiler has to find evidence, when used as an implicit parameter. What that means for our program is, that in the <: case, the type inferencer will try to find a type that satisfies this constraint. E.g.
def foo[A, B <: A](a: A, b: B) = (a,b)
scala> foo(1, List(1,2,3))
res1: (Any, List[Int]) = (1,List(1, 2, 3))
Here the inferencer finds that Int and List[Int] have the common super type Any, so it infers that for A to satisfy B <: A.
<:< is more restrictive, because the type inferencer runs before the implicit resolution. So the types are already fixed when the compiler tries to find the evidence. E.g.
def bar[A,B](a: A, b: B)(implicit ev: B <:< A) = (a,b)
scala> bar(1,1)
res2: (Int, Int) = (1,1)
scala> bar(1,List(1,2,3))
<console>:9: error: Cannot prove that List[Int] <:< Int.
bar(1,List(1,2,3))
^
1. def bar[A <: java.io.Serializable](i:A) = i
<: - guarantees that instance of i of type parameter A will be subtype of Serializable
2. def foo[A](i:A)(implicit ev : A <:< java.io.Serializable) = i
<:< - guarantees that execution context will contains implicit value (for ev paramenter) of type A what is subtype of Serializable.
This implicit defined in Predef.scala and for foo method and it is prove if instance of type parameter A is subtype of Serializable:
implicit def conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]
fictional case of using <:< operator:
class Boo[A](x: A) {
def get: A = x
def div(implicit ev : A <:< Double) = x / 2
def inc(implicit ev : A <:< Int) = x + 1
}
val a = new Boo("hi")
a.get // - OK
a.div // - compile time error String not subtype of Double
a.inc // - compile tile error String not subtype of Int
val b = new Boo(10.0)
b.get // - OK
b.div // - OK
b.inc // - compile time error Double not subtype of Int
val c = new Boo(10)
c.get // - OK
c.div // - compile time error Int not subtype of Double
c.inc // - OK
if we not call methods what not conform <:< condition than all compile and execute.
There are definitely differences between <: and <:<; here is my attempt at explaining which one you should pick.
Let's take two classes:
trait U
class V extends U
The type constraint <: is always used because it drives type inference. That's the only thing it can do: constrain the type on its left-hand side.
The constrained type has to be referenced somewhere, usually in the parameter list (or return type), as in:
def whatever[A <: U](p: A): List[A] = ???
That way, the compiler will throw an error if the input is not a subclass of U, and at the same time allow you to refer to the input's type by name for later use (for example in the return type). Note that if you don't have that second requirement, all this isn't necessary (with exceptions...), as in:
def whatever(p: U): String = ??? // this will obviously only accept T <: U
The Generalized Type Constraint <:< on the other hand, has two uses:
You can use it as an after-the-fact proof that some type was inferred. As in:
class List[+A] {
def sum(implicit ev: A =:= Int) = ???
}
You can create such a list of any type, but sum can only be called when you have the proof that A is actually Int.
You can use the above 'proof' as a way to infer even more types. This allows you to infer types in two steps instead of one.
For example, in the above List class, you could add a flatten method:
def flatten[B](implicit ev: A <:< List[B]): List[B]
This isn't just a proof, this is a way to grab that inner type B with A now fixed.
This can be used within the same method as well: imagine you want to write a utility sort function, and you want both the element type T and the collection type Coll. You could be tempted to write the following:
def sort[T, Coll <: Seq[T]](l: Coll): Coll
But T isn't constrained to be anything in there: it doesn't appear in the arguments nor output type. So T will end up as Nothing, or Any, or whatever the compiler wants, really (usually Nothing). But with this version:
def sort[T, Coll](l: Coll)(implicit ev: Coll <:< Seq[T]): Coll
Now T appears in the parameter's types. There will be two inference runs (one per parameter list): Coll will be inferred to whatever was given, and then, later on, an implicit will be looked for, and if found, T will be inferred with Coll now fixed. This essentially extracts the type parameter T from the previously-inferred Coll.
So essentially, <:< checks (and potentially infers) types as a side-effect of implicit resolution, so it can be used in different places / at different times than type parameter inference. When they happen to do the same thing, stick to <:.
After some thinking, I think it has some different.
for example:
object TestAgain {
class Test[A](a: A) {
def foo[A <: AnyRef] = a
def bar(implicit ev: A <:< AnyRef) = a
}
val test = new Test(1)
test.foo // return 1
test.bar // error: Cannot prove that Int <:< AnyRef.
}
this menas:
the scope of <: is just in the method param generic tpye scope foo[A <: AnyRef]. In the example, the method foo have it's generic tpye A, but not the A in class Test[A]
the scope of <:< , will first find the method's generic type, but the method bar have no param generic type, so it will find the Test[A]'s generic type.
so, I think it's the main difference.
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]