tvtable.nim 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. discard """
  2. output: '''
  3. OBJ 1 foo
  4. 10
  5. OBJ 1 bar
  6. OBJ 2 foo
  7. 5
  8. OBJ 2 bar
  9. '''
  10. """
  11. type
  12. # these are the signatures of the virtual procs for each type
  13. fooProc[T] = proc (o: var T): int {.nimcall.}
  14. barProc[T] = proc (o: var T) {.nimcall.}
  15. # an untyped table to store the proc pointers
  16. # it's also possible to use a strongly typed tuple here
  17. VTable = array[0..1, pointer]
  18. TBase {.inheritable.} = object
  19. vtbl: ptr VTable
  20. TUserObject1 = object of TBase
  21. x: int
  22. TUserObject2 = object of TBase
  23. y: int
  24. proc foo(o: var TUserObject1): int =
  25. echo "OBJ 1 foo"
  26. return 10
  27. proc bar(o: var TUserObject1) =
  28. echo "OBJ 1 bar"
  29. proc foo(o: var TUserObject2): int =
  30. echo "OBJ 2 foo"
  31. return 5
  32. proc bar(o: var TUserObject2) =
  33. echo "OBJ 2 bar"
  34. proc getVTable(T: typedesc): ptr VTable =
  35. # pay attention to what's going on here
  36. # this will initialize the vtable for each type at program start-up
  37. #
  38. # fooProc[T](foo) is a type coercion - it looks for a proc named foo
  39. # matching the signature fooProc[T] (e.g. proc (o: var TUserObject1): int)
  40. var vtbl {.global.} = [
  41. cast[pointer](fooProc[T](foo)),
  42. cast[pointer](barProc[T](bar))
  43. ]
  44. return vtbl.addr
  45. proc create(T: typedesc): T =
  46. result.vtbl = getVTable(T)
  47. proc baseFoo(o: var TBase): int =
  48. return cast[fooProc[TBase]](o.vtbl[0])(o)
  49. proc baseBar(o: var TBase) =
  50. cast[barProc[TBase]](o.vtbl[1])(o)
  51. var a = TUserObject1.create
  52. var b = TUserObject2.create
  53. echo a.baseFoo
  54. a.baseBar
  55. echo b.baseFoo
  56. b.baseBar