Isn't the argument type co- not contra-variant?

后端 未结 4 1240
抹茶落季
抹茶落季 2020-12-03 05:12

I understand the terms co-variance and contra-variance. But there is one small thing I am unable to understand. In the course \"Functional Programming in Scala\" on coursera

相关标签:
4条回答
  • 2020-12-03 05:46

    I think the original question about converting Dog to Animal as already been clarified but it might be of interest to note that there is a reason why functions are defined contravariant in its arguments and covariant in its return types. Let’s say you have two functions:

    val f: Vertebrate => Mammal = ??? val g: Mammal => Primate = ???

    As we are talking about functions, you would expect functions composition to be amongst your primitive operations. Indeed, you can compose f and g (g o f) and obtain as result a function:

    val h: Vertebrate => Primate = f andThen g

    But I can replace g with a subtype:

    val gChild: Animal => Primate

    Without breaking the composability. And gChild is a subtype of g precisely because we defined Function contravariant in its argument. As a conclusion, you can see that a function must be defined in such a way if you want to capture and preserve the idea of functions composability. You can find more details and few graphics that should help in digesting this subject here

    0 讨论(0)
  • 2020-12-03 05:50

    I remember being confused by that very sentence when I was reading the Scala Book back in 2007. Martin delivers it as if he was talking about a language feature, but in that sentence he only states a fact about functions in general. Scala, specifically, models that fact simply by a regular trait. Since Scala has declaration-site variance, expressing those semantics is natural to the language.

    Java Generics, on the other hand, support only use-site variance, so the closest one can get to co/contravariance of a function type in Java is to hand-code it at each use site:

    public int secondOrderFunction(Function<? super Integer, ? extends Number> fn) {
         ....
    }
    

    (assuming an appropriately declared interface Function<P, R>, P standing for parameter type and R for return type). Naturally, since this code is in the hands of the client, and not being specific to functions at all, the statement about param type/return type variance is not applicable to any language feature of Java. It is only applicable in a broader sense, pertaining to the nature of functions.

    Java 8 will introduce closures, which implies first-class functions, but, as per Jörg's comment below, the implementation will not include a fully-fledged function type.

    0 讨论(0)
  • 2020-12-03 05:54

    This is how functions are defined in Scala:

    trait Function1 [-T1, +R]  extends AnyRef
    

    In English, parameter T1 is contravariant and result type R is covariant. What does it mean?

    When some piece of code requires a function of Dog => Animal type, you can supply a function of Animal => Animal type, thanks to contravariance of parameter (you can use broader type).

    Also you can supply function of Dog => Dog type, thanks to covariance of result type (you can use narrower type).

    This actually makes sense: someone wants a function to transform dog to any animal. You can supply a function that transforms any animal (including dogs). Also your function can return only dogs, but dogs are still animals.

    0 讨论(0)
  • 2020-12-03 05:59

    Converting Dog to Animal is converting narrow to wider, so it's not covariance.

    0 讨论(0)
提交回复
热议问题