I agree strongly with returning a struct as a best practice. Returning a single base type is too constraining and hinders interface evolution.
I also agree that it is often a good design to pass structs as params. In particular, modeling key parts of your interface as message types in Apache Thrift IDL makes it easy to use those messages over RPC as well as messaging systems (RabbitMQ, Apache Apollo, ZeroMQ, etc.) and in streaming scenarios using UDP multicast and other protocols directly. Many overlook the fact that Apache Thrift is a standalone serialization tool, RPC being an optional feature. I have also found Apache Thrift interfaces to be fairly easy to evolve with base type Args lists. There is an elegance to calling a function with direct parameters that works nicely in some settings. If you want a functional interface, this is a pretty natural way to go. While I am not promoting it, I would not deprecate it either. A server compiled with func (1: i32 x) will happily accept calls from a client compiled for func(1: i32 x, 2: i32 y). Unknown arguments (y in this case) are ignored by servers. This also works the other way around. If a client calls a server with func(1: i32 x) and the server was built with func(1: i32 x, 2: i32 y) the server will receive an uninitialized y. This is ok in dynamically typed languages where the argument can be tested for a value of “None” or some such. A better solution would be to give the new parameter a default value, e.g. func(1: i32 x, 2: i32 y=2). This would cause the server to receive a y of 2 when the client calls with the old interface. The server could also be defined with the interface func(2: i32 y=2), ignoring x altogether. Apache Thrift Args lists are pretty flexible really. Args lists are implemented as struts. So if you pack all of your params in a struct param, Apache Thrift is going to put that into an Args list struct anyway. A little redundant. There is no technical reason for Args lists not to support all struct features. However, today, the parser does not allow “optional” requiredness function arguments. Optional struct members certainly have their place, but I often find folks using optional for things “default” requiredness does better. Default requiredness is simple (no optional is_set/unset overhead), consistently implemented across languages (sadly, it is hard to say that about optional at this point) and quite elegant in its support for interface evolution. Using args lists lets applications use functions like functions, leaving Apache Thrift to handle the RPC and interface evolution details. A nice division of labor. So whether you like to pass struct params or a mix of base types and structs, I consider it a matter of preference and use case more than general best practice. On Thu, Feb 12, 2015 at 1:17 AM, Denis Samoilov <[email protected]> wrote: > Jens, Edward, thank you very much! > > On February 12, 2015 at 12:09:20 AM, Jens Geyer ([email protected]) > wrote: > > We also made good experiences with that approach. I just want to add that > we do the same with retvals - we always return a struct (or void) which has > several advantages: > - you can add more data at any time > - possibility to retire old elements > - ability to return a null value for a member is legal, returning null as > function result is not > > Have fun, > JensG > ________________________________ > Von: Edward Capriolo > Gesendet: 12.02.2015 04:49 > An: [email protected] > Betreff: Re: best practices for methods - to wrap arguments into struct or > not? > > Yes, I believe so. Thrift does not support overloaded methods and thus it > makes the methods in a service hard to evolve. I prefer to send a a single > struct with all/mostly optional arguments. This way if service methods get > new parameters the change does not cause a ripple of API breaking changes > on the client. Otherwise you end up doing something like: > > v1 > int method(int x); > > v2 > int method(int x); > int method_v2(int x, int y); > > > I think this cleaner in the long run: > > > v1 > int method( methodStruct); > > v2 > int method( methodStruct); > > This is because structs have optional members but functions do no. even > though they are marked optional no language supports them even languages > that theoretically could support optional arguments like python. > > > On Wed, Feb 11, 2015 at 10:22 PM, Denis Samoilov <[email protected]> > wrote: > > > hello Thrift Community! > > > > Is there best practice to wrap function params into struct? like: > > struct InfoRequest { > > 1: required bool getActive > > 2: required i32 logLimit > > } > > ClientsInfoList getExtendedClientsInfo(1: InfoRequest params) > > vs > > ClientsInfoList getExtendedClientsInfo(1: bool getActive, 2: i32 > logLimit) > > > > > > > > because this way i can add more optional (with default values) params in > > future without breaking backward compatibility, like > > struct InfoRequest { > > 1: required bool getActive > > 2: required i32 logLimit > > 3: optional i32 newParam > > } > > > > Thank you! > > >
