tags:

views:

636

answers:

6

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.

+5  A: 

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
Daniel
+7  A: 

<:< 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
oxbow_lakes
The ones in `Predef` are generalised type constraints. This mailing list thread goes over some of it: http://old.nabble.com/-scala--Using-generalised-type-constraints-in-2.8-collections-td26249516.html
Ben Lings
But from the declarations they all look identical, so how can they mean different things?
oxbow_lakes
Thanks for the link: unfortunately I'm still struggling to understand how replacing `implicit ev: A => B` with `implicit ev: A <:< B` where `<:<[A,B] extends A => B` actually *does* anything
oxbow_lakes
There are differences in the variance of the type parameters (eg. `-From` vs `From`) and if the implicit method uses a view-bound (e.g. `implicit def conformsOrViewsAs[A <% B, B]: A <%< B`). I think the difference between `ev: A=>B` and `ev: A <:< B` is that the former will take any in-scope implicit conversion whereas the latter will only use the more specific one defined in `Predef`.
Ben Lings
I think you'll find that `A => B` and `<:<[A, B]` have the same variance annotations. I've realized what's going on now and it's in the implicit declarations `conforms` etc as you say
oxbow_lakes
+1  A: 

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.

DVK
+5  A: 

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.

aioobe
hmm, this seems somehow familiar :-)
Seth Tisue
+3  A: 

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}
Eastsun
+14  A: 

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.

Ben Lings
What's the difference between <:< and =:= ?
Eastsun
@Eastsun `<:<` admits subclassing, while `=:=` doesn't.
Daniel
An implicit parameter `ev: T1 <:< T2` asserts that `T1` is a subtype of `T2`. An implicit parameter `ev: T1 =:= T2` asserts that they are the same type. See http://article.gmane.org/gmane.comp.lang.scala.user/18879 for an example of the latter.
Ben Lings