This module implements a simple interface over dynamic dispatched traits. It allows one to define the required implementation for a type to match both at runtime and compile time. Enabling the writing of code that does not require inheritance, but still has dynamic dispatch.Defining -d:traitorNiceNames can be used to make the generate procedures have nicer names for debugging.
Types
AnyTraitor[Traits] = StaticTraitor[Traits] or Traitor[Traits]
- Allows writing a procedure that operates on both static and runtime. Source Edit
Atom = distinct int
- Default field name to be replaced for all Traits. Should be distinct void to prevent instantiation... Source Edit
GenericType = concept typeof(F) isGeneric(F)
- Cannot instantiate it so it's just checked it's a type T[...] = distinct tuple Source Edit
StaticTraitor[Traits] = concept st st.toTrait(Traits) is Traitor[Traits]
- Allows generic dispatch on types that fit traits Source Edit
Traitor[Traits] = ref object of RootObj vtable*: typeof(emitTupleType(Traits))
- Base Trait object used to ecapsulate the vtable Source Edit
TraitType = concept typeof(F) for field in default(distinctBase(F)).fields: when field is (proc): field.paramTypeAt(0) is Atom atomCount(typeof(field)) == 1 else: for child in field.fields: child.paramTypeAt(0) is Atom atomCount(typeof(child)) == 1 distinctBase(F) is tuple
- Forces tuples to only have procs that have Atom inside first param Source Edit
TypedTraitor[T; Traits] {.final, acyclic.} = ref object of Traitor[Traits] data*: T
- Typed Trait object has a known data type and can be unpacked Source Edit
Procs
proc getData[T; Traits](tratr: Traitor[Traits]; _: typedesc[T]): var T
-
Converts tratr to TypedTrait[T, Traits] then access data
Example:
type MyTrait = distinct tuple[doThing: proc(_: Atom){.nimcall.}] MyType = object x: int implTrait MyTrait proc doThing(typ: MyType) = discard let traitObj = MyType(x: 100).toTrait MyTrait assert traitObj.getData(MyType) == TypedTraitor[MyType, MyTrait](traitObj).data
Source Edit
Macros
macro emitTupleType(trait: typedesc): untyped
- Exported just to get around generic binding issue Source Edit
macro joinTraits(traits: varargs[typed]): untyped
- Source Edit
Templates
template emitConverter(T: typedesc; trait: typedesc[ValidTraitor])
- Emits a converter from T to Traitor[trait] This allows skipping of val.toTrait(trait) Source Edit
template implTrait(trait: typedesc[ValidTraitor])
-
Emits the vtable for the given trait and a procedure for types to convert to trait. It is checked that trait is only implemented once so repeated calls error.
Example:
type MyTrait = distinct tuple[bleh: proc(_: Atom, _: int) {.nimcall.}] implTrait MyTrait
Source Edit template setProc[T, Trait](traitor: TypedTraitor[T, Trait]; name: untyped; prc: proc)
- Allows one to override the vtable for a specific instance Source Edit