Hi Alex,
(You didn't say which language you're using so I'll assume C++, but roughly the same should apply in other languages.)
You don't need AnyPointer here. Cap'n Proto supports upcasting and downcasting capabilities, as any inheritance heirarchy should. E.g. a TextNode::Client can implicitly cast to Node::Client. Downcasting is explicit: if you have a `Node::Client`, you can call `cilent.castAs<TextNode>()` to get a `TextNode::Client`.
However, `castAs` doesn't actually verify the remote type. If you then call a `TextNode`-specific method, and the remote object doesn't actually implement `TextNode`, then you'll get an "unimplemented" exception back.
So, you probably want some way to determine the type without calling methods to find out if they throw. How to do that is really up to you. One option would be to have a big enum. Another would be to use type ID's -- e.g. you can do `capnp::typeId<TextNode>()` to get the `uint64_t` type ID for TextNode. (Note `typeId<T>()` is a constant expression -- you can use it in in a switch case.)
So you can have a method like:
getType @0 () -> (id :UInt64);
Things get more complicated, of course, if you have a multi-level hierarchy, e.g. Node -> Button -> RadioButton. Now you need to send around a list of types.
getTypes @0 () -> (ids :List(UInt64));
To avoid incurring a round trip to get the type, you might try to pass the type (or list of types) along with the capabilities, like:
interface Node {
children @0 () -> (list :List(TypedNode));
}
struct TypedNode {
node @0 :Node;
type @1 :UInt64;
}
Cap'n Proto does not have any built-in way of communicating the type because in the vast majority of use cases, it either isn't needed at all, or there is a use-case-specific solution that is cheaper/better than the general solution.
-Kenton