This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Recursive composition of a contravariant type

2 replies
Sebastien Bocq
Joined: 2008-12-18,
User offline. Last seen 42 years 45 weeks ago.
Hello,

I would like to connect an output channel to another output channel to implement a form of indirection, for example to pass on messages from an Output[String] to an Output[Any]. I modeled my problem using the code snipped below. Since output channels are contravariant the compiler doesn't like my `connect` method.

trait MyOutput[-E] {
 
  private[this] var o:MyOutput[_ >: E] = _
 
  def connect(oc:MyOutput[_ >: E]) {  // See error below
    o = oc
  }
 
  def !(e:E) {
    o!e
  }
}

The error I get is:

<console>:8: error: contravariant type E occurs in covariant position in type MyOutput[_ >: E] of value oc
         def connect(oc:MyOutput[_ >: E]) {
                     ^

This looks simple but it's a real puzzler for me... :(

Thanks,
Sebastien
ewilligers
Joined: 2008-08-20,
User offline. Last seen 3 years 17 weeks ago.
Re: Recursive composition of a contravariant type

Sebastien Bocq wrote:
> Hello,
>
> I would like to connect an output channel to another output channel to
> implement a form of indirection, for example to pass on messages from an
> Output[String] to an Output[Any]. I modeled my problem using the code
> snipped below. Since output channels are contravariant the compiler
> doesn't like my `connect` method.
>
> trait MyOutput[-E] {
>
> private[this] var o:MyOutput[_ >: E] = _
>
> def connect(oc:MyOutput[_ >: E]) { // See error below
> o = oc
> }
>
> def !(e:E) {
> o!e
> }
> }
>
> The error I get is:
>
> :8: error: contravariant type E occurs in covariant position in
> type MyOutput[_ >: E] of value oc
> def connect(oc:MyOutput[_ >: E]) {
> ^
>
> This looks simple but it's a real puzzler for me... :(

This can't be done type safely when you have mutability and aliasing.

trait MyOutput[-E] {
private[this] var o: MyOutput[_ >: E] = _

def connect(oc: Any) {
o = oc.asInstanceOf[MyOutput[_ >: E]]
}

def !(e:E) {
o!e
}
}

object Test extends Application {
val o2 = new MyOutput[String] { override def !(e:String) {} }
val o1 = new MyOutput[Any] {}
(o1 : MyOutput[String]).connect(o2)
o1 ! this // ClassCastException when we pass anything other than a
String
}

Sebastien Bocq
Joined: 2008-12-18,
User offline. Last seen 42 years 45 weeks ago.
Re: Re: Recursive composition of a contravariant type
Ok, I understand why the compiler was not happy now...

Thanks a lot!
Sebastien

2008/12/23 Eric Willigers <ewilligers [at] gmail [dot] com>
Sebastien Bocq wrote:
Hello,

I would like to connect an output channel to another output channel to implement a form of indirection, for example to pass on messages from an Output[String] to an Output[Any]. I modeled my problem using the code snipped below. Since output channels are contravariant the compiler doesn't like my `connect` method.

trait MyOutput[-E] {
   private[this] var o:MyOutput[_ >: E] = _
   def connect(oc:MyOutput[_ >: E]) {  // See error below
   o = oc
 }
   def !(e:E) {
   o!e
 }
}

The error I get is:

<console>:8: error: contravariant type E occurs in covariant position in type MyOutput[_ >: E] of value oc
        def connect(oc:MyOutput[_ >: E]) {
                    ^

This looks simple but it's a real puzzler for me... :(


This can't be done type safely when you have mutability and aliasing.

trait MyOutput[-E] {
 private[this] var o: MyOutput[_ >: E] = _

 def connect(oc: Any) {
   o = oc.asInstanceOf[MyOutput[_ >: E]]
 }

 def !(e:E) {
   o!e
 }
}

object Test extends Application {
   val o2 = new MyOutput[String] { override def !(e:String) {} }
   val o1 = new MyOutput[Any] {}
   (o1 : MyOutput[String]).connect(o2)
   o1 ! this // ClassCastException when we pass anything other than a String
}


Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland