The implementation of `Any` in the standard library package
[typeinfo](https://nim-lang.org/docs/typeinfo.html) and the implementation of
`Variant` in @yglukhov's lovely [variant](https://github.com/yglukhov/variant)
package take an interestingly different approach to dissecting and using types
during compile-time execution. `typeinfo`'s approach is based on
`getTypeInfo()`, which yields a `PNimType`. `variant`'s approach is based on
`getTypeImpl()`, which yield a `NimNode`.
What are the strengths and weaknesses of these two approaches? Do they have
different limitations? Different maintainability? Are they ultimately
complementary? I.e. if a package goes far enough in dissecting and using types,
will it tend to use both? (And if so, is that a good thing?)
The implementation of `Any` begins by converting the type to a `PNimType`:
proc toAny*[T](x: var T): Any {.inline.} =
newAny(addr(x), cast[PNimType](getTypeInfo(x)))
Run
Then it dissects and uses that `PNimType` (as `rawType`). Here's a
representative example:
proc invokeNewSeq*(x: Any, len: int) =
assert x.rawType.kind == tySequence
var z = newSeq(x.rawType, len)
genericShallowAssign(x.value, addr(z), x.rawType)
Run
In contrast, the implementation of `Variant` begins by obtaining the type's
implementation as a `NimNode`:
proc mangledName(t: NimNode): string =
mangledNameAux(getTypeImpl(t)[1])
Run
Then it dissects the type by understanding that `NimNode` and by navigating
deeper with additional calls to `getTypeImpl()` or `getImpl()`. Here's a
representative example:
proc mangledNameAux(t: NimNode): string =
case t.typeKind
of ntyAlias:
assert(t.kind == nnkSym)
let impl = t.symbol.getImpl()
assert(impl.kind == nnkTypeDef)
result = mangledNameAux(impl[^1])
. . .
of ntySequence:
let impl = t.getTypeImpl()
assert impl.kind == nnkBracketExpr
assert impl.len == 2
result = "seq[" & mangledNameAux(impl[^1]) & "]"
. . .
Run
Thoughts on the pros and cons of these two approaches?
Dean