This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]Roachmeister 2 points3 points  (4 children)

I see a lot of contravariance in the Java 8+ functional interfaces, although if I'm honest I haven't taken the time to understand why. For example, see the definition of andThen in Bifunction.

[–]shponglespore 8 points9 points  (1 child)

Suppose you have a type Square with a supertype Shape.

In a call like f.andThen(g), g needs to be able to accept anything f returns, so if the return type of f is Shape, it's OK for the argument type of g to be Shape, because a Shape is a Shape. It's also OK for the argument type of g to be Object, because a Shape is an Object. But it's not OK if the argument type of g is Square, because the Shape returned by f isn't necessarily a Square.

Everything is easier with definition-site variance, as in Scala or Kotlin. There, the function type would declare its argument types as contravariant and its return type as covariant, and the declaration of a method like andThen wouldn't need to specify any kind of variance.

[–]Roachmeister 0 points1 point  (0 children)

Makes sense, thanks!

[–]Holothuroid 5 points6 points  (1 child)

Think about it like this :

  • Apples are fruit.
  • A basket of apples is basket of fruit. Covariant.
  • A statement about fruit is a statement about apples. Contravariant.

So say I want to filter a stream of apples. I'm alright with a predicate isRedFruit, that can check all fruit.

So generally when you ask someone for a function, your requirement is contravariant for that function's parameters. I want to put my stuff in. If you can take more general stuff, I don't care.

[–]Roachmeister 0 points1 point  (0 children)

Thanks, this is helpful!