Modeling a widget tree?

34 views
Skip to first unread message

trave...@gmail.com

unread,
May 11, 2019, 12:44:23 PM5/11/19
to Cap'n Proto
I'm new to statically typed languages in general, I'm doing this as a learning experience.

I'm building a toy UI toolkit, and I want to create a tree of widgets. Something like

interface Node {
    children
@0 () -> (list :List(Node));
}

interface TextNode extends(Node) {
   
//some textNode specific stuff
}

My problem is that I want a node to be able to contain anything that implements the node interfaces, even if it's a textNode, or an SVGNode, or whatever. Is there a way to do that without resorting to using AnyPointer or registering all my sub nodes in advance? Some provision for doing structural typing?

Kenton Varda

unread,
May 11, 2019, 1:09:11 PM5/11/19
to Alex Davies, Cap'n Proto
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

--
You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+...@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.
To view this discussion on the web visit https://groups.google.com/d/msgid/capnproto/04478ec6-c647-4d3f-a981-dc1bc6da6cae%40googlegroups.com.

trave...@gmail.com

unread,
May 11, 2019, 1:29:09 PM5/11/19
to Cap'n Proto
Thanks, I'm using rust. That should be enough to keep me going for a while.
To unsubscribe from this group and stop receiving emails from it, send an email to capn...@googlegroups.com.

trave...@gmail.com

unread,
May 26, 2019, 11:58:42 AM5/26/19
to Cap'n Proto
So I had a chance to set down with this again, and I can not for the life of me figure out how to get the typeId of a capability using the rust generator. Since I'm new to the language I presume I'm just doing something fundamentally wrong. Can you provide any guidance?


On Saturday, May 11, 2019 at 2:09:11 PM UTC-3, Kenton Varda wrote:
To unsubscribe from this group and stop receiving emails from it, send an email to capn...@googlegroups.com.

Kenton Varda

unread,
May 26, 2019, 1:56:55 PM5/26/19
to Alex Davies, David Renshaw, Cap'n Proto
+David Renshaw who wrote the Rust implementation, maybe he can answer?

To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+...@googlegroups.com.

David Renshaw

unread,
May 27, 2019, 1:12:26 PM5/27/19
to Kenton Varda, Alex Davies, Cap'n Proto
An implementation of the `HasTypeId` trait will be generated for `text_node::Client`.  https://github.com/capnproto/capnproto-rust/blob/eddcc1ea8599be0ae62209509ae48e1e99ee00d8/capnp/src/traits.rs#L103-L105

You should be able to get the type ID by doing `<text:node::Client as HasTypeID>::type_id()`.
Reply all
Reply to author
Forward
0 new messages