static hierarchy with sub-typing

28 views
Skip to first unread message

Jan Vanek

unread,
Sep 7, 2012, 1:17:36 PM9/7/12
to scala-user
Hi,

I'm trying to encode hierarchy of named topics (topic is either a top-level topic or a sub-topic of a parent topic), where each topic defines its associated message type, so that the sub-topic's message type must be a sub-type of its parent topic's message type. Sounds easy but my scala level dropped recently.

object X {
    trait Topic {
        val name: String
        
        abstract class MessageBase
        
        type Message <: MessageBase
    }
    
    trait SubTopic extends Topic {
        val parent: Topic
        
        // type Message <: parent.Message // would be nice
        type Message <: parent.Message with MessageBase
    }
}

object Y {
    object Topic extends X.Topic {
        val name = "root"
            
        class Message(a: Int, b: String) extends MessageBase
    }

    class L2Topic(val name: String) extends X.SubTopic {
        val parent = Topic
        
        class Message(a: Int, b: String, c: Boolean) extends Topic.Message(a, b) // error
        // type Message = Topic.Message // error
    }
    
    val testTopic = new L2Topic("test")
}

How can I achieve it? I'm using 2.9. Thanks and regards,
Jan

Grégoire Neuville

unread,
Sep 7, 2012, 3:34:53 PM9/7/12
to scala...@googlegroups.com
Hello,

Here is what I can come with (I'm just a dilettantish scalaist) :

trait Topic[+M] { type Message = M; def message: Message}

trait SubTopic[M, S <: Topic[M]#Message] extends Topic[S]

class HistMessage { val value = " A History Message " }

class XXCentMessage extends HistMessage { override val value = " A
XXCent Message " }

class DummyMessage { val value = " A DUMMY Message " }

class History extends Topic[HistMessage] { def message = new HistMessage }

class XXCentury extends History with SubTopic[HistMessage,
XXCentMessage] { override def message = new XXCentMessage}

--

scala> val hist = new History

scala> hist.message.value
res3: java.lang.String = " A History Message "

--

scala> val xx = new XXCentury

scala> xx.message.value
res4: java.lang.String = " A XXCent Message "

--

scala> class XXCentury extends History with SubTopic[DummyMessage,
XXCentMessage] { override def message = new XXCentMessage}

<console>:13: error: type arguments [DummyMessage,XXCentMessage] do
not conform to trait SubTopic's type parameter bounds [M,S <: M]
class XXCentury extends History with SubTopic[DummyMessage,
XXCentMessage] { override def message = new XXCentMessage}

--

scala> class XXCentury extends History with SubTopic[HistMessage,
DummyMessage] { override def message = new XXCentMessage}

<console>:13: error: illegal inheritance;
class XXCentury inherits different type instances of trait Topic:
Topic[DummyMessage] and Topic[HistMessage]
class XXCentury extends History with SubTopic[HistMessage,
DummyMessage] { override def message = new XXCentMessage}
^
<console>:13: error: overriding method message in trait Topic of type
=> XXCentury.this.Message;
method message has incompatible type
class XXCentury extends History with SubTopic[HistMessage,
DummyMessage] { override def message = new XXCentMessage}

^
<console>:13: error: type arguments [HistMessage,DummyMessage] do not
conform to trait SubTopic's type parameter bounds [M,S <: M]
class XXCentury extends History with SubTopic[HistMessage,
DummyMessage] { override def message = new XXCentMessage}
^
--

scala> class XXCentury extends History with SubTopic[HistMessage,
DummyMessage] { override def message = new DummyMessage}

<console>:12: error: type mismatch;
found : DummyMessage
required: HistMessage
class XXCentury extends History with SubTopic[HistMessage,
DummyMessage] { override def message = new DummyMessage}

--

Hope this helps,

G.N
--
Grégoire Neuville


--
Grégoire Neuville

kHodel

unread,
Sep 7, 2012, 4:39:43 PM9/7/12
to scala...@googlegroups.com
Maybe something like the following?


abstract class X {
  abstract class MessageBase
  trait Topic {
    val name: String
    type Message <: MessageBase
  }
  trait SubTopic extends Topic {
    type BaseTopic <: Topic
    val parent: BaseTopic
    type Message <: BaseTopic#Message
  }
}

object Y extends X {
  class L1Message(a: Int, b: String) extends MessageBase
  class L2Message(a: Int, b: String, c: Boolean) extends L1Message(a, b)
  class L1Topic extends Topic {
    val name = "root"
    type Message = L1Message
  }
  class L2Topic(val name: String) extends SubTopic {
    type BaseTopic = L1Topic
    object parent extends L1Topic
    type Message = L2Message
  }
  val testTopic = new L2Topic("test")
}


Jan Vanek

unread,
Sep 10, 2012, 3:53:16 PM9/10/12
to scala...@googlegroups.com
On 07.09.2012 22:39, kHodel wrote:
Maybe something like the following?


abstract class X {
  abstract class MessageBase
  trait Topic {
    val name: String
    type Message <: MessageBase
  }
  trait SubTopic extends Topic {
    type BaseTopic <: Topic
    val parent: BaseTopic
    type Message <: BaseTopic#Message
  }
}


Hi, this is exactly what I came with (the only diff is "BaseTopic" <=> "ParentTopic"). I originally wanted the message to have/know its topic - similar to event has/knows its source, so I wanted the Message nested class in Topic. But it doesn't play nice to the requirement SubTopic#Message <: Parent#Message but SubTopic contains ParentTopic, not is sub-type of it. Finally I dropped that wish. Also, to be honest, I was confused not to see the problem with my original code.

Thanks and also thanks to Gregoire for comments,
Jan
Reply all
Reply to author
Forward
0 new messages