3 ms·
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.
by nemo1618 1y ago
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.
- oefrha 1y agoUsing struct embedding for pure data to implement discriminated unions is fine, better than MarshalJSON() that is lost on a type definition. Using it to save typing, or going crazy with it (I consider embedding two things going crazy) is bad.
- nine_k 1y agoI 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.
- oefrha 1y agoI'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 opportunity. You seem to be under the impression that I'm advocating for something like type OrderUnion struct { CommonAttr1 int CommonAttr2 string TypeAAttrs TypeBAttrs } That's what I consider going crazy.
- debugnik 1y ago> 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?
- oefrha 1y agoThe missing something is manually creating the structs, not casting.
- Thorrez 1y ago>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.
- jerf 1y agoNeeding 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.
- debugnik 1y agoYou said struct embedding could be used for discriminated unions, but there's no mechanism to discriminate between union variants here.
- oefrha 1y ago
- cyphar 1y agoI think there are a handful of cases where it is a nice-to-have and would be sad if it was removed in a hypothetical Go 2. Making a utility wrapper struct that overrides a method or adds new helper methods while keeping the rest of the interface is the most common example, though there are also some JSON spec type examples which are a little more esoteric. However, you need to be mentally prepared to switch to the boilerplate version as soon as things start getting hairy. But yes, for anything more complicated I have generally regretted trying to embed structs. I think requiring "unsafe" is a bit too strong, but I think the syntax should've been uglier / more in-your-face to discourage its use. (Fellow 10+ years Go user.)
- nemo1618 1y agoyup, less than 24 hours after writing that comment, I found myself embedding a struct so that I could override one method in a test, haha
- h4ck_th3_pl4n3t 1y agoI 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.