Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to understand "The variance position of a method parameter is the opposite of the variance position of the enclosing parameter clause."

I see this sentence is scala specification (pdf):

The variance position of a method parameter is the opposite of the variance position of the enclosing parameter clause.

Which is on page 44.

But I can't quite understand it. Could you give me some samples?

like image 401
Freewind Avatar asked Mar 19 '23 17:03

Freewind


1 Answers

So, let's start with a motivating example. Suppose I write the following:

class Foo[+A] {
  def foo(a : A) = ???
}

Now, by annotating the type parameter A with a +, I've declared that Foo is covariant in A, which is to say that if X <: Y, then Foo[X] <: Foo[Y]. So, suppose I have such a Foo[X] and I try to pass it to a function which requires a Foo[Y]:

def bar(a : Y, x : Foo[Y]) = {
  x.foo(a)
}

Now, bar tries to call x.foo with a Y. But x is a Foo[X], and X is a subtype of Y - so it's like trying to pass an Object to a function requiring a String - there's no guarantee that the Object contains everything that's needed to do this. So the definition of Foo above is invalid - to use the terminology in the specification, the type parameter A is covariant, but you've attempted to use it in a contravariant position - as the parameter to a function.

The set of rules set out in the Scala spec where you've referenced are the rules used by the Scala compiler to determine the variance position of different places in the code, which it uses to check that you haven't done anything like the definition of Foo above. The specific clause you identify gives the rule corresponding to the example above - it says that the variance position of a parameter clause (e.g. within the parameter list of a function) is the opposite of the surrounding variance position.

Usually, this means that parameter clauses are contravariant. However, things can get multiply inverted:

class Foo[A, B] {
  def foo(a : A) = {
    def bar(b : B) = ???
  }
}

Here, the parameter clause of foo is contravariant, and hence the parameter clause of bar is inverted again, and is covariant. So the following definition is valid:

class Foo[-A, +B] {
  def foo(a : A) = {
    def bar(b : B) = ???
  }
}
like image 155
Impredicative Avatar answered Mar 22 '23 19:03

Impredicative