I'm evaluating the technical difficulty & runtime impact of implementing project Caprese in Scala (https://www.slideshare.net/Odersky/capabilities-for-resources-and-effects-252161040)
The scope of the project is to introduce a new substructural type system that can mix-in/evict new capabilities to a define term over its lifespan. Similar to the linear/affine type system of Rust, the compiler can now track its evolving usage/state and enable/disable its method at different part of the program.
I'm trying to mimic this capability using several terms that are different in types, but are identical in runtime, here is my code:
trait Cap
trait Cap1 extends Cap {
final def canDo(): Unit = {
println("canDo")
}
}
trait Cap2 extends Cap {
// ...some other capabilities
}
class HasNoCap extends Cap
// class HasCap1 extends HasNoCap with Cap1
val a = new HasNoCap
val b = a.asInstanceOf[HasNoCap & Cap1]
b.canDo()
Unfortunately, it can't be executed in JVM (haven't tried JavaScript or native compiler yet), despite the fact that HasNoCap
and HasCap1
has identical data structure:
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.tribbloids.spike.dotty.CapabilityTracking$.main(CapabilityTracking.scala:27)
at com.tribbloids.spike.dotty.CapabilityTracking.main(CapabilityTracking.scala)
Caused by: java.lang.ClassCastException: class com.tribbloids.spike.dotty.CapabilityTracking$ByDirectMixin$HasNoCap cannot be cast to class com.tribbloids.spike.dotty.CapabilityTracking$ByDirectMixin$Cap1 (com.tribbloids.spike.dotty.CapabilityTracking$ByDirectMixin$HasNoCap and com.tribbloids.spike.dotty.CapabilityTracking$ByDirectMixin$Cap1 are in unnamed module of loader 'app')
at com.tribbloids.spike.dotty.CapabilityTracking$ByDirectMixin$.<clinit>(CapabilityTracking.scala:23)
... 2 more
As a result, it appears that the compiler will rely heavily on extension methods (https://www.baeldung.com/scala/extension-methods), which to my knowledge has high overhead and may not be compatible with method override
Is there a method that allows me to bypass this limitation? Or it is simply impossible under current architecture?