Composing subclasses to achieve type restriction

71 Views Asked by At

I am new to Scala and learning to code a personal project in it.

I have this issue and looking around did not help much. So here it is -

abstract class Service{
 def containsFeatures(x: Feature*) = ??? 
 } 

object Service1 extends Service{..
 def containsFeature(x: Feature*)
 }

object Service2 extends Service{..
 def containsFeature(x: Feature*)
 }

Trait Feature

case object A extends Feature
case object B extends Feature
case object C extends Feature
case object D extends Feature
case object E extends Feature
case object F extends Feature
case object G extends Feature

I would like to restrict my code in such a way that Service1 defines which features are possible and which are erroneous. Eg: Service1 allows composing objects A, C, E, G and shows error when other features are supplied.

Is this possible to programmatically restrict this just with our definition of Service1 without modifying the other classes?

I hope my question is clear enough.

Thanks for any suggestions.

1

There are 1 best solutions below

3
On BEST ANSWER

If you want scalac to show an error at compile time when a wrong Feature is supplied, AND you cannot alter anything other than Service1 then it is not possible. The compiler accepts or rejects a call to Service1.containsFeature based on its interface, but its interface is already defined in Service where it says that it will accept any Feature.

If you CAN change things about the other code, there are some ways to do this. For instance if you can change everything:

scala> :paste
// Entering paste mode (ctrl-D to finish)

abstract class Service[Allowed <: Feature] {
  def containsFeatures(x: Allowed*): Unit
} 

object Service1 extends Service[S1Feature] {
  def containsFeatures(x: S1Feature*): Unit = println("ok")
}

object Service2 extends Service[S2Feature] {
  def containsFeatures(x: S2Feature*): Unit = println("ok")
}

sealed trait Feature
sealed trait S1Feature extends Feature
sealed trait S2Feature extends Feature

case object A extends S1Feature
case object B extends S2Feature
case object C extends S1Feature
case object D extends S2Feature
case object E extends S1Feature
case object F extends S2Feature
case object G extends S1Feature

// Exiting paste mode, now interpreting.

scala> Service1.containsFeatures(A,B,C)
<console>:16: error: type mismatch;
 found   : B.type
 required: S1Feature
       Service1.containsFeatures(A,B,C)
                                   ^

scala> Service1.containsFeatures(A,C,G)
ok