1
votes

I have a scenario that is causing a type mismatch that I cannot seem to resolve. Here's a simplified version of the code:

abstract class Msg

trait Channel[M <: Msg] {
  def receive(): M
  def ack(envelope: M)
}

object ChannelSender {
  private var channel : Channel[_ <: Msg] = _
  def assignChannel(channel : Channel[_ <: Msg]) = this.channel = channel

  def test() {
    val msg = channel.receive()
    channel.ack(msg) // Type mismatch here
  }
}

The error from the compiler is:

type mismatch; found : msg.type (with underlying type com.msgtest.Envelope) required: _$1 where type _$1 <: com.msgtest.Envelope

What sort of changes could I make to get this working? Additionally, the changes require that the following concrete implementation compile:

class SomeMsg extends Msg

object SomeChannel extends Channel[SomeMsg] {
  def receive(): SomeMsg = { null.asInstanceOf[SomeMsg] }
  def ack(envelope: SomeMsg) {}
}

object Setup {
  ChannelSender.assignChannel(SomeChannel)
}
1

1 Answers

4
votes

I could get it to compile under Scala 2.9 with two changes,

trait Channel[M <: Msg] {
  type M2 = M       // Introduce a type member that's externally visible
  def receive(): M2
  def ack(envelope: M2)
}

object ChannelSender {
  private var channel : Channel[_ <: Msg] = _
  def assignChannel(channel : Channel[_ <: Msg]) = this.channel = channel

  def test() {
    val c = channel  // An immutable value, so that c.M2 is stable
    val msg = c.receive()
    c.ack(msg)       // OK now
  }
}

The first change is to use an immutable value val c = channel, so that the path dependent type c.M2 always means the same thing. The second change is to introduce a type member type M2 = M in trait Channel. I'm not totally sure why this is necessary (could it be a bug?). One thing to note is that c.M2 is a valid type, whereas c.M is undefined.