<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>mikeash.com pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html comments</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>mikeash.com Recent Comments</description><lastBuildDate>Mon, 17 Aug 2026 11:20:27 GMT</lastBuildDate><generator>PyRSS2Gen-1.0.0</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>J2 - 2021-04-08 13:10:58</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>There is an error:
&lt;br /&gt;
&lt;br /&gt;"This is another key rule: functions are subtypes of other functions if the parameter types are supertypes and the return types are subtypes."
&lt;br /&gt;
&lt;br /&gt;Should be
&lt;br /&gt;
&lt;br /&gt;"This is another key rule: functions are subtypes of other functions if the parameter types are subtypes and the return types are supertypes."</description><guid isPermaLink="true">7b0fdb7d11102fb73552d35e0f6189c7</guid><pubDate>Thu, 08 Apr 2021 13:10:58 GMT</pubDate></item><item><title>mikeash - 2017-09-23 23:41:29</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>My guess is just that there are higher priorities and they haven't gotten around to it yet. That's the answer for a lot of "obvious" features the language doesn't have. It's still pretty young.</description><guid isPermaLink="true">d0f60845efa4c3dfacd87d191dd3e3a4</guid><pubDate>Sat, 23 Sep 2017 23:41:29 GMT</pubDate></item><item><title>Oleg - 2017-09-23 20:44:41</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>Hi Mike.
&lt;br /&gt;Could you please explain/guess why in swift it was decided to use invariant generics? For me it is wierd, i've tried to use some of my obj-c code with generics (that involves subtyping) via bridging in swift and it gets useless without casts. I wonder isn't swift compiler wise enough to infer generic type variance?</description><guid isPermaLink="true">83da56511fe00d9997a5783c7748e26e</guid><pubDate>Sat, 23 Sep 2017 20:44:41 GMT</pubDate></item><item><title>mikeash - 2016-06-08 01:54:25</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>Right, the first line works, the second line doesn't.</description><guid isPermaLink="true">67542022359ced1de8f30e31c9a65705</guid><pubDate>Wed, 08 Jun 2016 01:54:25 GMT</pubDate></item><item><title>Saurav Nagpal - 2016-06-06 10:04:18</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>Hi Mike 
&lt;br /&gt;
&lt;br /&gt;let returnsCat: () -&amp;gt; Cat = animalF
&lt;br /&gt;
&lt;br /&gt;I think this will not work. Because return Cat is subtype of function animalF. As you said superTypes cannot substitute subtypes. </description><guid isPermaLink="true">710b58946d64b527e08b15d7664062d3</guid><pubDate>Mon, 06 Jun 2016 10:04:18 GMT</pubDate></item><item><title>Spud - 2015-12-11 20:33:08</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>the way you wrote:
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let returnsCat: () -&amp;gt; Cat = animalF
&lt;br /&gt;
&lt;br /&gt;and started the following paragraph "All of this works in Objective-C too,d" made me think that was legal.  suggest putting a comment beside it like // illegal 
&lt;br /&gt;</description><guid isPermaLink="true">99fa827b617cef917855070943f09970</guid><pubDate>Fri, 11 Dec 2015 20:33:08 GMT</pubDate></item><item><title>VinDuv - 2015-11-23 12:36:19</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>There is an interesting problem with generic collection covariance: it potentially allows objects of the wrong type to be inserted in the collection.
&lt;br /&gt;
&lt;br /&gt;I’m told that the first version of Java had covariant arrays without sufficient protection, which allowed to downcast objects without compile time or runtime checks:
&lt;br /&gt;&lt;code&gt;
&lt;br /&gt;// Cat is a subclass of Animal
&lt;br /&gt;Cat[] cats = ...;
&lt;br /&gt;Animal[] animals = cats; // Array covariance is allowed
&lt;br /&gt;animals[0] = new Dog(); // Putting a Dog into an array of Animal: no complaint from the compiler, no runtime check
&lt;br /&gt;Cat cat = cats[0]; // We try to get a Cat from the array of Cat but it’s a Dog!
&lt;br /&gt;cat.purr(); // invalid method call, will probably crash the JVM
&lt;br /&gt;&lt;/code&gt;
&lt;br /&gt;On current Java implementations, the above code still compiles, but the assignation to &lt;code&gt;animals[0]&lt;/code&gt; fails with an ArrayStoreException.
&lt;br /&gt;
&lt;br /&gt;Fortunately, with Swift’s copy-on-write arrays, this code is perfectly fine: the assignment of &lt;code&gt;animals[0]&lt;/code&gt; will create a copy of the array, so &lt;code&gt;cats&lt;/code&gt; will still only contain &lt;code&gt;Cat&lt;/code&gt;s.
&lt;br /&gt;
&lt;br /&gt;Maybe this Array-specific feature could be provided to custom generic container types, but I’m not sure if it’s doable in a “safe” (compiler-checked) manner.</description><guid isPermaLink="true">de0c671d49ab210e369af33d2d662c65</guid><pubDate>Mon, 23 Nov 2015 12:36:19 GMT</pubDate></item><item><title>Sven - 2015-11-22 10:36:28</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>I believe subtype and supertype are mixed up in the Generics section as well. Method return types and r/o properties should be subtypes and method parameters should be supertypes, right?</description><guid isPermaLink="true">8fcab0942f80e4dedfa0f3d662c45a35</guid><pubDate>Sun, 22 Nov 2015 10:36:28 GMT</pubDate></item><item><title>mikeash - 2015-11-21 18:00:20</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>&lt;b&gt;J:&lt;/b&gt; Thanks, fixed now. This stuff still does mix me up sometimes.
&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Matthew Cheok:&lt;/b&gt; It looks like protocols don't support changing types at all. If you take a protocol that inherits from another protocol and try to "override" the super-protocol's function with one that has different types, Swift just treats it as a new function regardless of variance. You can try this code to see:
&lt;br /&gt;&lt;code&gt;
&lt;br /&gt;class Thing {}
&lt;br /&gt;class Animal: Thing {}
&lt;br /&gt;class Cat: Animal {}
&lt;br /&gt;
&lt;br /&gt;protocol SuperP {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func f(animal: Animal) -&amp;gt; Animal
&lt;br /&gt;}
&lt;br /&gt;
&lt;br /&gt;protocol SubP1: SuperP {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func f(thing: Thing) -&amp;gt; Cat
&lt;br /&gt;}
&lt;br /&gt;
&lt;br /&gt;protocol SubP2: SuperP {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func f(cat: Cat) -&amp;gt; Thing
&lt;br /&gt;}
&lt;br /&gt;
&lt;br /&gt;class ImplementsSubP1: SubP1 {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func f(thing: Thing) -&amp;gt; Cat {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return Cat()
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;}
&lt;br /&gt;
&lt;br /&gt;class ImplementsSubP2: SubP2 {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func f(cat: Cat) -&amp;gt; Thing {
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return Thing()
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;}&lt;/code&gt;
&lt;br /&gt;
&lt;br /&gt;Neither of the two classes are considered to fully implement the protocols. If you add a second &lt;code&gt;f&lt;/code&gt; to each class that's &lt;code&gt;Animal -&amp;gt; Animal&lt;/code&gt; then it works.</description><guid isPermaLink="true">3d4a17e7f01db63e17462b62a940c9e9</guid><pubDate>Sat, 21 Nov 2015 18:00:20 GMT</pubDate></item><item><title>Matthew Cheok - 2015-11-21 16:58:15</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>Suppose the discussion for subclass applies to protocols as well? Thanks for this! It's succinct and easily digestible. I find it more helpful to replace A, B and C with something I'm more familiar with like NSObject, UIView and UILabel.</description><guid isPermaLink="true">9696c69ff300588d35715171b72eb08c</guid><pubDate>Sat, 21 Nov 2015 16:58:15 GMT</pubDate></item><item><title>J - 2015-11-21 16:22:07</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>I think "subtype" and "supertype" are reversed in the Standalone Functions section
&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogcommentquote"&gt;&lt;div class="blogcommentquoteinner"&gt;Applied here, the above code works if A is a subtype of C, and if B is a supertype of D.&lt;/div&gt;&lt;/div&gt;
&lt;br /&gt;should be
&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogcommentquote"&gt;&lt;div class="blogcommentquoteinner"&gt;Applied here, the above code works if A is a supertype of C, and if B is a subtype of D.&lt;/div&gt;&lt;/div&gt;</description><guid isPermaLink="true">1998ca32c83dff47c403da5ced2f1dc3</guid><pubDate>Sat, 21 Nov 2015 16:22:07 GMT</pubDate></item><item><title>Kyle McAlpine - 2015-11-21 11:45:33</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>Thanks for this Mike! Just as I posted a SO question on this topic! Haha!
&lt;br /&gt;
&lt;br /&gt;&lt;a href="http://stackoverflow.com/questions/33752968/swift-cast-generic-type-into-same-generic-type-but-with-a-subclass-of-associate/33759858#33759858"&gt;http://stackoverflow.com/questions/33752968/swift-cast-generic-type-into-same-generic-type-but-with-a-subclass-of-associate/33759858#33759858&lt;/a&gt;</description><guid isPermaLink="true">c04f4df48ae34dbe4bea9607ec710a28</guid><pubDate>Sat, 21 Nov 2015 11:45:33 GMT</pubDate></item><item><title>Rick - 2015-11-20 22:09:06</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>Even more complex and subtle: part of the deal with &lt;code&gt;__covariant&lt;/code&gt; showing up in ObjC and NSArray might be compatibility/bridging with Swift. 
&lt;br /&gt;
&lt;br /&gt;Swift generics are normally invariant, but the Swift standard library collection types — even though those types appear to be regular generic types — use some sort of magic inaccessible to mere mortals that lets them be covariant.
&lt;br /&gt;
&lt;br /&gt;Take a look... here's a quick concrete example of invariant generic types in Swift:
&lt;br /&gt;&lt;code&gt;
&lt;br /&gt;import UIKit
&lt;br /&gt;
&lt;br /&gt;class Thing&amp;lt;T&amp;gt; { // could be a struct just as well
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var thing: T
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;init(_ thing: T) { self.thing = thing }
&lt;br /&gt;}
&lt;br /&gt;var foo: Thing&amp;lt;UIView&amp;gt; = Thing(UIView())
&lt;br /&gt;var bar: Thing&amp;lt;UIButton&amp;gt; = Thing(UIButton())
&lt;br /&gt;foo = bar // error: cannot assign value of type 'Thing&amp;lt;UIButton&amp;gt;' to type 'Thing&amp;lt;UIView&amp;gt;'
&lt;br /&gt;&lt;/code&gt;
&lt;br /&gt;But Array lets you do the same thing without error:
&lt;br /&gt;&lt;code&gt;
&lt;br /&gt;var views: Array&amp;lt;UIView&amp;gt; = [UIView()]
&lt;br /&gt;var buttons: Array&amp;lt;UIButton&amp;gt; = [UIButton()]
&lt;br /&gt;views = buttons
&lt;br /&gt;&lt;/code&gt;
&lt;br /&gt;(Note that if you tried to assign &lt;code&gt;buttons = views&lt;/code&gt; instead, you'd get an error: Swift collections are covariant, not contravariant or bivariant.)</description><guid isPermaLink="true">e1defaef8e71a2dcc471b51f67725737</guid><pubDate>Fri, 20 Nov 2015 22:09:06 GMT</pubDate></item><item><title>George Kulakowski - 2015-11-20 16:57:43</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html#comments</link><description>Nice post!
&lt;br /&gt;
&lt;br /&gt;You're right that bivariance doesn't come up much in Swift (or Java or...). All you could do with a bivariant type parameter is use it to construct other bivariant generic types, or to not use it (and why might you want to do that?).
&lt;br /&gt;
&lt;br /&gt;&lt;a href="https://people.cs.umass.edu/~yannis/variance-extended2011.pdf"&gt;https://people.cs.umass.edu/~yannis/variance-extended2011.pdf&lt;/a&gt; talks about variance, and 3.3 about a setting where bivariant types could come into play, with recursive types. It's pretty readable, as these things go.
&lt;br /&gt;
&lt;br /&gt;&lt;a href="https://github.com/rust-lang/meeting-minutes/blob/master/workweek-2014-08-18/markers-variance.md"&gt;https://github.com/rust-lang/meeting-minutes/blob/master/workweek-2014-08-18/markers-variance.md&lt;/a&gt; and &lt;a href="https://github.com/rust-lang/rfcs/blob/master/text/0738-variance.md"&gt;https://github.com/rust-lang/rfcs/blob/master/text/0738-variance.md&lt;/a&gt; talk about variance in Rust, where the interactions with lifetimes make things a bit more interesting. (I'm not sure how up-to-date these are, may not reflect Rust today, etc.)</description><guid isPermaLink="true">e43de30c82e05ee25b1d44a0df949171</guid><pubDate>Fri, 20 Nov 2015 16:57:43 GMT</pubDate></item></channel></rss>
