title: Use-site vs declaration-site difference in type projections in Kotlin
body: <h2>Type Hierarchy</h2>
  <pre><code>open class Fruit()
  
  open class CitrusFruit : Fruit()
  
  class Orange : CitrusFruit()
  </code></pre>
  <hr />
  <h2>Declaration-site Variance</h2>
  <p>The <code>Crate</code> is used as a producer or consumer of <code>Fruit</code>s.</p>
  <p><strong>Invariant class</strong></p>
  <pre><code>class Crate&lt;T&gt;(private val elements: MutableList&lt;T&gt;) {
      fun add(t: T) = elements.add(t)    // Consumer allowed
      fun last(): T = elements.last()    // Producer allowed
  }
  </code></pre>
  <p><strong>Covariant class<sup><code>out</code></sup></strong></p>
  <pre><code>class Crate&lt;out T&gt;(private val elements: MutableList&lt;T&gt;) {
      fun add(t: T) = elements.add(t)    // Consumer not allowed: Error
      fun last(): T = elements.last()    // Producer allowed
  }
  </code></pre>
  <p><strong>Contravariant class<sup><code>in</code></sup></strong></p>
  <pre><code>class Crate&lt;in T&gt;(private val elements: MutableList&lt;T&gt;) {
      fun add(t: T) = elements.add(t)    // Consumer allowed
      fun last(): T = elements.last()    // Producer not allowed: Error
  }
  </code></pre>
  <hr />
  <h2>Use-site Variance</h2>
  <p>All these use-site projections are for the <em>invariant class</em> <code>Crate&lt;T&gt;</code> defined above.</p>
  <p><strong>No Projection</strong></p>
  <p>No subtyping allowed: Only the <code>Crate&lt;Fruit&gt;</code> can be assigned to a <code>Crate&lt;Fruit&gt;</code>.</p>
  <pre><code>fun main() {
      val invariantCrate: Crate&lt;Fruit&gt; = Crate&lt;Fruit&gt;(mutableListOf(Fruit(), Orange()))
  
      invariantCrate.add(Orange())       // Consumer allowed
      invariantCrate.last()              // Producer allowed
  }
  </code></pre>
  <p><strong>Covariant Projection<sup><code>out</code></sup></strong></p>
  <p>Subtyping allowed: <code>Crate&lt;CitrusFruit&gt;</code> can be assigned to <code>Crate&lt;Fruit&gt;</code> when <code>CitrusFruit</code> is a subtype of <code>Fruit</code>.</p>
  <pre><code>fun main() {
      val covariantCrate: Crate&lt;out Fruit&gt; = Crate&lt;CitrusFruit&gt;(mutableListOf(Orange()))
  
      covariantCrate.add(Orange())       // Consumer not allowed: Error
      covariantCrate.last()              // Producer allowed
  }
  </code></pre>
  <p><strong>Contravariant Projection<sup><code>in</code></sup></strong></p>
  <p>Subtyping allowed: <code>Crate&lt;CitrusFruit&gt;</code> can be assigned to <code>Crate&lt;Orange&gt;</code> when the <code>CitrusFruit</code> is a supertype of <code>Orange</code>.</p>
  <pre><code>fun main() {
      val contravariantCrate: Crate&lt;in Orange&gt; = Crate&lt;CitrusFruit&gt;(mutableListOf(Orange()))
  
      contravariantCrate.add(Orange())   // Consumer allowed
      contravariantCrate.last()          // Producer allowed: No Error?
  }
  </code></pre>
  <hr />
  <h2>Questions</h2>
  <ol>
  <li><p>Is my understanding and the use of type projection correct in the given example?</p>
  </li>
  <li><p>For contravariance: why is the <code>last()</code>(producer) function not allowed at declaration-site but allowed at use-site? Shouldn't the compiler show an error like it shows in the declaration-site example? Maybe I'm missing something? If the producer is allowed for contravariance only at use-site, what could be the use case for it?</p>
  </li>
  </ol>
  <hr />
  <p>I prefer detailed answers with examples but any kind input will be much appreciated.</p>