It turns out, you can use Dynamic
for opaque types, for example:
opaque type NamedPair
[LabelA <: LabelType, A, LabelB <: LabelType, B] <: Dynamic
= (A, B) & Dynamic
Thanks to @Jasper-M who used it in Should extension methods works with Dynamic trait? - #2 by Jasper-M
Applying this change, the main method looks like this after each phase:
At the beginning:
val john = P(age = 42, name = "John")
println(john.age)
After erasure:
val john: Tuple2 =
{
val b$proxy1: Tuple2 = Tuple2.apply("name", "John")
Tuple2.apply(Tuple2.apply("age", scala.Int.box(42))._2(),
b$proxy1._2()):Tuple2
}
println(
{
val $proxy1: Tuple.Pair$package =
Tuple.Pair$package:Tuple.Pair$package
val p$proxy1: Tuple2 = john:Tuple2
p$proxy1._1()
}
)
Adding back some syntactic sugar:
val john: Tuple2 = ( ("age", scala.Int.box(42))._2, ("name", "John")._2 )
println( john._1 )
It looks like the one thing missing is partial evaluation/constant folding of tuples
@Ichoran
I don’t know how to show the bytecode for it, but I guess it looks promising
I made a repo to host my experiments, you can see the updated example there