pure/typetraits

  Source   Edit

This module defines compile-time reflection procs for working with types.

Unstable API.

Example:

import pure/typetraits
type A = enum a0 = 2, a1 = 4, a2
type B = enum b0 = 2, b1, b2
assert A is enum
assert A is HoleyEnum
assert A isnot OrdinalEnum
assert B isnot HoleyEnum
assert B is OrdinalEnum
assert int isnot HoleyEnum
type C[T] = enum h0 = 2, h1 = 4
assert C[float] is HoleyEnum

Types

HoleyEnum = (not Ordinal) and enum
Enum with holes.   Source   Edit
OrdinalEnum = Ordinal and enum
Enum without holes.   Source   Edit
StaticParam[value] = object
  
Used to wrap a static value in genericParams.   Source   Edit

Procs

proc arity(t: typedesc): int {.magic: "TypeTrait", ...raises: [], tags: [].}
Returns the arity of the given type. This is the number of "type" components or the number of generic parameters a given type t has.

Example:

doAssert arity(int) == 0
doAssert arity(seq[string]) == 1
doAssert arity(array[3, int]) == 2
doAssert arity((int, int, float, string)) == 4
  Source   Edit
proc distinctBase(T: typedesc; recursive: static bool = true): typedesc {.
    magic: "TypeTrait", ...raises: [], tags: [].}

Returns the base type for distinct types, or the type itself otherwise. If recursive is false, only the immediate distinct base will be returned.

See also:

Example:

type MyInt = distinct int
type MyOtherInt = distinct MyInt
doAssert distinctBase(MyInt) is int
doAssert distinctBase(MyOtherInt) is int
doAssert distinctBase(MyOtherInt, false) is MyInt
doAssert distinctBase(int) is int
  Source   Edit
proc genericHead(t: typedesc): typedesc {.magic: "TypeTrait", ...raises: [],
    tags: [].}

Accepts an instantiated generic type and returns its uninstantiated form. A compile-time error will be produced if the supplied type is not generic.

See also:

Example:

type
  Foo[T] = object
  FooInst = Foo[int]
  Foo2 = genericHead(FooInst)

doAssert Foo2 is Foo and Foo is Foo2
doAssert genericHead(Foo[seq[string]]) is Foo
doAssert not compiles(genericHead(int))

type Generic = concept f
  type _ = genericHead(typeof(f))

proc bar(a: Generic): typeof(a) = a

doAssert bar(Foo[string].default) == Foo[string]()
doAssert not compiles bar(string.default)

when false: # these don't work yet
  doAssert genericHead(Foo[int])[float] is Foo[float]
  doAssert seq[int].genericHead is seq
  Source   Edit
proc hasClosure(fn: NimNode): bool {....raises: [], tags: [].}
Return true if the func/proc/etc fn has closure. fn has to be a resolved symbol of kind nnkSym. This implies that the macro that calls this proc should accept typed arguments and not untyped arguments.   Source   Edit
proc isCyclical(t: typedesc): bool {.magic: "TypeTrait", ...raises: [], tags: [].}
Returns whether the type t is potentially able to be part of a reference cycle when used as the type of a managed heap location.

Example:

type
  NoCycle = object
    x: seq[NoCycle]
  NoCycle2 {.acyclic.} = ref object
    x: NoCycle2
  Cycle = ref object
    x: Cycle

doAssert not isCyclical(NoCycle)
doAssert not isCyclical(NoCycle2)
doAssert isCyclical(Cycle)
  Source   Edit
proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait", ...raises: [], tags: [].}
Returns true for named tuples, false for any other type.

Example:

doAssert not isNamedTuple(int)
doAssert not isNamedTuple((string, int))
doAssert isNamedTuple(tuple[name: string, age: int])
  Source   Edit
proc name(t: typedesc): string {.magic: "TypeTrait", ...raises: [], tags: [].}

Returns the name of the given type.

Alias for system.`$`(t) since Nim v0.20.

Example:

doAssert name(int) == "int"
doAssert name(seq[string]) == "seq[string]"
  Source   Edit
proc rangeBase(t: typedesc): typedesc {.magic: "TypeTrait", ...raises: [], tags: [].}
Returns the base type of the range type t. Only a single level is skipped, that is, if the range type's base type is also a range type, the base type is not skipped.

Example:

type
  Range = range[1..3]
  Nested = range[Range(1)..Range(3)]

doAssert rangeBase(Range) is int
doAssert rangeBase(Range) isnot range
doAssert rangeBase(Nested) is Range
  Source   Edit
proc stripGenericParams(t: typedesc): typedesc {.magic: "TypeTrait", ...raises: [],
    tags: [].}
This trait is similar to genericHead, but instead of producing an error for non-generic types, it will just return them unmodified.

Example:

type Foo[T] = object

doAssert stripGenericParams(Foo[string]) is Foo
doAssert stripGenericParams(int) is int
  Source   Edit
proc supportsCopyMem(t: typedesc): bool {.magic: "TypeTrait", ...raises: [],
    tags: [].}

This trait returns true if the type t is safe to use for copyMem.

Other languages name a type like these blob.

  Source   Edit
proc supportsZeroMem(t: typedesc): bool {.magic: "TypeTrait", ...raises: [],
    tags: [].}
This trait returns true if using zeroMem on a location of type t brings the location into its "default-initialized" state. This doesn't imply that using zeroMem on a location already storing a value is valid.   Source   Edit
proc tupleLen(T: typedesc[tuple]): int {.magic: "TypeTrait", ...raises: [],
    tags: [].}

Returns the number of elements of the tuple type T.

See also:

Example:

doAssert tupleLen((int, int, float, string)) == 4
doAssert tupleLen(tuple[name: string, age: int]) == 2
  Source   Edit

Macros

macro enumLen(T: typedesc[enum]): int
Returns the number of items in the enum T.

Example:

type Foo = enum
  fooItem1
  fooItem2

doAssert Foo.enumLen == 2
  Source   Edit
macro genericParams(T: typedesc): untyped

Returns the tuple of generic parameters for the generic type T.

Note: For the builtin array type, the index generic parameter will always become a range type.

Example:

type Foo[T1, T2] = object

doAssert genericParams(Foo[float, string]) is (float, string)

type Bar[N: static float, T] = object

doAssert genericParams(Bar[1.0, string]) is (StaticParam[1.0], string)
doAssert genericParams(Bar[1.0, string]).get(0).value == 1.0
doAssert genericParams(seq[Bar[2.0, string]]).get(0) is Bar[2.0, string]
var s: seq[Bar[3.0, string]]
doAssert genericParams(typeof(s)) is (Bar[3.0, string],)

doAssert genericParams(array[10, int]) is (range[0..9], int)
var a: array[10, int]
doAssert genericParams(typeof(a)) is (range[0..9], int)
  Source   Edit

Templates

template distinctBase[T](a: T; recursive: static bool = true): untyped
Overload of distinctBase for values.

Example:

type MyInt = distinct int
type MyOtherInt = distinct MyInt
doAssert 12.MyInt.distinctBase == 12
doAssert 12.MyOtherInt.distinctBase == 12
doAssert 12.MyOtherInt.distinctBase(false) is MyInt
doAssert 12.distinctBase == 12
  Source   Edit
template elementType(a: untyped): typedesc
Returns the element type of a, which can be any iterable (over which you can iterate).

Example:

iterator myiter(n: int): auto =
  for i in 0 ..< n:
    yield i

doAssert elementType(@[1,2]) is int
doAssert elementType("asdf") is char
doAssert elementType(myiter(3)) is int
  Source   Edit
template get(T: typedesc[tuple]; i: static int): untyped
Returns the i-th element of T.

Example:

doAssert get((int, int, float, string), 2) is float
  Source   Edit
template pointerBase[T](_: typedesc[ptr T | ref T]): typedesc
Returns T for ref T | ptr T.

Example:

assert (ref int).pointerBase is int
type A = ptr seq[float]
assert A.pointerBase is seq[float]
assert (ref A).pointerBase is A # not seq[float]
assert (var s = "abc"; s[0].addr).typeof.pointerBase is char
  Source   Edit
template tupleLen(t: tuple): int

Returns the number of elements of the tuple t.

See also:

Example:

doAssert tupleLen((1, 2)) == 2
  Source   Edit

Exports

$, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $