Covariant Return and Contravariant Arguments
As we know, to a variable of function type may be assigned a closure with compatible return type and compatible argument types. "Compatible return type" means that the type is either the same as in function type or is a subclass of this type (return types are covariant).
{ => Number } p1 = { => Integer.valueOf(19) }; // Integer is a subclass of Number { => Number } p2 = { => Double.valueOf(1.25) }; // Double is a subclass of Number
"Compatible argument type" means that the argument type is either the same as in function type or is a superclass of this type (argument types are contravariant).
{ String => void } p = // Object is a superclass of String { Object o => System.out.println(o); };
We can combine covariant return with contravariant arguments:
{ String => Number } p = { Object o => Integer.valueOf(o.hashCode()) }; System.out.println(p.invoke("haf"));
These rules define hierarchy on function types. So a function type might be a subtype or supertype of another function type.
For example, { => Integer }
is a subtype of { => Number }
and { String => void }
is
a supertype of { Object => void }
. As for class types, to a variable of function type may be assigned
an object (closure) of its type or any subtype.
What is meant by covariant and contravariant?
Let S and T be two types (classes or function types) such that S is a subtype of T. If method m of T is overridden in S, then
the corresponding types from the m's signature can either preserve the relationship between S and T (i.e. the type used in S is
a subtype of the
corresponding type in T), reverse this relationship (i.e. the type used in S is a supertype of that in T), or neither
preserve nor reverse this relationship. If they preserve the relationship of S and T, we say they are covariant, and if
they reverse the relationship of S and T, we say they are contravariant.
8 comments:
The covariant works fine for me unless I specify an Object as the type.... then my closure starts yielding null all the time.
Is there a forum to discuss this on?
Do you know why the following produces 19, 19, null?
public class Example {
public static void main(String[] args) {
{ => Integer } one = { => Integer.valueOf(19) };
System.out.println(one.invoke());
{ => Number } two = { => Integer.valueOf(19) };
System.out.println(two.invoke());
{ => Object } three = { => Integer.valueOf(19) };
System.out.println(three.invoke());
}
}
It works under the previous version (2007-11-30) so it is probably a bug in the latest version.
Hamlet: thanks for the bug report. Now fixed.
I don't understand this. In particular, the statement is made that argument types must be contravariant. As I understand this then if I specify, for example, that an argument should be of type javax.naming.directory.SearchResult because I expect to invoke its member function getAttributes() in the closure, I can pass an actual instance of javax.naming.NameClassPair which is a supertype of SearchResult. This makes no sense, as NameClassPair has no getAttributes() method to invoke. HELP!
Hi Mike,
"contravariant arguments" are not used when you call the closure but when you assign a closure to a variable of function type.
For example, the p variable is a reference to a closure that has a single argument of type String:
{ String => void } p;
And we are allowed to assign to p a closure that takes an argument of type Object:
p = { Object o => System.out.println(o); };
Why? Because String is Object. So, when you call a closure with a String argument, this argument can be safely passed to the referenced closure.
kami penyededia informasi alat bantu sex.
sekaligus jual alat sex wanita.
alat bantu sex pria.
semua alat seks ada pada kami.
sex toys terbaru.
nie job.
Nice blog. I Love reading all your blog post. it feels so nice and enjoying reading your blogs.
https //www.twitch.tv/activate
Post a Comment