[ 
https://issues.apache.org/jira/browse/THRIFT-2451?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13970631#comment-13970631
 ] 

Jens Geyer commented on THRIFT-2451:
------------------------------------

{quote}
nil pointers for required fields are not surprising at all, for example any 
required struct field is a pointer, and I have a mixed feeling about it. I 
would rather prefer to have it inlined, but it means we may start copying 
struct values somewhere we don't want, 
{quote}

Are you aware, that this very same argument could be applied to the non-pointer 
optional fields with defaults? If we do the one but ignore the other, it starts 
looking arbitrary and inconsistent. That's what I for sure don't want. If we 
have two cases (pointer vs. non-pointer), we should at least be able to explain 
it in a logical fashion. 

But speaking about that, I found another issue with non-pointer-fields (both 
optional or required): Having them would require us to add special handling for 
the new {{cpp.ref}} annotation for those cases, where you *want* it to be a 
pointer. The benefit of the annotation would be that it would be only applied 
in exactly such cases, manually by editing the IDL, not affecting the 
performance of the non-pointerized fields. And yes, there are (and will be) use 
cases for this.

In my opinion, we should do it all or nothing: *Either we want to sacrifice the 
(more consistent) "all-pointers" style to performance wherever possible, or we 
don't.* I'm strongly against producing an 
[Mischmasch|http://www.dict.cc/deutsch-englisch/Mischmasch.html]-solution here 
It is already complex enough. there is really no need to make it more 
complicated as it already is.


> 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-v2.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)

Reply via email to