Oh, forgot the footnote: [1] Note that even that doesn't *actually* work, as `*HtmlNode` would become a parametric type, so it would have to be instantiated to be used in the constraint - you'd have to write `type HtmlNode[T string | *HtmlNode[Something]]`. And the fact that there is no actual answer to what "Something" would be should be a strong indicator for how much generics are not what you want for this.
On Mon, Dec 20, 2021 at 8:29 PM Axel Wagner <axel.wagner...@googlemail.com> wrote: > > > On Mon, Dec 20, 2021 at 7:07 PM Michael Ellis <michael.f.el...@gmail.com> > wrote: > >> >Just to be clear, the way I understood you is that you want HtmlTree.C >> to be a slice which has elements which can each either be a string or an >> *HtmlTree - i.e. you want these to be mixed in a single slice. Correct? >> >> Actually, no. An HtmlTree instance whose content is a string is a >> terminal node. The recursion in the Render() func looks like: >> >> for _, c := range h.C { >> switch c := c.(type) { >> case string: >> b.WriteString(c) >> case *HtmlTree: >> err = Render(c, b, rindent) >> if err != nil { >> return fmt.Errorf("%s : %v", h.T, err) >> } >> default: >> return fmt.Errorf("Bad content %v. Can't render >> type %T! ", h.C, c) >> } >> } >> > > That's pretty much what I meant, yes. You want a sum type (and in lieu of > sum types, an interface), not generics. > The "union" aspect of Go generics (the `a | b` syntax) only applies to > using interfaces as *constraints*, not as *types* - you want to do the > latter. You want to have a field which is either a string or an *HtmlNode - > but Go only gives you a convenient way to write the two distinct types > `type HtmlNodeString struct { /*…*/ C string }` and `type HtmlNodeNode > struct { /* … */ C *HtmlNode }` into one¹ type declaration and write > function which can work on either. It's just not what you want. > > The best option for you is (as Robert mentions) to use an interface, which > is an "open sum" - meaning you can't have the guarantee that its dynamic > type is of a limited set of options, but you *can* have a value whose > actual type is dynamic. You can look at e.g. ast.Node > <https://pkg.go.dev/go/ast#Node>, which is de-facto the same thing - it's > supposed to be a limited set of options, but in lieu of sum types, it's an > interface. > > Go might, at some point, allow the union-elements of constraint interfaces > to be used as actual types, which *would* be a form of sum types. But > probably not for a while - it's more complicated than it may seem. > > >> >> I suppose it's still a problem, though, since the compiler doesn't have >> any way of knowing that's how trees of HtmlTree meant to be constructed. I >> should have expressed the intended constraint on HtmlTree.C as `string | >> []*HtmlTree`. Does that make a difference? >> On Monday, December 20, 2021 at 10:25:26 AM UTC-5 >> axel.wa...@googlemail.com wrote: >> >>> Just to be clear, the way I understood you is that you want HtmlTree.C >>> to be a slice which has elements which can each either be a string or an >>> *HtmlTree - i.e. you wan these to be mixed in a single slice. Correct? >>> Because that is not a use case for generics, it's a use case for sum >>> types (which Go does not have). >>> >>> On Mon, Dec 20, 2021 at 4:11 PM Michael Ellis <michael...@gmail.com> >>> wrote: >>> >>>> > They can't, sorry. >>>> Ok. Thanks, Axel. >>>> Saves me wasting more time. In the past 3 years of using Go, this is >>>> the only use case where I've really wanted generics (other cases I've >>>> encountered so far are easily handled with code generation). >>>> >>>> -- >>>> >>> 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/ac75dc32-733d-4a73-9735-619c33cb4cd4n%40googlegroups.com >>>> <https://groups.google.com/d/msgid/golang-nuts/ac75dc32-733d-4a73-9735-619c33cb4cd4n%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/2de22684-0263-465c-8ac0-ff288c535fb7n%40googlegroups.com >> <https://groups.google.com/d/msgid/golang-nuts/2de22684-0263-465c-8ac0-ff288c535fb7n%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/CAEkBMfELP%2BP74kkKJCaZLfk9axEK%2BLUUMFZw2t26m6fNeT%2BjAQ%40mail.gmail.com.