The Context problem is more easily solved using package namespaces for keys with conventions rather than type embedding.
Otherwise you end up with a brittle multiple inheritance problem. Or you need language support for typed TLS and remove Context entirely. > On Jul 21, 2020, at 6:24 AM, 'Axel Wagner' via golang-nuts > <golang-nuts@googlegroups.com> wrote: > > >> On Tue, Jul 21, 2020 at 10:54 AM 'Javier Zunzunegui' via golang-nuts >> <golang-nuts@googlegroups.com> wrote: > >> It's not A(B,C,D) vs A(B(C(D))), both are supported with & without >> embedding. My issue is with a linked list that requires a new type for each >> additional node. It is potentially an explosion of types > > I don't think "explosion" is an appropriate word. It's really not any worse > than regular embedding. You can write `x := struct{ Y }{y}` just fine, and > you wouldn't say that embedding leads to "an explosion of types", right? And > `context.Value` also needs a new type for each value stored in it, if used as > recommended (for each key), and there's no "explosion of types" there either. > > I can't think of a way you can make the number of types in a program grow > superlinear in code-size if we allow embedding (that we can't already do), so > I really don't think "explosion" is the right word - and that's important, > because it's indicative of there not really being a problem with that > >> an imho an abuse of the type system. > > Potato, Tomato :) There are loads of things that are allowed and even often > recommended, that could very well be called an "abuse of the type system". > Like defining an unexported type and using it as an argument, to enforce that > only literals can be used. Or adding _-fields to prevent comparison or > copying of structs. > > I agree that it's probably too clever for its own good and I would prefer if > it were simpler. But I do think it would be very useful to have a way to > amend an arbitrary type with new methods without erasing any of the existing > ones. Context.Value was only the first example I wrote about. But there are > others as well, like `http.ResponseWriter`. Even an `io.Writer` may benefit > from being able to be wrapped without erasing potential `WriteByte`, > `WriteRune`, `ReadFrom`… methods. > > Embedding type-parameters is a way to achieve that and I don't know a > different way. > I'm not saying a generics design *must* enable it, but it's certainly a > useful feature to have. > >> Agreed. My point is it either ads no value, or when it does add some it is >> probably at the expense of things like maintainability, abstraction, >> tooling, types system, etc. and is simply not worth it. > > But that's a *very different* point from your original "The fundamental > problem I see is it introduces complexity, but no value". Now you're simply > saying "it's a tradeoff and I don't think it's worth it", which is fine of > course :) > > I don't think I agree, personally. IMO it is very natural being able to do > this and easy enough to implement, so I don't really think the cost is *that* > high. And if it was *just* to do my context-experiment, I'd agree that the > benefit is probably too low. But as I said, a) I don't think that's the only > use-case and b) people *are* frequently complaining about the lack of > type-safety of Context.Value, so there is definitely interest to solve that > problem *somehow*. > > But ultimately, yeah. It's a tradeoff, whatever the outcome is, I'll be fine > :) > >> PS I didn't find where to discuss your post in your blog. If you have >> somewhere for that please share and I'd be happy to discuss at more length >> there > > I don't have a dedicated comment-section, because I don't want to moderate. > You can discuss via off-list E-Mail if you want and I also always submit my > posts to /r/golang. > > >>> On Tuesday, July 21, 2020 at 10:15:58 AM UTC+2 axel.wa...@googlemail.com >>> wrote: >>> Why do you feel that a type A(B, C, D, E) should be supported, but >>> A(B(C(D(E))) shouldn't? They are equivalent in expressiveness. And to be >>> clear, I'd also prefer A(B, C, D, E) for this use, but ISTM this isn't >>> possible without variadic type-parameters (i.e. I'd need a way to express >>> "this function takes a A(…) and returns an A(B,…)"). So to get this value, >>> you'd either need embedded type-parameters or variadic type-parameters. >>> >>> At the end of the day, though, my main point was "there is value". You may >>> very well feel that the value isn't worth the cost (as I say in the >>> conclusion, I'm not sure how I feel about that myself). But would you agree >>> that your statement "it adds complexity without adding value" doesn't >>> really hold up? >>> >>>> On Tue, Jul 21, 2020 at 9:46 AM 'Javier Zunzunegui' via golang-nuts >>>> <golan...@googlegroups.com> wrote: >>>> >>>> Thanks for sharing Axel. >>>> >>>> I would place your post firmly in the category "doing something wild and >>>> can't use generics for it". >>>> >>>> Philosophical issues around context aside, it implements the chain of >>>> contexts directly via the type system, e.g.the TYPE after N wraps is >>>> `FooContext(BarContext(... N times ... (context.Context))` >>>> I would say that is abusing the type system and don't think it shuld be >>>> something generics should aim to support. >>>>> On Monday, July 20, 2020 at 9:54:57 PM UTC+2 axel.wa...@googlemail.com >>>>> wrote: >>>>> Hi, >>>>> >>>>> given the discussion here, the blog post I just published might be >>>>> interesting: >>>>> https://blog.merovius.de/2020/07/20/parametric-context.html >>>>> To the best of my knowledge, what I describe there is only really doable >>>>> using embedded type-parameters. As I state in the conclusion, I'm not >>>>> entirely sure this would be something *good*. But I do think it adds more >>>>> type-safety and that does provide value. >>>>> >>>>> Interested to hear your thoughts :) >>>>> >>>>> Axel >>>>> >>>>> >>>>>> On Mon, Jul 20, 2020 at 3:37 PM 'Javier Zunzunegui' via golang-nuts >>>>>> <golan...@googlegroups.com> wrote: >>>>>> Coming back at this after more thought & exploration. The fundamental >>>>>> problem I see is it introduces complexity, but no value. >>>>>> >>>>>> Say >>>>>> `type I interface {...}` >>>>>> `type S(type T I) struct {T}` >>>>>> Then the generic S (before instantiating with a particular T) may >>>>>> implement any interface, e.g. in any method on S or any other generic >>>>>> code using S, you may have >>>>>> `_, ok := (interface{}(S(...){})` ).(Whatever)` >>>>>> and the result of ok depends on what T is used. Without embedding, that >>>>>> is strue of T but not S. >>>>>> >>>>>> # What value did this add? >>>>>> - You can call methods listed in I directly, e.g. if method Foo is in >>>>>> listed I, you can do s.Foo(). >>>>>> => without embedding using s.I.Foo() is hardly a change. >>>>>> - You can implement interfaces based on method listed in I directly, >>>>>> e.g. if method Foo is listed in I and characterises interface Fooer, you >>>>>> can do Fooer(s). >>>>>> => without embedding, you can do Fooer(s.I) or if you actually want >>>>>> s in the interface, write a generic method Foo in S and keep Fooer(s). >>>>>> - You can implement interfaces based on method NOT listed in I directly, >>>>>> e.g. if method Foo is NOT listed in I, but is defined in some T and >>>>>> characterises interface Fooer, you can do Fooer(s) (for s := S(T){...}). >>>>>> => without embedding, you can't do this. You can do Fooer(s.I), or >>>>>> create a new type for this specificT, `type X S(T)`, and implement >>>>>> method Foo, but let's assume that neither is acceptable. How realistic / >>>>>> in what circumstances do you want this? If you require a struct to have >>>>>> a method not listed in any contract but present in the type that happens >>>>>> to be embedded on this instance of the generic, and want it to be >>>>>> assigned to an interface that uses that method but won't accept either >>>>>> the embedded field in the interface, nor a separate type derived from it >>>>>> with the additional method, I'd say you need to re-evaluate your >>>>>> requirements because you are not following any moderatly sensible >>>>>> standards, or at the very least accept you are doing something wild and >>>>>> can't use generics for it. >>>>>> >>>>>> # What did this cost? >>>>>> - Complexity => the possibility of there being more methods available in >>>>>> a struct than listed in its definition is in itself one more thing to >>>>>> think about. >>>>>> - Refactoring => an embedding can't be refactored without a breacking >>>>>> change (can't change `type S(type T I) struct {T}` to `type S(type T I) >>>>>> struct {T}` + methods in I), since users may be relying on methods not >>>>>> present in I. >>>>>> - Limits to Tooling: without embedding, `_, ok := >>>>>> (interface{}(S(...){})` ).(Whatever)` above may always be false and the >>>>>> tooling may be able to identify and flag that, with embedding there is >>>>>> nothing it can do since it may always be true. >>>>>> >>>>>> # No arbitrary restrictions >>>>>> "our hope is to make generic types work as much like ordinary types as >>>>>> possible, without arbitrary restrictions" >>>>>> => this is indeed a restriction, and I don't know how much that >>>>>> weights in the go team's mind regarding future features, etc. But on the >>>>>> other hand even allowing embedding in generics isn't quite as >>>>>> pre-generics go either, after all you are embedding using the generic's >>>>>> type name (in my example, T) and not the name of the actuall type T is >>>>>> instantiated with. In other words, the type produced can't be replicated >>>>>> without generics. Banning embedding you limit slightly the types you can >>>>>> produce, but at least those that are allowed are valid pre-generic go >>>>>> types. >>>>>> >>>>>> And of course there is also a 'delay decision' argument here: if >>>>>> embedding is banned, it can be added later. If it is allowed, the >>>>>> decision is final. >>>>>> >>>>>> I do not claim anything dramatic about this feature's significance, like >>>>>> generics with fail if embedding is allowed, but also generics will not >>>>>> fail because they weren't. So if there is no strong reason for, and >>>>>> there are some reasons against, it seems to me the best decision is to >>>>>> ban at first and re-evaluate later. >>>>>>>> On Tuesday, July 14, 2020 at 11:41:42 AM UTC+2 Javier Zunzunegui wrote: >>>>>>>> Issue openned in https://github.com/golang/go/issues/40199. >>>>>>>> >>>>>>>> Still clarifying my thoughts on embedding types within generics, will >>>>>>>> postpone this debate while I focus on other parts of the proposal and >>>>>>>> gain some more experience using the go2 branch. Not calling for any >>>>>>>> action here at this point. Thanks Ian. >>>>>>>>> On Monday, July 13, 2020 at 7:03:35 PM UTC+2 Ian Lance Taylor wrote: >>>>>>>>> On Mon, Jul 13, 2020 at 9:15 AM 'Javier Zunzunegui' via golang-nuts >>>>>>>>> <golan...@googlegroups.com> wrote: >>>>>>>>> > >>>>>>>>> > In the context of Type Parameters - Draft Design#generic-types: >>>>>>>>> > >>>>>>>>> > Type embedding is allowed in the proposed generic changes. Oddly, >>>>>>>>> > the current implementation allows for calling methods in the >>>>>>>>> > embedded types but not using the method to satisfy an interface >>>>>>>>> > (here). That seems like a bug in the implementation. >>>>>>>>> > >>>>>>>>> > More significantly, it allows for calling not just the methods >>>>>>>>> > declared in the interface, but also methods available to the >>>>>>>>> > instantiated type but not part of the interface. Example here. I >>>>>>>>> > can't see what is the gain in allowing that, and it presents a risk >>>>>>>>> > as the interfaces satisfied by types originating from the same >>>>>>>>> > generic type will differ not only in the types of the methods, but >>>>>>>>> > also i the method names themselves. >>>>>>>>> > >>>>>>>>> > Would it not be best to not allow embeding in generic types? >>>>>>>>> >>>>>>>>> At least at first glance these just seem like bugs in the current >>>>>>>>> implementation, not in the design draft as such. Would you mind >>>>>>>>> opening an issue for these problems? Thanks. >>>>>>>>> >>>>>>>>> We could ban embedding type parameters, but our hope is to make >>>>>>>>> generic types work as much like ordinary types as possible, without >>>>>>>>> arbitrary restrictions. The existence of bugs doesn't in itself seem >>>>>>>>> like a good enough reason to ban the feature. >>>>>>>>> >>>>>>>>> Ian >>>>>>> >>>>>> -- >>>>>> 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/36bae6eb-4537-4796-8c11-60e828a36d51n%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/082b29da-91ca-431f-9378-5b858727ddd3n%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/0a37c712-e83b-45c9-9910-12d9b40d9566n%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/CAEkBMfHOAcmOG6Vrhn1DDYRjz%2B_KXoxqJ9Jzom65pgJxn%2BdU_g%40mail.gmail.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/8E892642-F7F2-432E-9F8C-781C3419618E%40ix.netcom.com.