Dear Thrift Users, I have an issue with Thrift-generated C++ interfaces.
Imagine we have a function, Fun(CLS), which we wish to call over Thrift RPC. The CLS object has just one field, "fld". If we generate a Thrift Python API and create a CLS object, we can do the following: instance = CLS() instance.fld = "something" Fun(instance) Result: Fun gets a CLS object with fld="something" or: instance = CLS() Fun(instance) Result: Fun gets a CLS object with fld=null. So we have two different invocations of Fun, and it can have behavior contingent on fld being null. Now, if we use the same IDL file to produce a C++ API layer, we can do the following: CLS instance = new CLS() instance.fld = "something" Fun(instance) ... and that's the same as the first Python example. But when we do this: CLS instance = new CLS() Fun(instance) ... Fun gets a CLS instance with fld="", the empty string! That's not the same as the expected null. In fact, so far as I can tell, it is impossible to cause Fun to receive a CLS instance with fld=null from C++. This means that, without explicitly modifying the Thrift-generated code, some APIs have different capabilities from one client language than they have from another. That seems counter to the goal of language independence, no? Investigating further, Thrift emits an __isset structure with a bool for each member of the class. However, the __set_fld method does not do __isset.fld = true, and the write method sends fld over the wire even when __isset.fld is false. I would strongly urge honoring the __isset flags on wire writes and using the setter methods instead of direct write property access for the C++ language. As things stand, some APIs cannot be used from a C++ client: there is no way to invoke them correctly with some parameters unspecified. Bryan Jacobs
