Given a value of some path-dependent type, how can I get an instance of the "container"?
It's more easily explained in code:
class Bippy {
val x = 42
class Boppy {
val y = "hello world"
}
val bop = new Boppy
}
val bip = new Bippy
val bop: Bippy#Boppy = b开发者_如何学Cip.bop
bop
is then supplied to another method, which needs to find the value x
from the containing instance of Bippy
. What's the magic incantation to do so?
The instance bop
comes from code that I don't control, so adding new methods to Boppy
isn't an option here.
You can't. At least not without cheating. Here's how to cheat.
def getOuter(bop : Bippy#Boppy) =
bop.asInstanceOf[{def Bippy$Boppy$$$outer() : Bippy}].Bippy$Boppy$$$outer()
Obviously that's very dependent on details of how scalac works today and no guarantees that it will work tomorrow.
As James said, you can't. His cheat makes my eyes bleed, and I suggest doing something else instead ;-)
I strongly recommend modifying the consumers of bop if you can. Rather than handing them an instance of Bippy#Boppy, hand them a pair comprising the value of the dependent type and the value that the type depends on,
trait DependentPack {
val bippy : Bippy
val boppy : bippy.Boppy
}
val bip = new Bippy
val bop = bip.bop
val dep = new DependentPack { val bippy = bip ; val boppy = bop }
foo(dep)
def foo(dp : DependentPack) = {
import dp._
// use bippy ...
// use boppy ...
}
Note that this is in part a workaround for the lack of dependent method types (enabled in scalac by adding the -Ydependent-method-types or -Xexperimental command line switches). If we had them, then we could drop artefacts like DependentPack and rewrite the above as,
val bip = new Bippy
val bop = bip.bop
foo(bip)(bop)
def foo(bippy : Bippy)(boppy : bippy.Boppy) = {
// use bippy ...
// use boppy ...
}
Needless to say, I think having dependent method types enabled by default would be highly desirable. Non-trivial uses of dependent types bring a world of pain with them in their absence unless you're very careful.
精彩评论