1

I cannot figure out how to instantiate an Option(T) type in pycapnp.

I have tried to instantiate a new message and then set the value of 'some', but it loses type information in doing so.

struct Option(T) {
  union {
    none @0 :Void;
    some @1 :T;
  }
}

struct Something {
  a @0 :Int16;
}
o = Option.new_message()
o.some = Something.new_message(a=5)
o.some.a // throws error

I would expect the option to become typed by virtue of the added struct, but it loses all type information and I cannot access the members of the object placed in the 'some' union value.

Dan Jenson
  • 961
  • 7
  • 20

2 Answers2

0

Cap'n Proto generics aren't really designed to work that way. They are designed for static type checking (with statically-typed languages in mind, i.e. not Python). An instance of a generic type cannot "become typed" after the fact -- the type must be known statically / at construction.

If a type parameter isn't specified, then it is assumed to be AnyPointer. I believe that means you need to access some like this:

o.some.as_struct(Something).a

I think that in Python there is no way to construct a generic type with type parameter specified at runtime. The only way you can really use generics is when the containing type specifies type parameters, like:

struct ContainingType {
  option @0 :Option(Something);
}

If you then construct a ContainingType and then access its option field, you'll get an Option object that knows that the type of some is Something, not AnyPointer.

Kenton Varda
  • 41,353
  • 8
  • 121
  • 105
0

I wanted to provide an example of how I got this working:

struct Request(PayloadType) {
  type @0 :Text;
  payload @1: PayloadType;
}
struct PingPayload {
  num @0 :Int64;
}

Creating the Payload

payload = self.capnp_models['ping_payload'].PingPayload.new_message()
payload.num = 999

req = self.capnp_models['request'].Request.new_message()
req.type = 'ping'
req.payload = payload

Reading the Payload

request = self.capnp_models['request'].Request.from_bytes(req)
payload = request.payload.as_struct(self.capnp_models['ping_payload'].PingPayload)
print(str(payload.num)) # Prints 999
ossys
  • 4,157
  • 5
  • 32
  • 35