Capacytron
Capacytron

Reputation: 3739

Compile time type check when adding element elements to list

Is it possible to implement it at compile time using Scala?

Use case:

It's easy to check in runtime, and are there any solutions to implement it at compile time? The goal is to make IDE to highlight compile error.


trait Thing

trait SimpleThing extends Thing

trait ComplexThing extends Thing

sealed case class DummySimpleThing() extends SimpleThing

sealed case class InstanceOfComplexThing() extends ComplexThing

class ThingRepository {
  private val buffer = new ListBuffer[Thing]()

  def addThing(thing: Thing): ThingRepository = {
    buffer += thing
    this
  }
}

object TestThingRepository {

  def testAddThings() = {
    new ThingRepository()
      .addThing(DummySimpleThing())
      .addThing(DummySimpleThing()) // it's ok to add SimpleThing after SimpleThing
      .addThing(InstanceOfComplexThing()) // it's ok to add ComplexThing after SimpleThing

      .addThing(DummySimpleThing()) // Not allowed to add anything after ComplexThing, how can I get compile time error here?
      .addThing(InstanceOfComplexThing()) // Not allowed anything after ComplexThing, how can I get compile time error here?
  }
}

Upvotes: 1

Views: 80

Answers (1)

Tim
Tim

Reputation: 27421

You cannot do this with a mutable repository because you can't change the signature of a class once it is defined.

It would be possible to do this if addThing returned a new repository, because adding ComplexThing could return a repository without an addThing method while adding SimpleThing returns a repository with an addThing method.

case class StaticThingRepository(buffer: List[Thing])

class ThingRepository private(buffer: List[Thing]) {  
  def addThing(thing: Thing): ThingRepository =
    new ThingRepository(buffer :+ thing)

  def addThing(thing: ComplexThing): StaticThingRepository =
    StaticThingRepository(buffer :+ thing)
}

object ThingRepository {
  def apply() = new ThingRepository(Nil)
}

Upvotes: 2

Related Questions