My (pragmatic) answer to the question:
The reason it is only safe to return a subtype of the return type of the original function (+R
) it is clear by analyzing a concrete case:
whereas Gato
is a subtype of Animal
.
class Gato extends Animal
Note the following example where f <: g
:
g: (Int => Animal)
f: (Int => Gato)
It is clear that in order to use f
in place of g
, f
needs to return a subtype of R
, i and.., Gato <: Animal
; otherwise f
could return a type out of compliance with the signature of g
(a guy who wasn’t a Animal
).
The opposite rule (-A
) can be understood by another practical example in which f <: g
:
g: (Gato => Int)
f: (Animal => Int)
It is clear that in order to use f
in place of g
, f
needs to receive a supertype of A
, i and.., Animal >: Gato
; otherwise f
could receive a type out of compliance with the signature of g
. (there is no problem in f
also meet other subtypes of Animal
, provided that Gato
be one of them to satisfy the G
).
P.S.: This second part may sound a little strange to Java programmers, since the language does not allow one method to be overwritten by another with broader type arguments. This was a language decision (which Scala also embraced, functions and methods are two different things); the most likely reason for the decision is that allowing this type of superscript along with the ability to overload would bring a number of complications to the language (more information on SOE).
ps: Part of my program "More questions for the Beta", if anyone disagrees with tags feel free to edit
– Anthony Accioly