Procedures utilizing type classes in such manner are considered to be implicitly generic. They will be instantiated once for each unique combination of param types used within the program.

    By default, during overload resolution each named type class will bind to exactly one concrete type. We call such type classes bind once types. Here is an example taken directly from the system module to illustrate this:

    1. ## requires `x` and `y` to be of the same tuple type
    2. ## generic ``==`` operator for tuples that is lifted from the components
    3. ## of `x` and `y`.
    4. result = true
    5. for a, b in fields(x, y):
    6. if a != b: result = false

    Procs written with the implicitly generic style will often need to refer to the type parameters of the matched generic type. They can be easily accessed using the dot syntax:

    1. type Matrix[T, Rows, Columns] = object
    2. ...
    3. proc `[]`(m: Matrix, row, col: int): Matrix.T =

    Here are more examples that illustrate implicit generics:

    1. proc p(a: Table, b: Table)
    2. # is roughly the same as:
    3. proc p[Key, Value](a, b: Table[Key, Value])
    1. proc p(a: Table, b: distinct Table)
    2. # is roughly the same as:
    3. proc p[Key, Value, KeyB, ValueB](a: Table[Key, Value], b: Table[KeyB, ValueB])

    typedesc is a “bind many” type class:

    1. # is roughly the same as:
    2. proc p[T, T2](a: typedesc[T], b: typedesc[T2])

    A parameter of type typedesc is itself usable as a type. If it is used as a type, it’s the underlying type. (In other words, one level of “typedesc”-ness is stripped off:

    1. proc p(a: typedesc; b: a) = discard
    2. # is roughly the same as:
    3. proc p[T](a: typedesc[T]; b: T) = discard
    4. # hence this is a valid call:
    5. # as parameter 'a' requires a type, but 'b' requires a value.