This is a task for a parser - and the parser can be type safe -but the constraints for something as complex as html aren’t typically expressed in types but rather bnf or similar.
You can look at the Java html renderer/parser and it uses type safe nodes but it still has a resilient parser layer to produce the nodes. > On Dec 20, 2021, at 3:06 PM, Michael Ellis <michael.f.el...@gmail.com> wrote: > > Thanks, Axel & Robert. As I said in the first post, the package already > works well for my purposes (and apparently for the few others who use it). > It allows defining web content more concisely than raw HTML and makes the > full power of Go available for composing repetitive page structures. > > I was mostly just curious about the possibility of detecting bad content at > compile time instead of at run time. In practice, that's turned out not to be > a significant problem so I'm ok with learning generics don't support a fix. > >> On Monday, December 20, 2021 at 2:31:32 PM UTC-5 axel.wa...@googlemail.com >> wrote: >> 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.wa...@googlemail.com> >>> wrote: >>> >>> >>>> On Mon, Dec 20, 2021 at 7:07 PM Michael Ellis <michael...@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, 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. >>>> >>>> -- >>>> 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/2de22684-0263-465c-8ac0-ff288c535fb7n%40googlegroups.com. > > -- > 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/34f509ae-1681-4bb4-8b54-ce0e5534fe87n%40googlegroups.com. -- 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/261AF334-7F5C-4C0C-8D34-DF248ACA6A0D%40ix.netcom.com.