Reputation: 26710
Consider a type hierarchy, where the base object is non-generic, but sub-types are:
type
TestBase = ref object of RootObj
DerivedA = ref object of TestBase
DerivedB[T] = ref object of TestBase
field: T
proc testProc(x: TestBase) =
if x of DerivedB: # <= what to do here
echo "it's a B!"
else:
echo "not a B"
Using the of
operator like this won't compile, because it expects object types. What does work is e.g. to match for specific types like DerivedB[int]
, or making the proc itself generic in T
, which is meaningless when passing in a DerivedA
.
Is there a way to solve this problem generically without resorting to methods and dynamic dispatch?
Upvotes: 3
Views: 522
Reputation: 5384
The easiest solution here is to introduce a dummy base type for all of the generic derived types, with the only purpose of assisting in such checks. Here is an example:
type
TestBase = ref object of RootObj
DerivedA = ref object of TestBase
# I'm using illustrative names here
# You can choose something more sensible
DerivedDetector = ref object of TestBase
DerivedB[T] = ref object of DerivedDetector
field: T
proc testProc(x: TestBase) =
if x of DerivedDetector: # This will be true for all derived types
echo "it's a B!"
else:
echo "not a B"
testProc DerivedB[int](field: 10)
testProc DerivedA()
This solution won't increase the size of the objects and it doesn't introduce any run-time overhead in typical code.
If you can't modify the inheritance hierarchy (it may be part of a third-party library), there is a much more complicated solution based on the getTypeInfo
proc from the system module. This proc returns an opaque pointer that can be used as an identifier for the type. You'll have to register all derived types with their identifiers in a hash table (you can do this at the start of the program) and then use that to make run-time checks against the type-info pointers of the input values in the proc.
Upvotes: 5