Restrict abstract types in traits

26 views
Skip to first unread message

Adam Dohnal

unread,
Nov 21, 2015, 11:15:04 PM11/21/15
to scala-user
Hello,

I am curious if something like this is supported somehow in Scala language. I will like to compile following program:

trait Base {
  type S
<: BaseState

  trait
BaseState {
   
def base: String
 
}

 
var state: S
}


trait
ExtensionA {
 
this: Base =>

 
// here I want to restrict that S must be subtype of ExtensionAState whenever this trait is mixed-in
  type S
<: ExtensionAState

  trait
ExtensionAState {
   
def extensionA: String
 
}

 
// this line does not compile
 
// I want this to be typesafe because state should be subtype both of BaseState and ExtensionAState
 
def extensionMethod() = state.base + state.extensionA
}


class Final extends Base with ExtensionA {
  type S
= State

 
var state = State("base", "extension")

 
case class State(base: String, extensionA: String) extends BaseState with ExtensionAState
}


object Test extends App {
  println
(new Final().extensionMethod())
}

Adam Dohnal

unread,
Nov 22, 2015, 5:18:41 AM11/22/15
to scala-user
After some sleep I found a solution, so following program compile and work as expected. The solution is to use inheritance instead of self type annotation to get access to parent abstract type and then I can extend it

trait Base {
  type S
<: BaseState

  trait
BaseState {
   
def base: String
 
}

 
var state: S
}

/**
 * Extends base trait with extensionA state property and extensionAMethod which can use state with both BaseState's
 * and ExtensionAState's properties
 */

trait
ExtensionA extends Base {
  type S
<: BaseState with ExtensionAState

  trait
ExtensionAState {
   
def extensionA: String
 
}

 
def extensionAMethod() = state.base + state.extensionA
}

/**
 * Extends base trait with extensionB state property and extensionBMethod which can use state with both BaseState's
 * and ExtensionBState's properties
 */

trait
ExtensionB extends Base {
  type S
<: BaseState with ExtensionBState

  trait
ExtensionBState {
   
def extensionB: String
 
}

 
def extensionBMethod() = state.base + state.extensionB
}

/**
 * Extends base trait with extensionC state property and extensionCMethod and define dependency to both
 * ExtensionA and ExtensionB, so the method extensionCMethod can use all state properties
 */

trait
ExtensionC extends Base with ExtensionA with ExtensionB {
  type S
<: BaseState with ExtensionAState with ExtensionBState with ExtensionCState

  trait
ExtensionCState {
   
def extensionC: String
 
}

 
def extensionCMethod() = state.base + state.extensionA + state.extensionB + state.extensionC
}

class Final extends Base with ExtensionA with ExtensionB with ExtensionC {
  type S
= State

 
var state = State("base", "extensionA", "extensionB", "extensionC")

 
case class State(base: String,
                   extensionA
: String,
                   extensionB
: String,
                   extensionC
: String) extends BaseState with ExtensionAState with ExtensionBState with ExtensionCState
}

object Test extends App {
  val obj
= new Final()

  println
(obj.extensionAMethod())
  println
(obj.extensionBMethod())
  println
(obj.extensionCMethod())
}


Reply all
Reply to author
Forward
0 new messages