Hmm, I’m not sure I have really valid case, but maybe I’m using it as palliative for the lack of a “better” feature?
Example 1:
I’m using it as temporary store for a complicated calculated type (in a library for generic records)
erased trait TypeWitness[N]:
type T = N
erased given [T]: TypeWitness[T] = null
...
def renameField(field: String & Singleton, to: String & Singleton)
(using erased w: TypeWitness[IndexOf[TupleMap[Tup, @@[String & Singleton, Any], FieldName], field.type]])
(using i: ValueOf[w.T]): Tuple.Concat[Tuple.Take[Tup, w.T], (to.type @@ FieldType[Tuple.Elem[Tup, w.T]]) *: Tuple.Drop[Tup, S[w.T]]]
In the above example, w
is used 4 times in the following types, copy pasting all that type would not be desirable (furthermore I don’t know if the compiler caches the calculation of this type, which might not be cheap).
We could argue that the above is not a valid usage of erased and what I really wanted here is being able to declare an auxiliary type.
Example 2:
While using vulkan bindings, I have a wrapper layer that gives me a modular structure and methods on top of essentially C methods (so the api feels more like the c++ or rust one), and I have to make decisions about allocations of structs all the time. I abstracted this with
trait Allocator[S]:
type Buffer <: CustomBuffer[_] // ideally I should be able to not have to put an upper bound, but the compiler crashes if I don't when extending
inline def stackCalloc(stack: MemoryStack): S
inline def stackMalloc(stack: MemoryStack): S
inline def calloc(): S
inline def malloc(): S
transparent inline def stackCallocBuffer(stack: MemoryStack, capacity: Int): Buffer
transparent inline def stackMallocBuffer(stack: MemoryStack, capacity: Int): Buffer
transparent inline def callocBuffer(capacity: Int): Buffer
transparent inline def mallocBuffer(capacity: Int): Buffer
and then tons of methods are inline and take a AllocMethod and an implicit Allocator.
In this second exampe, I use erased to make sure that a reference to Allocator is never actually popping up in the bytecode, since it should only ever be inlining (and this happened a couple of times when I accidentally stored the allocator to a variable that wasn’t inline’d itself).
Same thing with a Managed[T]
that I use essentially auto freeing things once they are out of scope.
In this second example we could argue I’m abusing erased and I should just trust the compiler.