Live data from Hacker News

Be careful with Go struct embedding

mattjhall.co.uk

81–90 of 101 posts

Re: Be careful with Go struct embedding

#81
post #74

Some people in comments jump to the conclusion that Go allows conflicting names in embedded structs. It doesn't not – for the embedded structs of the same depth. These won't compile: type Bad struct { Name string Name string } type A struct{ Name string } type B struct{ Name string } type C struct { A B } bad.Name() // compile error: other declaration of Name c.Name() // compile error: ambiguous selector c.Name The c…

I don't really use golang all that much and even I was confused about OP's point because of the different depths.

I feel like sometimes people just want to complain.

Re: Be careful with Go struct embedding

#82
post #74

Some people in comments jump to the conclusion that Go allows conflicting names in embedded structs. It doesn't not – for the embedded structs of the same depth. These won't compile: type Bad struct { Name string Name string } type A struct{ Name string } type B struct{ Name string } type C struct { A B } bad.Name() // compile error: other declaration of Name c.Name() // compile error: ambiguous selector c.Name The c…

> Even more, imagine in the future authors of `somepackage` decided to add URL to their struct and it suddendly started to break your code from being compiled.

doesn't this just shove the problem down a level?

e.g. if somepackage.Bar suddenly gets a member with same name as one of your URL members?

Re: Be careful with Go struct embedding

#83
post #79
post #66

Earlier quoted context omitted.

The missing something is manually creating the structs, not casting.

>And yes you should convert to OrderTypeA or OrderTypeB at the first opportunity How would you convert Order to OrderTypeA? You would need some other source to fill TypeAAttr1 and TypeAAttr2 with.

Needing further external information to "convert" from one struct type to another is fairly common and completely normal. One I happen to have encountered in multiple places over the years is normalizing user names. Sometimes there is no mechanical process to normalize user names, such as simply lowercasing them; you may need access to an LDAP server to get a canonical name/account, or access to information about local email munging rules (like "which character do you use to allow users to specify multiple addresses for themselves, like gmail uses '+'?" - not all systems use +), or you may need DB access to verify the user name exists if you want a value of the given type to represent a user that is not only normalized but guaranteed to exist.

Re: Be careful with Go struct embedding

#84
post #34

My personal conspiracy is that Golang is an epic prank. Make a language that's really good in some ways and just horrible in other ways for no reason whatsoever. So that when it's critics point out contradictory features like embedding, it's defenders can be the ultimate troll and say things like "but, actually, it's a simple language because it doesn't have while loops". It's the best explanation I have for some of…

I've been programming in Go for ten years.

This problem has happened to me once.

Would you care to make a list of all the problems your favorite language has served up to you at a rate of once in ten years, so I can also write a post making your language sound horrible as a result?

Re: Be careful with Go struct embedding

#85
post #74

Some people in comments jump to the conclusion that Go allows conflicting names in embedded structs. It doesn't not – for the embedded structs of the same depth. These won't compile: type Bad struct { Name string Name string } type A struct{ Name string } type B struct{ Name string } type C struct { A B } bad.Name() // compile error: other declaration of Name c.Name() // compile error: ambiguous selector c.Name The c…

> Even more, imagine in the future authors of `somepackage` decided to add URL to their struct and it suddendly started to break your code from being compiled. doesn't this just shove the problem down a level? e.g. if somepackage.Bar suddenly gets a member with same name as one of your URL members?

> e.g. if somepackage.Bar suddenly gets a member with same name as one of your URL members?

I think nothing happens there. Your fields "win" on depth and you'd have to access their field with `thing.Bar.Conflicted` (whereas yours would be `thing.Conflicted`).

It could only be a problem if someone embeds both `somepackage.Bar` and `mypackage.Cheese` into `T` with a shared field `X` but then you can't access `T.X` without a runtime error of "ambiguous selector".

Re: Be careful with Go struct embedding

#86
Why would you ever do opts.URL instead of opts.FooService.URL or opts.BarService.URL? What does ambiguity and imprecision gain you here when you can just write out from which struct you want it from? I don't even know why opts.URL would compile, it's completely unstated that you're not grabbing it from opts but grabbing it from some other structure contained within opts. Shouldn't even compile IMO, but at least I found something I disagree with Go's designers on.

Re: Be careful with Go struct embedding

#87
post #78
post #69

Earlier quoted context omitted.

It's not at all like saying that. The order of operations has nothing to do with it. opts := Options{ FooService: FooService{URL: "abc.com"}, BarService: BarService{ BarConnectionOptions: BarConnectionOptions{ URL: "xyz.com", }, }, } is equivalent to opts := Options{ BarService: BarService{ BarConnectionOptions: BarConnectionOptions{ URL: "xyz.com", }, }, FooService: FooService{URL: "abc.com"}, }

I'm making an analogy using simple assignments to show more clearly that it's actually counter-intuitive, I'm not claiming what you seem to be refuting, which at best seems to be beside the point.

And the analogy is invalid, because it completely replaces the intuitive thing that's happening with an unintuitive thing that isn't happening. There are no "latter operations or (re)definitions" here.

Re: Be careful with Go struct embedding

#88
post #66

Earlier quoted context omitted.

> And yes you should convert to OrderTypeA or OrderTypeB at the first opportunity in domain code, Go can only downcast through interfaces so there's something missing to your approach to unions, isn't there?

The missing something is manually creating the structs, not casting.

You said struct embedding could be used for discriminated unions, but there's no mechanism to discriminate between union variants here.

Re: Be careful with Go struct embedding

#89

Earlier quoted context omitted.

This comment unexpectedly received a few downvotes, which might be due to some misunderstanding. My point is as follows: 1. People choose Go for various reasons. 2. Beginners will encounter the issues mentioned in the article, so I hope there could be a feature that provides hints for newcomers. While the compilation errors might not be reasonable, at least the LSP/linter could provide some guidance.

This may be a language issue, but saying "I hope this causes a compilation failure" implies that you don't know if it does - this is probably why you got down voted, since the article very explicitly says that this doesn't cause compilation failure. You may have meant that you hoped it wouldn't do this - in that case you should have used a construction like "I'd hoped this would have caused a compilation failure".

Thank you so much for your reply! Your advice has been really helpful. I was confused about this.

Re: Be careful with Go struct embedding

#90
post #74

Some people in comments jump to the conclusion that Go allows conflicting names in embedded structs. It doesn't not – for the embedded structs of the same depth. These won't compile: type Bad struct { Name string Name string } type A struct{ Name string } type B struct{ Name string } type C struct { A B } bad.Name() // compile error: other declaration of Name c.Name() // compile error: ambiguous selector c.Name The c…

I don't really use golang all that much and even I was confused about OP's point because of the different depths. I feel like sometimes people just want to complain.

I think author just used to having consistency in Go. If you learned behaviour of one aspect of the language (i.e. compile-time error for conflicting field names), you would expect to have it in all cases. And that's not what's happened in the given example.
Post reply on HN