Type System in Depth

13.1 Type Aliases vs distinct

distinct gives zero-cost type safety (units, IDs, sanitized strings).

type
  UserId = int               # alias: interchangeable with int
  Meters = distinct float    # new type: NOT interchangeable
  Feet = distinct float

proc `+`(a, b: Meters): Meters {.borrow.}       # borrow ops from the base type
proc `$`(m: Meters): string {.borrow.}
let d = Meters(5.0) + Meters(2.5)
# let bad = Meters(1.0) + Feet(2.0)   # compile error: type safety
echo d, " ", float(d)

13.2 Converters (Implicit Conversions)

converter toBool(x: int): bool = x != 0
if 1: echo "truthy"      # uses the converter (use sparingly!)

13.3 Type Classes and typedesc

proc describe(x: SomeNumber) = echo "number: ", x        # SomeInteger, SomeFloat, SomeOrdinal...
proc zeroOf(T: typedesc): T = default(T)
echo zeroOf(int), zeroOf(string).len
proc show[T: int | string](x: T) = echo x                 # union type class

13.4 auto and typeof

proc identity(x: auto): auto = x
var v: typeof(identity(5))

13.5 Static Parameters

proc repeatN(s: string, n: static int): string =
  when n > 3: {.warning: "large repeat".}
  result = s.repeat(n)
type Matrix[R, C: static int] = array[R, array[C, float]]

13.6 Subtyping and of

Object inheritance (Module 17): of RootObj, runtime checks with of, conversion Derived(base).

13.7 Type Introspection

import std/typetraits
echo name(int), " ", int is SomeInteger, " ", supportsCopyMem(seq[int]), " ", genericParams(seq[int])
echo default(Point), " ", typeof(1 + 2.0)   # error: no mixed arithmetic without conversion