Thanks for the clarification, and I agree completely.

There are plenty of cases in the Go standard library where there is a 
public struct for bundling state, and I don't see adding a new member 
(whether it's private or public) as a breaking change.  Nobody's going to 
attempt to mirror the entire type tree, and generally they can't because 
there are private members too.

Equally, it's reasonable to allow a package to export a plain-old-data 
struct, certainly between packages that comprise a user application.

On Friday, 12 March 2021 at 12:15:15 UTC axel.wa...@googlemail.com wrote:

> On Fri, Mar 12, 2021 at 10:16 AM Brian Candler <b.ca...@pobox.com> wrote:
>
>> I can see two separate things under discussion - compatibility of struct 
>> types for conversion, and backwards-compatibility of serialization [JSON? 
>> Protobuf?]
>>
>
> Backwards-compatibility of serialization is a red herring. It is off-topic 
> as far as this thread is concerned, this is purely about language-level 
> compatibility of types.
>  
>
>> but I can't see what's being proposed to change.
>>
>
> I think the proposed change can be summarized as roughly
>
> Either
>> 1. Create consensus that adding an (exported) field to a struct should be 
>> considered a backwards incompatible change, or
>> 2. Create consensus that converting one struct type into a different 
>> struct type should be considered deprecated, as it makes you vulnerable to 
>> getting broken by someone adding a field.
>> Take either consensus and put it into the Go 1 compatibility promise and 
>> potentially encode it into a vet check.
>
>
> That is my understanding of what's "proposed". Personally, as I said, I'm 
> not in favor of either. I think both statements lack nuance.
>
> The logical conclusions of the arguments brought forth is that every 
> publicly visible change is a breaking change. So if we follow that logic 
> we'd end up (in my opinion) in an ecosystem where every module is 
> constantly incrementing their major versions because "we technically broke 
> the API". I think that is undesirable.
>
> Given that every publicly visible change to an exported identifier can be 
> considered a breaking change, I personally don't think it's all that useful 
> to talk about interface-changes vs. struct changes and which of them are 
> breaking. Both are - in some circumstances. And in some circumstance, 
> neither are. It's more useful to talk about *how frequently* any given 
> change leads to breakages. I think it's easy to make an argument that 
> changing in interface type will lead to very frequent breakages - it will 
> either break every implementation of the interface, or any usage of the 
> interface, or both.
>
> Meanwhile, I think it's also not that hard to make an argument that 
> breakages causing by converting one struct type into another and then 
> adding a field to one of them are *comparatively* rare. And even within 
> that, there is nuance, where it is more frequent for some kind of types 
> (POD - plain-old-data) than others (e.g. http.Server or other types used to 
> abstract and bundle state).
>
> That's why I don't think a vet check would work. It can't distinguish the 
> case of a struct being POD vs. the struct bundling state. And I would even 
> argue that generally, the "bundling state" case is more common in Go.
>
>
>> I don't follow the argument that "adding a field to a struct is *now* a 
>> backwards incompatible change".  Surely this was always the case, 
>> regardless of tags?  That is, if you have
>>
>> type T1 struct {
>>     Foo string
>> }
>>
>> type T2 struct {
>>     Foo string
>>     Bar string
>> }
>>
>> then what would you expect to happen for:
>>
>>     v1 := T1{}
>>     v2 := T2(v1)   ??
>> ...
>>     v2 := T2{}
>>     v1 := T1(v2)  ??
>>
>> These two structures have different shapes.  In the first case, I suppose 
>> it could copy the matching members and create zero values for the new 
>> ones.  In the second case, I suppose it could copy the matching members and 
>> silently(!) discard the missing ones.  But either way, that just means the 
>> compiler magically writing code which copies member-by-member.  I'd rather 
>> do this by hand.
>>
>> Even with magic conversions, trying to use a *t1 as a *t2 or vice versa 
>> would definitely not work, as they have differing layout in memory. Indeed, 
>> even the ordering of fields in memory must be the same for two structs to 
>> be compatible:
>> https://play.golang.org/p/BTUc6mNJQKS
>>
>> However, if two structures have the same members in the same order, and 
>> differ only by tags, then they have the same shape.  Then it seems 
>> reasonable to me to treat a T1 as compatible with T2; copying can be done 
>> as a blob of bytes.  The change in 1.8 to omit comparing tags has made 
>> types more compatible, not less.
>>
>> Separately from that, there's the issue of serialization and 
>> forwards/backwards compatibility.  I don't see any problem here.  For 
>> example, if you serialize a type T1 to JSON, and then deserialize to T2 
>> (which may have more or fewer fields), that all works fine.
>>
>> https://play.golang.org/p/aJwObgyRhan
>>
>> If you want to reject unexpected fields when deserializing, there are 
>> options for doing that.  But by default, they are compatible in both 
>> directions.  You can also re-order the fields in the struct, since the JSON 
>> deserialization is assigning elements individually.
>>
>> -- 
>>
> You received this message because you are subscribed to the Google Groups 
>> "golang-nuts" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to golang-nuts...@googlegroups.com.
>>
> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/golang-nuts/36e1a048-2505-4841-8882-a9b16a33fd57n%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/golang-nuts/36e1a048-2505-4841-8882-a9b16a33fd57n%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/9f50c4ad-13ae-45ad-a874-08c6dd63e7c9n%40googlegroups.com.

Reply via email to