My meta-question would be “How do I ask this question intelligibly?” but perhaps an example would make it clearer:
trait Toolbox {
trait Bolt
trait Wrench {
def tighten(b : Bolt)
}
def getWrench : Wrench
def getBolt : Bolt
}
object MetricToolbox extends Toolbox {
...
}
object EnglishToolbox extends Toolbox {
...
}
Of course, a metric wrench can only tighten a metric bolt; ditto for tools from the English toolbox. My question is, how do I express that in a type-safe way so the following won’t compile:
MetricToolbox.getWrench tighten EnglishToolbox.getBolt
but the following will:
def doTighten(box : Toolbox) = box.getWrench tighten box.getBolt
I know for a fact that this is possible because I heard Martin Odersky say it with his own mouth at the Scala meetup last night but at that moment, my wife called my cell and I had to scurry out of the room before he explained how.
EDIT didierd pointed out that my code worked as written. He’s right — I’m a little unclear on the details but it does. The natural reverse questions is, how do I not do that? The answer was pretty simple: put those classes at the same level as the main trait.
trait Nail
trait Hammer {
def pound(n : Nail)
}
trait Toolbox {
trait Bolt
trait Wrench {
def tighten(b : Bolt)
}
def getWrench : Wrench
def getBolt : Bolt
def getNail : Nail
def getHammer : Hammer
}
MetricToolbox.getHammer pound EnglishToolbox.getNail // this DOES compile
As written, it already works. As
BoltandWrenchare nested insideToolbox, theBoltthat types the argument oftightenmeans aBoltof this exact toolbox, not aBoltof any toolbox. They are written respectivelysomeToolbox.Bolt, which means aBoltof the exact instancesomeToolBoxandToolbox#Bolt, which means theBoltdefined in the typeToolbox, whatever the insatance toolbox. SoToolbox#Boltis a common supertype of allx.Bolt.Here
Boltwithout qualification meansthis.Bolt,thisbeing the enclosing Toolbox. So you cannot mix.