0

There is some explanation here

Types and objects can also have symbolic names; in particular, it should be mentioned that for types with two type parameters the name can be written between parameters, so that e.g. Int <:< Any is the same as <:<[Int, Any].

But, i still couldn't quite get it. I'd appreciate if someone can provide an explanation with an example.

0__
  • 66,707
  • 21
  • 171
  • 266
Pratik Khadloya
  • 12,509
  • 11
  • 81
  • 106

1 Answers1

1

This is a class defined in object Predef:

abstract class <:<[-From, +To] extends Function1[From, To]

An instance of A <:< B witnesses that A is a subtype of B.

That the class name is symbolic has no particular consequences, it could have been named IsSubType[From, To] aka From IsSubType To.

You get 'evidence' instances of this class by way of Predef.$conforms:

implicit def $conforms[A]: <:<[A, A]

The use case of this is where you have a type A but you want to operate on sub-type B <: A. Then you can simply ask for this implicit evidence:

trait Foo[A] {
  def x: A

  // def fails: Int = x * x -- not possible, we don't know that A is an Int

  def succeeds(implicit ev: A <:< Int): Int = x * x
}

From the use-site, the compiler only allows us to call succeeds if A <: Int, since otherwise we wouldn't be able to get the ev parameter. The implicit look-up works because of how the compiler can infer the upper bounds of the sought type based on the variance of the type parameters From and To of <:<.

(Of course Int is a final type, so we could have also asked for equality A =:= Int, this is just to have a simple example.)

0__
  • 66,707
  • 21
  • 171
  • 266