[ https://issues.apache.org/jira/browse/THRIFT-2451?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13962192#comment-13962192 ]
Jens Geyer commented on THRIFT-2451: ------------------------------------ Hi [~apesternikov] and [~bensigelman], there is a lengthy debate about the semantics of {{required}}, {{optional}} and default specifiers vis-รก-vis setting field defaults over there in THRIFT-2429. I dont want to repeat the stuff here, but the ideal result would have the Go implementation conform to what has been finally agreed upon over there. {quote} I wouldn't want to force callers to take responsibility for setting "set" bits along with field values. {quote} Absolutely. I'm 100% behind that, especially as it would a) not conform with the other languages and b) make things overly complicated. BTW, Ben, your opinion is more than welcome. > Go generated code should not initialize optional fields. Instead, Get > accessors should be generated > --------------------------------------------------------------------------------------------------- > > 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 > > Currently, for optional fields in struct > struct pkt { > 1: optional string s = "DEFAULT", > 2: optional i64 i = 42, > 3: optional bool b = false > } > go compiler generates the following: > 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 > } > 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: > if pkt.IsSetB() && *pkt.B { > //do something for b==true > } > 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: > if !pkt.IsSetB() || *pkt.B { > //do something for b==true > } > 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: > var Pkt_B_Default = false > func (p *Pkt) GetB() bool { > if p.B == nil { > return Pkt_B_Default > } > return *p.B > } > Just to make API uniform, we can also generate accessors for required fields: > func (p *Pkt) GetB() bool { > return p.B > } > 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)