teryret
teryret

Reputation: 577

Is there a way to require constructors that take particular arguments?

I think what I'm trying to do is easy, but I'm not getting the right collection of search terms. What I want is a trait that guarantees that all implementing classes have a constructor that can be invoked with an object of a known type. The syntax ought to be:

trait Message {
  def this(rdr: msgpack.MsgReader): Message
}

but the compiler tells me it expects an equals sign. Any idea how to do this?

Upvotes: 0

Views: 63

Answers (1)

HTNW
HTNW

Reputation: 29193

Use the typeclass pattern instead:

trait Message[T] {
  def read(reader: msgpack.MsgReader): T
  // Example of what would be a normal instance method.
  // thiz is similar to this, except because we're in another object it must be explicitly taken as parameter.
  // It's in a separate param list for convention and ease of currying
  def foo(thiz: T)(param1: Int): Boolean
}

// "Implementors" don't actually implement it, the behavior exists as its own singleton
class Foo { ... }

implicit object FooMessage extends Message[Foo] {
  // Note that this is not restricted to just constructors. If you want that then you are really out of luck. (And probably doing it wrong.)
  override def read(reader: msgpack.MsgReader) = ???
  override def foo(thiz: Foo)(param1: Int) = thiz.foo(param1)
}

// Usage
// Use an explicit, named implicit param to avoid implicitly
def readMsg[T: Message](reader: msgpack.MsgReader) = implicitly[Message[T]].read(reader)

val foo = readMsg[Foo](???)

Upvotes: 1

Related Questions