> 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?
> 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.
>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.
You said struct embedding could be used for discriminated unions, but there's no mechanism to discriminate between union variants here.
Go simply doesn't have discriminated unions, so a number of pattern can all be called "discriminated unions" in Go. I was simply emphasizing that sharing common fields between pure data structs with struct embedding (commonly seen in but not limited to discriminated unions) but now people are weirdly hung up on discriminated unions. I just showed a data model with a discriminator (.Type), there are a number of mechanisms to discriminate depending on your actual needs. You can make the types conform to an interface, pass an interface value around and cast to specific types. You can get a fat row with a bunch of left joins from your database then immediate create type-specific structs and call type-specific methods with them. You can get a discriminated union on the wire, unmarshal the type field first, then choose the type-specific struct to unmarshal to. Etc. These are largely irrelevant in a discussion about type embedding.
> so a number of pattern can all be called "discriminated unions"
Assuming they've got discriminators and some sense of type union, sure.
> I just showed a data model with a discriminator (.Type)
Which won't let you recover the additional fields from a pointer because you can't downcast, so that's insufficient for a union. AFAIK you need to combine this with interfaces, which I already know how to do.
> These are largely irrelevant in a discussion about type embedding.
Don't tell me, you brought it up.
It’s almost like I brought it up in passing because it’s a somewhat relevant concrete use case, rather than brought it up to have people who “already know how to do” to chastise me for not writing a full treatise on the use case.