[ https://issues.apache.org/jira/browse/THRIFT-2451?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13965771#comment-13965771 ]
Aleksey Pesternikov commented on THRIFT-2451: --------------------------------------------- >The test you wrote is a microbenchmark... i.e., of course it's faster. The big >question (IMO) is whether it would actually show up in the >profile of a real >production workload; of course I'm not demanding that you write such a test >(super painful to do, of course), but this is >not how thrift is used in the >wild: Production workloads are different. Thats why YMMV, disclamer etc etc are in the readme. All benchmarks in a world are more or less artificial. This one is a part of my real use case, when log records are processed by M/R-like workers and the structure is being created over and over again, just to be decoded from the stream, checked for some condition and mostly discarded. It is also a part of every thrift call, but impact is not that big of course. Also, IMHO non-pointers are much more intuitive and easy to use. As I already said, I would love to implement a (non-default) mapping mode when all optional fields use zero value as IsSet indicator. It is very natural for golang. And no, it is not broken as long as it is non-default and documented so people understand what they are doing. As a middle ground, I can return pointers for all optional fields as default mapping, and implement this one, as well as proposed as nondefault. For the record: I totally oppose hiding real struct fields behind getters/setters, since it makes code so clunky. [~jensg]? > Do not use pointers for optional fields with defaults. Do not write such > fields if its value set to default. Also, do not use pointers for any > optional fields mapped to go map or slice. generate Get accessors > ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- > > Key: THRIFT-2451 > URL: https://issues.apache.org/jira/browse/THRIFT-2451 > Project: Thrift > Issue Type: Bug > Components: Go - Compiler > Reporter: Aleksey Pesternikov > Assignee: Jens Geyer > Attachments: > thrift-2451-getters-and-no-pointers-for-optional-with-default.patch > > > Currently, for optional fields in struct > {code} > struct pkt { > 1: optional string s = "DEFAULT", > 2: optional i64 i = 42, > 3: optional bool b = false > } > {code} > go compiler generates the following: > {code} > type Pkt struct { > S *string `thrift:"s,1"` > I *int64 `thrift:"i,2"` > B *bool `thrift:"b,3"` > } > func NewPkt() *Pkt { > rval := &Pkt{ > S: new(string), > I: new(int64), > B: new(bool), > } > *(rval.S) = "DEFAULT" > *(rval.I) = 42 > *(rval.B) = false > return rval > } > func (p *Pkt) IsSetS() bool { > return p.S != nil > } > func (p *Pkt) IsSetI() bool { > return p.I != nil > } > func (p *Pkt) IsSetB() bool { > return p.B != nil > } > {code} > which is wrong in multiple ways: > 1. Freshly initialized fields returns IsSetField() true > http://play.golang.org/p/T2pIX80ZJp > This results in > a. wrong semantics: freshly created struct has optional fields set > b. excessive payload produced on serialization (writing field value > instead of skipping it) > 2. Additional load on garbage collector > 3. accessing field value is complicated and error prone. even without default > value: > {code} > if pkt.IsSetB() && *pkt.B { > //do something for b==true > } > {code} > would work for false default for field b. However, if I change default > value to true, I need to change all occurrences in the code like this: > {code} > if !pkt.IsSetB() || *pkt.B { > //do something for b==true > } > {code} > How to fix that? > there are two ways: > 1. get back to generating inlines instead of pointers for optional fields > with default value and compare with "magic value" of default in IsSet*(). > could be tricky since not all types are comparable > http://golang.org/ref/spec#Comparison_operators . notably, slices and maps > are not. > 2. approach, used in protobuf: Do not initialize optional fields, generate > Get*() accessors like this: > {code} > var Pkt_B_Default = false > func (p *Pkt) GetB() bool { > if p.B == nil { > return Pkt_B_Default > } > return *p.B > } > {code} > Just to make API uniform, we can also generate accessors for required fields: > {code} > func (p *Pkt) GetB() bool { > return p.B > } > {code} > I'm inclining to implement second approach, but I would like to collect > opinions before I dig into the code. -- This message was sent by Atlassian JIRA (v6.2#6252)