
Covariance and contravariance in C++ - ingve
https://quuxplusone.github.io/blog/2019/01/20/covariance-and-contravariance/
======
Koshkin
Some things are better left to the subconscious. Otherwise one might find
themselves in a position of a centipede who lost the ability to walk as soon
as it started wondering which leg to move first.

~~~
paulddraper
Any pattern involving "callbacks" or similar make one wish for contravariance,
though in my experience it is not an intuitive idea.

------
nly
> C++’s classical OOP system supports “covariant return types,” but it does
> not support “contravariant parameter types.”

The problem in the authors "Animal doctor" example is that the universe of all
possible animal types is practically unbounded, or "open".

What you want here are "open multimethods": something Bjarne Stroustrup has
wanted in C++ for a long time[0] but have been implemented in library form[1].

Of course, the thing to remember is that, as soon as you go to an open
multiple dispatch arrangement, you will lose much of the static safety
guarantees that the type-system affords us. There will always be
runtime/dynamic type checking, and a runtime failure case.

If you don't want an open system, then some combination of templates for
static polymorphism and strategic type-erasure will get the job done. e.g. use
boost::variant and multivisitation [2], and the compiler will instantiate all
O(n^2) methods for you.

[0]
[http://www.stroustrup.com/multimethods.pdf](http://www.stroustrup.com/multimethods.pdf)
(2007)

[1]
[https://github.com/jll63/yomm2/blob/master/examples/asteroid...](https://github.com/jll63/yomm2/blob/master/examples/asteroids.cpp)

[2]
[https://www.boost.org/doc/libs/1_69_0/doc/html/variant/tutor...](https://www.boost.org/doc/libs/1_69_0/doc/html/variant/tutorial.html#variant.tutorial.multi-
visitation)

~~~
malkia
I've learned about multi-dispatch from Common Lisp, and back then was
prototyping a turn-based game, where I can have multi-method working:

    
    
        Outcome attack( RangeBaseUnit attackingUnit, MeleeBasedUnit defendingUnit ) 
    

and also

    
    
        Outcome attack( MeleeBasedUnit attackingUnit, RangeBasedUnit defendingUnit ) 
    

it was the most elegant approaches I've seen. Not that you can't do it in C++,
but not as straightforward as it was in CLOS.

~~~
zenexer
In OOP, isn't that essentially just overloading? In many OO languages, you
could write both of those lines as-is (with corresponding method bodies) and
have valid code. They'll typically be treated as two separate methods that
just happen to have the same name.

~~~
oweiler
The main difference is that overloading is resolved at compilation time
whereas multi methods are resolved at runtime.

------
ramshorns
This seems pretty unrelated to the idea of covariant and contravariant four-
vectors in relativity and electromagnetism. I wonder if there's some clever
and insightful connection, or if it's more that the words just mean "varies
together" and "varies oppositely".

~~~
hhmc
In this case the terminology is by way of, roughly speaking

    
    
       type theory <- domain theory <- category theory
    

Perhaps one can draw a link from the latter to the operators in
electromagnetism.

~~~
ramshorns
Cool. It looks like the one place I'd seen these terms used is a subcategory
of one of a few different but related uses.

[https://en.wikipedia.org/wiki/Covariance_and_contravariance](https://en.wikipedia.org/wiki/Covariance_and_contravariance)

------
gpderetta
> C++’s classical OOP system supports “covariant return types,” but it does
> not support “contravariant parameter types.”

Interestingly enough, std::function correctly supports contravariant
parameters; it also correctly handles co/contra variance correctly via smart
pointers (as long as the smart pointers support it themselves of course).

------
saagarjha
Is the “obvious” behavior mentioned in the article what the standard
specifies? Because it’s surprising to me that the compilers are so broken in
these cases…

