On Apr 5, 2012, at 8:00 AM, Piscium wrote:

> On 5 April 2012 15:05, Rush Manbert <[email protected]> wrote:
> 
>> Hi Piscium,
>> 
>> I'm using an older version of Thrift, but my code is all C++.
>> 
>> Try it with your Thrift IDL written like this and I think you'll see what I 
>> meant:
>> 
>>> ================
>>> namespace cpp test
>>> 
>>> struct Test {
>>>  1: optional i32 npotatoes, // optional field because it has the optional 
>>> keyword
>>  2:           i32 nonions,  // required field (but will be sent regardless 
>> of the __isset state)
>>> }
> 
> Thanks, Rush. You are right, an optional field is sent only if __isset is set.
> 
> But there is more. I realise now that there are actually three types
> of fields: optional, required and "half-way" (when not explicitly
> marked as either optional or required). "half-way" fields are a bit
> like half-pregnant, somewhere in-between optional and required!
> 
> A "half-way" field is like a required field in that it is always sent
> on transmission, and it is like an optional field in that it does not
> cause an exception if not present on reception.
> 
> For obvious reasons a "half-way" field is not symmetrical. Moreover a
> required field is not symmetrical either, because there is no
> exception on transmission if it is not set. The apparent conclusion is
> that the only type of field that is symmetrical is the optional.
> 
> Still I wonder why it was designed this way. If I compare Thrift
> generated files with those created by Protobuf, it becomes immediately
> obvious how much smaller is the Thrift generated code. Maybe that is
> the reason why it was named "Thrift", because it is parsimonious! So
> maybe it was designed this way to keep the generated code to the bare
> minimum (for example, by not causing an exception on transmission if
> the field is not set, as that would require one check of variable
> every write).
> 
> Below is the modified Thrift file and generated code.
> 
> =========================
> 
> namespace cpp test
> 
> struct CountrySoup {
>  1: optional i32 npotatoes,
>  2: i32 nonions, // "half-way" field - neither required nor optional
>  3: required i32 cabbages,
> }
> 
> ==================
> 
<snip>

It certainly is very permissive on the client side as far as caring whether you 
really populate a required or "half-way" field, and I would suspect that 
minimal generated code is part of the reason. Facebook uses this internally, 
and they are very concerned with performance.

Also, I think this helps with mutation of the struct definitions over time. If 
I have a server deployed that knows about your CountrySoup definition above, 
but I talk to it from a client that has this definition:

struct CountrySoup {
 1: optional i32 npotatoes,
// nonions has been removed
 3: required i32 cabbages,
 4: i32 cupsOfWater,
}

then the server read routine will never see the Thrift ID value 2 when it 
receives a CountrySoup message, so in his CountrySoup struct, the 
__isset.nonions will be false, and since he doesn't have a case for ID value 4, 
he just ignores the cupsOfWater field. This way clients and servers of 
different versions can communicate, whether the combination really works or 
not. It's up to the server implementation to plan for this case and decide what 
to do if CountrySoup.__isset.nonions is false.

Best regards,
Rush

Reply via email to