Details ~ Transformation Description - miniboxing/ildl-plugin GitHub Wiki
If you haven't read the introduction and first example already, it's a good time to do so, as this advanced discussion assumes familiarity with the ildl-plugin
.
In this section we will show some tricks for creating transformation objects. There are five sections:
- Transformation Objects
- Writing Coercions
- Handling Generics
- Intercepting Methods
- Annotations
All of the API mentioned in this part lives in the ildl-plugin
repository, in the components/runtime/src
directory. If you have imported the ildl-*
projects in the Scala IDE, you can find the classes under the ildl-runtime
project, in the src
directory.
Transformation Objects
Transformation descriptions have to be objects and need to extend one of the two marker traits:
- (Flexible)
TransformationDescription
Objects and RigidTransformationDescription
Objects
It is recommended that description objects do not inherit from anything whose members contain either @high
or @repr
annotations. Currently this is not enforced in the plugin but seeing its dangers, we will soon add checks against it.
Going back to the marker traits, the difference between the two comes from the ability to target generic data types: flexible transformations can target any generic type while rigid transformations can only target monomorphic types.
A note about generics: It is important to distinguish between targeting generics and targeting inside generics. Current ildl
transformations can target generic types such as List[T]
and use the type parameters in the transformation (e.g. to LazyList[T]
) but, under the current generics compilation scheme, they cannot target inside generics, for example targeting BigInt
inside List[BigInt]
. This is why, in the efficient collections benchmark, we had to create two objects: BigIntToLong
and QueueOfBigIntToFunnyQueue
. This will be discussed later in detail.
Writing Coercions
Both the TransformationDescription
and the RigidTransformationDescription
objects have the two toRepr
and toHigh
coercions:
- in flexible transformations these can be fully generic, taking as many type parameters as necessary:
object MyFlexibleTransformation extends TransformationDescription {
def toRepr[T](high: List[T]): Vector[T] @high = high.toVector
def toHigh[T](repr: Vector[T] @high): List[T] = repr.toList
}
- in rigid transformations these must not have type parameters and must only convert between the
High
andRepr
types defined in theRigidTransformationDescription
:
object MyRigidTransformation extends RigidTransformationDescription {
type High = List[Int]
type Repr = Vector[Int]
def toRepr(high: List[Int]): Vector[Int] @high = high.toVector
def toHigh(repr: Vector[Int] @high): List[Int] = repr.toList
}
A word of warning in writing coercions: Coercions are automatically considered to be transparent:
X.toHigh(X.toRepr(obj)) == obj
Not respecting this restriction can lead to incorrect behaviour and loss of data. Furthermore, for mutable collections, where aliasing can occur, or for objects that can be used for synchronization, the following (much stronger) restriction applies:
X.toHigh(X.toRepr(obj)) eq obj
This ...
From here:
- continue reading the in-depth explanation scope nesting
- get back to the home page