That gets a little messy.  What I started with was:

message A {
  optional int32 field_a = 1;
}

message B {
  optional int32 field_b = 1;
  optional A sub_a = 2;
}

Right off the bat that has a couple artifacts that I don't like.  B is
really a subclass of A, but to refer to A's members I have to prefix
them with B's name for the field (e.g. message.sub_a.field_a).  But
let's keep going with the example.  I'm taking this message and adding
some extra data to both A and B.

message APrime1 {
  optional A original_a = 1;
  optional int32 field_a2 = 2;
}

message BPrime1 {
  optional B original_b = 1;
  optional int32 field_b2 = 2;
}

This doesn't really work, because there's no reference to APrime1.  So
I could do this:

message APrime2 {
  optional A original_a = 1;
  optional int32 field_a2 = 2;
}

message BPrime2 {
  optional B original_b = 1;
  optional APrime2 new_a = 2;
  optional int32 field_b2 = 3;
}

But this is a different kind of bad, because A is referenced twice
(message.new_a.original_a and message.original_b.sub_a).  So maybe
instead I do this:

message APrime3 {
  optional int32 field_a2 = 1;
}

message BPrime3 {
  optional B original_b = 1;
  optional APrime3 new_a = 2;
  optional int32 field_b2 = 3;
}

This is the most viable yet.  There's no duplication, but again it's
hardly ideal.  A and APrime3 are separated pretty widely.  So now I
could use extensions...

extend A {
  optional int32 field_a2 = 2;
}

extend B {
  optional int32 field_b2 = 3;
}

But now in Java I'm using the getExtension and setExtension methods,
which really doesn't feel clean to me.  So instead what I'm probably
going to end up doing is...

message APrime4 {
  optional int32 field_a = 1;
  optional int32 field_a2 = 100;
}

message BPrime4 {
  optional APrime2 new_a = 1;
  optional int32 field_b2 = 100;
}

Now APrime4 is essentially overlaid on A and BPrime4 is overlaid on B,
and if I understood the wire format correctly, I should be able to
write a B and read a BPrime4 and be done with it.  I'd have preferred
to do something like this...

message A {
  optional int32 field_a = 1;
}

message B {
  optional int32 field_a = 1;
  optional int32 field_b = 101;
}

message BPrime5 {
  optional int32 field_a = 1;
  optional int32 field_a2 = 51;
  optional int32 field_b = 101;
  optional int32 field_b2 = 151;
}

I can write an A, read it back as a B, write that as a B and read it
back as a BPrime5.  But if I add a field to A, I've got to add it to
every B and BPrime5 class (and I have a number of these).  Too much
copy/paste and room for error.  At least in the earlier example I'd
only have to add it to A and APrime4 (or B and BPrime4).  This also
means that I don't have to write a clone constructor which builds a
BPrime5 based on a B.


As for the WontFix explanation, I can see two possible answers.

The first answer would be "yeah it breaks.  Just like it breaks if you
need to bump an extension section range up because you ran out of
slots."  It's easy to work around this limitation assuming that it's
known in advance by using conventions.  And using those conventions is
easier than a myriad of copy/paste code.

The second answer would be "so reserve spots".  You already do a
reverse reservation with the extend functionality.  When you say
"extensions 100 to 199;" you're effectively saying "reserve 1 to 99;
reserve 200 to max;".  So give us a "reserve" keyword (make
"extensions" internally resolve to the converse "reserve"), and if any
inherited classes have conflicting reservations, throw a compile
error.

Here's some examples:

message A {
  reserve 1 to 99;
  optional int32 field_a = 1;
}

message B : A {
  reserve 1 to 199;  // This reservation is fine, even though it
overlaps A because B is derived from A
  optional int32 field_b = 101;
}

message C {
  reserve 100 to 299;
  optional int32 field_c = 101
}

message D : B, C {
  // This message fails because it uses B (reserving 1 to 199) and C
(reserving 100 to 299) with overlapping reservations
}

message E : B {
  optional int32 field_e = 102; // This message fails because 102 was
reserved by B
}

message F : A, C {
  // This message is perfectly fine because A and C do not have
overlapping reservations (and coincidentally doesn't need any extra
members)
}




On Jul 12, 3:23 pm, Marc Gravell <marc.grav...@gmail.com> wrote:
> Now add a field for A (which is legitimate) and it all falls apart.
>
> Possibly a *viable* representation might be:
>
> message C {
>     optional A field_a = 1;
>     optional B field_b = 2;
>     optional int32 field_c = 3;
>
> }
>
> and that is something that *can* be understood today, by all
> implementations, and involves no copy/paste error, while retaining the
> ability to add fields to all the message types.
>
> Just a thought...
>
> Marc
>
> On 12 July 2010 23:10, <proto...@googlecode.com> wrote:
>
> > message A {
> >  optional int32 field_a = 1;
> > }
>
> > message B {
> >  optional int32 field_b = 2;
> > }
>
> > message C {
> >  optional int32 field_a = 1;
> >  optional int32 field_b = 2;
> >  optional int32 field_c = 3;
> > }
>
> --
> Regards,
>
> Marc

-- 
You received this message because you are subscribed to the Google Groups 
"Protocol Buffers" group.
To post to this group, send email to proto...@googlegroups.com.
To unsubscribe from this group, send email to 
protobuf+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/protobuf?hl=en.

Reply via email to