Live data from Hacker News

Be careful with Go struct embedding

mattjhall.co.uk

61–70 of 101 posts

Re: Be careful with Go struct embedding

#61

I like the Go language because it's straightforward and clear, even if it looks a bit plain. I hope the feature mentioned in the article will cause a compiler error. However, I wouldn't use this approach when writing my own code.

I tested the tool more thoroughly using a strict method to review the code, but it couldn't find the problems mentioned in the article.

golangci-lint run --enable-all --max-issues-per-linter=0 --max-same-issues=0

Re: Be careful with Go struct embedding

#62
post #50
post #43

Earlier quoted context omitted.

I think that using embedding for discriminating unions if a good idea. It would work, but it does not force the user to do the discrimination. I would say that explicit typecasting at the point of discrimination is safer. Without it, nothing prevents you from using one field from one variant of the union, and another from a different variant. Introduction of proper discriminated unions would be great.

I'm not sure I understand you, or you understand me. I'm saying this is okay: type Order struct { Type OrderType CommonAttr1 int CommonAttr2 string } type OrderTypeA struct { Order TypeAAttr1 int TypeAAttr2 string } type OrderTypeB struct { Order TypeBAttr1 int TypeBAttr2 string } And yes you should convert to OrderTypeA or OrderTypeB at the first opportunity in domain code, and only convert from them at the latest o…

> 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?

Re: Be careful with Go struct embedding

#64
post #63

The same issue with embbedding of field had reflect tag like json or bson ...

After that time, I did not use json or bson Unmarshal to cast anymore. Any transform/converter function of me is manual directly. And thanks for LLM, with the their help, I only need to review the function, so no more typing.

Re: Be careful with Go struct embedding

#66
post #50

Earlier quoted context omitted.

I'm not sure I understand you, or you understand me. I'm saying this is okay: type Order struct { Type OrderType CommonAttr1 int CommonAttr2 string } type OrderTypeA struct { Order TypeAAttr1 int TypeAAttr2 string } type OrderTypeB struct { Order TypeBAttr1 int TypeBAttr2 string } And yes you should convert to OrderTypeA or OrderTypeB at the first opportunity in domain code, and only convert from them at the latest o…

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

Re: Be careful with Go struct embedding

#67

Who's actually expecting `xyz.com` here? Spec: https://go.dev/ref/spec#Selectors > x.f resolves to the field/method at the shallowest depth in T. If there isn’t exactly one at that depth, it’s illegal. Embedding promotes fields; on name collisions the shallowest wins. So `opts.URL` is `FooService.URL` (depth 1), not `BarConnectionOptions.URL` (depth 2).

That something is clearly specced doesn’t imply all developers actively know it.

Even given that it compiles, I wouldn’t exclude it being a runtime error.

But the big problem isn’t that it behaves as advertised, it’s that it is way too easy to write opts.URL where you mean opts.Bar.URL. Auto-complete will happily compete the wrong thing for you.

Re: Be careful with Go struct embedding

#68

Over the course of ~10 years of writing Go, my ratio of "embedding a struct" to "regretting embedding a struct" is nearly 1:1. I do not embed structs anymore. It is almost always a mistake. I would confidently place it in the "you should be required to import 'unsafe' to use this feature" bin.

I think embedding structs would be way more useful if a) there would be properties on interfaces and b) there would be generic methods available.

As long as these two aren't there, embedding structs is literally identical to dispatching methods, and can't be used for anything else due to lack of state management through it. You have to manage the states externally anyways from a memory ownership perspective.

Re: Be careful with Go struct embedding

#69
post #59

Am I the only one who found the described behavior to be intuitively correct? I did expect it to print "abc.com".

I'm confused at the responses saying this intuitive. It's like saying: var x string x = "abc.com" x = "xyz.com" fmt.Println(x) will print abc.com and that's totally expected. The normal intuition would be that the latter operations or (re)definitions override the preceding ones.

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"},
  }

Re: Be careful with Go struct embedding

#70
This is a "you had one job" level language defect. If there are excuses that allow Go to pretend that structs with duplicate member names are well formed, good programming language designers would reject them in horror and specify how the compiler should actively look for this type of mistake, without wasting effort to look for such excuses.
Post reply on HN