A collection of useful macros, mostly related to the construction of objects.
nimble install constructor
constr works on procedures so you can match your preferred init method.
You can pass other parameters to the object constructor by having a variable named the same in the main scope of the procedure.
Aside from that it's practically like writting your own init procedure.
import constructor/constructor
typeUser=object
name: string
age: int
lastOnline: floatprocinitUser*(name: string, age: int): User {.constr.} # Can use like a forward declare.procinit(T: typedesc[User], name: string, age: int): User {.constr.} =result.lastOnline =30f
assertinitUser("hello", 10) ==User(name: "hello", lastOnline: 0f, age: 10)
assertUser.init("hello", 30) ==User(name: "hello", lastOnline: 30f, age: 30)
You can use the defaults macro, which allows you to easily generate a constructor with default values.
If your type is a value type the constructor is init<YOUR TYPE>() (e.g. initThingy()).
If your type is a reference object the constructor is new<YOUR TYPE>() (e.g. newThingy()).
import constructor/defaults
typeThingy {.defaults: {}.} =object
a: float=10# Can do it this way
b ="Hmm"# Can also do it this way
c =10assertinitThingy() ==Thingy(a: 10, b: "Hmm", c: 10)You can modify the generation of the defaults procedure by passing a set of DefaultFlag flags.
Currently implemented flags are:
defExported- Adds a '*' to the proc so that it is exported (e.g. generatesnewThingy\*()instead ofnewThingy())defTypeConstr- Changes the constructor signature for references fromnewThingy()tonew(_: typedesc Thingy)and for value types frominitThingy()toinit(_: typedesc[Thingy])defBothConstr- Includes bothinitThingy()/newThingyandnew(_: typedesc[Thingy])/init(_: typedesc[Thingy])
import constructor/defaults
typeThingy {.defaults: {defExported, defTypeConstr}.} =refobjectofRootObj
a: float=10# Can do it this way
b ="Hmm"# Can also do it this way
c =10assertnew(Thingy)[] ==Thingy(a: 10, b: "Hmm", c: 10)[]
typeOtherThingy {.defaults: {defBothConstr}.} =object
d ="lula"assertinit(OtherThingy) ==OtherThingy(d: "lula")
assertinitOtherThingy() ==OtherThingy(d: "lula")A variant of positional initialisers exists inside constructor/structinits.
There are type checks to ensure safety and it works on typedescs that are not object variants.
import constructor/structinits
typeMyType=object
x, y: int
z: stringMyRef=refMyTypeMyGen[T] =object
x: intassertMyType.init(10, 20, "hello") ==MyType(x: 10, y: 20, z: "hello")
assertMyType.new(10, 20, "hello")[] == (refMyType)(x: 10, y: 20, z: "hello")[]
assertMyRef.new(10, 20, "Hello")[] ==MyRef(x: 10, y: 20, z: "Hello")[]
assertMyGen[int].init(100) ==MyGen[int](x: 100)
assertMyGen[int].new(100)[] == (refMyGen[int])(x: 100)[]