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.

Reply via email to