Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala type bounds & variance

I am trying to get a better understanding of the following behaviour:

scala> class C[-A, +B <: A]
<console>:7: error: contravariant type A occurs in covariant position
                    in type >: Nothing <: A of type B
       class C[-A, +B <: A]
                    ^

However the following works:

scala> class C[-A, +B <% A]
defined class C

I can see that there could be issues from the variance of the bounding and bounded variables being opposite, though I have am not clear on what the specific problem is. I am even less clear on why changing the type bound to a view bound makes things ok. In the absence of applicable implicit conversions I would expect the two definitions to be have largely the same effect. If anything I would expect a view bound to provide more opportunities for mischief.

For a bit of background I defining classes that are in some ways like functions, and I wanted to do something like

CompositeFunc[-A, +B <: C, -C, +D] (f1 : BaseFunc[A, B], f2 : BaseFunc[C, D]) 
  extends BaseFunc[A, D]

Arguably

CompositeFunc[-A, +B <% C, -C, +D] (f1 : BaseFunc[A, B], f2 : BaseFunc[C, D]) 
  extends BaseFunc[A, D]

is actually preferable, but I would still like to better understand what is going on here.

like image 627
Daniel Mahler Avatar asked Jun 04 '13 18:06

Daniel Mahler


People also ask

What are Type Parameters in Scala?

Methods in Scala can be parameterized by type as well as by value. The syntax is similar to that of generic classes. Type parameters are enclosed in square brackets, while value parameters are enclosed in parentheses.

What is context bound in Scala?

A context bound is a shorthand for expressing the common pattern of a context parameter that depends on a type parameter. Using a context bound, the maximum function of the last section can be written like this: def maximum[T: Ord](xs: List[T]): T = xs.reduceLeft(max)

What is Supertype in Scala?

Scala Type HierarchyAny is the supertype of all types, also called the top type. It defines certain universal methods such as equals , hashCode , and toString . Any has two direct subclasses: AnyVal and AnyRef . AnyVal represents value types.

What are type classes in Scala?

A type class is an abstract, parameterized type that lets you add new behavior to any closed data type without using sub-typing. If you are coming from Java, you can think of type classes as something like java.


1 Answers

First the easy one:

class C[-A, +B <% A]

This is equivalent to

class C[-A, +B](implicit view: B => A)

Since view is not publically returned, it is not in a position which would constrain the variance of A or B. E.g.

class C[-A, +B](val view: B => A)  // error: B in contravariant position in view

In other words, C[-A, +B <% A] is no different than C[-A, +B] in terms of constraints, the view argument doesn't change anything.


The upper bound case C[-A, +B <: A] I'm not sure about. The Scala Language Specification in §4.5 states

The variance position of the lower bound of a type declaration or type parameter is the opposite of the variance position of the type declaration or parameter.

The variance of B does not seem to be involved, but generally the upper bound must be covariant:

trait C[-A, B <: A] // contravariant type A occurs in covariant position

This must somehow produce a problem? But I couldn't come up with an example which proofs that this construction becomes unsound in a particular case....


As for the composed function, why not just

class Composite[-A, B, +C](g: A => B, h: B => C) extends (A => C) {
  def apply(a: A) = h(g(a))
}

EDIT: For example:

import collection.LinearSeq

def compose[A](g: Traversable[A] => IndexedSeq[A], h: Traversable[A] => LinearSeq[A]) =
  new Composite(g, h)
like image 93
0__ Avatar answered Sep 22 '22 09:09

0__