Skip to content

Commit

Permalink
add detailed use case examples
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour committed Apr 21, 2021
1 parent ce7b7a4 commit 7263616
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 5 deletions.
17 changes: 13 additions & 4 deletions lib/pure/typetraits.nim
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,26 @@ type
TypeId* = distinct string ## opaque, used by `getTypeId`

proc `==`*(x, y: TypeId): bool {.borrow.}
proc `$`*(x: TypeId): string {.borrow.}

proc getTypeIdImpl(t: typedesc): string {.magic: "TypeTrait", since: (1, 1).}

proc getTypeId*(t: typedesc): TypeId {.since: (1, 1).} =
## Returns a unique id representing a type; the id is stable across
## recompilations of the same program, but may differ if the program source
## changes. In particular serializing it will be meaningless after source
## change + recompilation: ids are reused in an un-specified manner.
## changes. In particular serializing it will be meaningless after source change
## and recompilation: ids are reused in an un-specified manner.
##
## Example use cases: using ids as keys in Tables (eg for Type hashing), for Comparisons? Store into sets to prevent recursions during type traversal?
## Example use case: passing a callback
## Example use cases that are impossible / hard without such feature:
## 1: using ids as keys in Tables (eg for Type hashing) or to prevent recursions during type traversal
## 2: passing a callback proc that can handle multiple types to a routine
## 3: defining an exportc proc that can handle multiple types, this can be used
## as workaround for lack of cyclic imports
##
## See examples for those use cases in ttypetraits.nim; in each case the
## callback is called via:
## `callbackFun(cast[pointer](a), getTypeId(type(a)), ...)`

runnableExamples:
type Foo[T] = object
type Foo2 = Foo
Expand Down
14 changes: 14 additions & 0 deletions tests/metatype/mtypetraits_impl.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{.used.}

import std/typetraits
import mtypetraits_types
import ttypetraits

proc callbackFun(a: pointer, id: TypeId): string {.exportc.} =
case id
of getTypeid(Foo1): $("custom1", cast[Foo1](a))
of getTypeid(Foo2): $("custom2", cast[Foo2](a))
of getTypeid(Foo3): $("custom3", cast[Foo3](a))
else:
doAssert false, $id
""
10 changes: 10 additions & 0 deletions tests/metatype/mtypetraits_types.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type Foo1* = object
x1*: int

type Foo2* = object
x2*: int

import std/typetraits
proc callbackFun(a: pointer, id: TypeId): string {.importc.}

proc callbackFun*[T](a: T): string = callbackFun(cast[pointer](a), getTypeid(T))
22 changes: 21 additions & 1 deletion tests/metatype/ttypetraits.nim
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ block: # getTypeId

doAssert int.getTypeId is TypeId

block: # example use case for `getTypeId`:
block: # example use case for `getTypeId`: passing a callback that handles multiple types
## this would be in a library, say prettys.nim:
type Callback = proc(result: var string, a: pointer, id: TypeId): bool

Expand Down Expand Up @@ -433,3 +433,23 @@ block: # example use case for `getTypeId`:
doAssert pretty(f, callback2) == """(b1: ("custom2:", 12), b2: abc, )"""

main()

type Foo3* = object
x3*: int

import ./mtypetraits_types

block:
# example use case for `getTypeId`: exportc proc that handles multiple types.
# This can be used in cases where we want to define implementation for a
# proc in a separate module (here, mtypetraits_impl), to avoid cyclic import
# issues or avoid dragging many dependencies for users of the proc, which can
# be declared in another import module (here, mtypetraits_types).
# This mimicks the use of headers vs source files in C.

doAssert callbackFun(Foo1(x1: 1)) == """("custom1", (x1: 1))"""
doAssert callbackFun(Foo2(x2: 2)) == """("custom2", (x2: 2))"""
doAssert callbackFun(Foo3(x3: 3)) == """("custom3", (x3: 3))"""

import ./mtypetraits_impl
# this could be imported from any module; it defines our exportc proc

0 comments on commit 7263616

Please sign in to comment.