Hi Allen, there are three kinds of requiredness with Thrift:
a) required The field must be written and the reader must be able to read it. If it is not properly set on write or if the reader does not find it in the data, some language implementations (not all) throw an exception. b) optional The field can be written, but may be as well missing form the data stream. Usually the implementations check on write whether the field is null or if the matching "isset" flag is set. What method is used is mostly an implememntation detail of the particular language. For convenience, some implementations use property setters to set the "isset" flag along with the value. c) default This is the default (hence the name) that is applied when neither required nor optional are specified. These fields are intended to be written always to the output stream. But, on the other hand, if the foo member in the Bar struct below is null, foo will in many (all?) cases not be written at all: struct Foo { ... } struct Bar { 1: Foo foo } > With the OPT_IN_REQ_OUT behavior it seems I have to serialize an empty > string over the wire. As a result, when the echo server responds, I > actually get: > > Foo { thing: Some("") } > > This seems very puzzling, because > the receiver can't tell the difference between sender-unset values and > values with the standard default. That may just be right from the formal definition, but there's a "but". I think the main confusion stems from the fact, that None is not a real value, but the attempt of getting out of the language what would be null values otherwise. The formally correct way would be to enforce a set field on write or throw otherwise, just like with "required". If we do a short facts check against the current code base, we find this behaviour for unset foo members: - C++ writes an empty foo - Python does not write unset foo - NodeJS does not write unset foo - Java does not write unset foo - Delphi does not write unset foo - C_glib expects foo to be set and writes it - C# does not write unset foo So a lot of implementations treat "default" very similar to "optional", but some don't and follow the formal definition to always write some data. It works though, because on read the field is mandatory and the implementation provides some default for it, which in a lot of cases will again be "null". From my perspective, I would recommend to do the thing that makes most sense w/regard to the Rust language environment, the option that provides the least surprise. Have fun, JensG -----Ursprüngliche Nachricht----- From: Allen George Sent: Sunday, November 20, 2016 4:55 AM To: dev@thrift.apache.org Subject: Question about OPT_IN_REQ_OUT fields Hi, I've made a lot of progress on the Rust thrift generation front and I've been able to get the C++ server and Rust client communicating for some types. One thing really puzzles me however: T_OPT_IN_REQ_OUT fields. Looking at the docs and other code generators it looks like those fields are written out no matter what. Does that mean that I'm writing a default value (empty string, empty collections, 0 for numeric types) when they're not set? This seems very puzzling, because the receiver can't tell the difference between sender-unset values and values with the standard default. It's unfortunate from my point of view because a Rust client communicating with an echo server receives a result that doesn't match what it sent out! An example: struct Foo { 1: string thing; } Rust representation: struct Foo { thing: Option<String>, } If I don't set "thing" I have the following value to send: let sent = Foo { thing: None } With the OPT_IN_REQ_OUT behavior it seems I have to serialize an empty string over the wire. As a result, when the echo server responds, I actually get: Foo { thing: Some("") } This means that my simple "check that the response is exactly what I sent out" doesn't quite work and I'll have to modify it for those cases where I have unset fields. At any rate - just wanted to check that my understanding of OPT_IN_REQ_OUT was right. Thanks, Allen Terminal Musings: http://www.allengeorge.com/ Raft in Java: https://github.com/allengeorge/libraft/ Twitter: https://twitter.com/allenageorge/