Re: [go-nuts] [generics] Type embedding in generic types

2020-07-21 Thread 'Javier Zunzunegui' via golang-nuts
I suggest we move the discussion about Axel's post to reddit 
.
Let's keep this exclusively on the the topic of embeding + generics.
For anyone joining here, the main arguments are in the 4th post here 
.
On Tuesday, July 21, 2020 at 1:45:35 PM UTC+2 ren...@ix.netcom.com wrote:

> 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 <
> golan...@googlegroups.com> wrote:
>
> 
>
> On Tue, Jul 21, 2020 at 10:54 AM 'Javier Zunzunegui' via golang-nuts <
> golan...@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 

Re: [go-nuts] [generics] Type embedding in generic types

2020-07-21 Thread Robert Engels
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 
>  wrote:
> 
> 
>> On Tue, Jul 21, 2020 at 10:54 AM 'Javier Zunzunegui' via golang-nuts 
>>  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 
  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 

Re: [go-nuts] [generics] Type embedding in generic types

2020-07-21 Thread 'Axel Wagner' via golang-nuts
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 

Re: [go-nuts] [generics] Type embedding in generic types

2020-07-21 Thread 'Javier Zunzunegui' via golang-nuts
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, an imho an abuse 
of the type system.

> 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?

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.

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
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 

Re: [go-nuts] [generics] Type embedding in generic types

2020-07-21 Thread 'Axel Wagner' via golang-nuts
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 <
golang-nuts@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"
>>> => 

Re: [go-nuts] [generics] Type embedding in generic types

2020-07-21 Thread 'Javier Zunzunegui' via golang-nuts

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 

Re: [go-nuts] [generics] Type embedding in generic types

2020-07-20 Thread 'Axel Wagner' via golang-nuts
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 <
golang-nuts@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 

Re: [go-nuts] [generics] Type embedding in generic types

2020-07-20 Thread 'Javier Zunzunegui' via golang-nuts
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
>>  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 

Re: [go-nuts] [generics] Type embedding in generic types

2020-07-14 Thread 'Javier Zunzunegui' via golang-nuts
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
>  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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/d8540f91-94b4-498f-97fe-606f956cea77n%40googlegroups.com.


Re: [go-nuts] [generics] Type embedding in generic types

2020-07-13 Thread Ian Lance Taylor
On Mon, Jul 13, 2020 at 9:15 AM 'Javier Zunzunegui' via golang-nuts
 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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAOyqgcVpAp5pSRRJmYCN4KquKwKQ8-OJ_QALbTUE4JCckdc%3Dww%40mail.gmail.com.


[go-nuts] [generics] Type embedding in generic types

2020-07-13 Thread 'Javier Zunzunegui' via golang-nuts
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? 

-- 
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/007aa3e3-5ae8-4385-83dd-5f7246565db3n%40googlegroups.com.