Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upproposal: spec: generic programming facilities #15292
Comments
adg
added
Go2
Proposal
labels
Apr 14, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
gopherbot
commented
Apr 14, 2016
|
CL https://golang.org/cl/22057 mentions this issue. |
pushed a commit
to golang/proposal
that referenced
this issue
Apr 14, 2016
ianlancetaylor
added this to the Proposal milestone
Apr 14, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
bradfitz
Apr 14, 2016
Member
Let me preemptively remind everybody of our https://golang.org/wiki/NoMeToo policy. The emoji party is above.
|
Let me preemptively remind everybody of our https://golang.org/wiki/NoMeToo policy. The emoji party is above. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
egonelbre
Apr 14, 2016
Contributor
There is Summary of Go Generics Discussions, which tries to provide an overview of discussions from different places. It also provides some examples how to solve problems, where you would want to use generics.
|
There is Summary of Go Generics Discussions, which tries to provide an overview of discussions from different places. It also provides some examples how to solve problems, where you would want to use generics. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
tamird
Apr 14, 2016
Contributor
There are two "requirements" in the linked proposal that may complicate the implementation and reduce type safety:
- Define generic types based on types that are not known until they are instantiated.
- Do not require an explicit relationship between the definition of a generic type or function and its use. That is, programs should not have to explicitly say type T implements generic G.
These requirements seem to exclude e.g. a system similar to Rust's trait system, where generic types are constrained by trait bounds. Why are these needed?
|
There are two "requirements" in the linked proposal that may complicate the implementation and reduce type safety:
These requirements seem to exclude e.g. a system similar to Rust's trait system, where generic types are constrained by trait bounds. Why are these needed? |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
sbunce
Apr 14, 2016
It becomes tempting to build generics into the standard library at a very low level, as in C++ std::basic_string<char, std::char_traits, std::allocator >. This has its benefits—otherwise nobody would do it—but it has wide-ranging and sometimes surprising effects, as in incomprehensible C++ error messages.
The problem in C++ arises from type checking generated code. There needs to be an additional type check before code generation. The C++ concepts proposal enables this by allowing the author of generic code to specify the requirements of a generic type. That way, compilation can fail type checking before code generation and simple error messages can be printed. The problem with C++ generics (without concepts) is that the generic code is the specification of the generic type. That's what creates the incomprehensible error messages.
Generic code should not be the specification of a generic type.
sbunce
commented
Apr 14, 2016
The problem in C++ arises from type checking generated code. There needs to be an additional type check before code generation. The C++ concepts proposal enables this by allowing the author of generic code to specify the requirements of a generic type. That way, compilation can fail type checking before code generation and simple error messages can be printed. The problem with C++ generics (without concepts) is that the generic code is the specification of the generic type. That's what creates the incomprehensible error messages. Generic code should not be the specification of a generic type. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ianlancetaylor
Apr 14, 2016
Contributor
@tamird It is an essential feature of Go's interface types that you can define a non-interface type T and later define an interface type I such that T implements I. See https://golang.org/doc/faq#implements_interface . It would be inconsistent if Go implemented a form of generics for which a generic type G could only be used with a type T that explicitly said "I can be used to implement G."
I'm not familiar with Rust, but I don't know of any language that requires T to explicitly state that it can be used to implement G. The two requirements you mention do not mean that G can not impose requirements on T, just as I imposes requirements on T. The requirements just mean that G and T can be written independently. That is a highly desirable feature for generics, and I can not imagine abandoning it.
|
@tamird It is an essential feature of Go's interface types that you can define a non-interface type T and later define an interface type I such that T implements I. See https://golang.org/doc/faq#implements_interface . It would be inconsistent if Go implemented a form of generics for which a generic type G could only be used with a type T that explicitly said "I can be used to implement G." I'm not familiar with Rust, but I don't know of any language that requires T to explicitly state that it can be used to implement G. The two requirements you mention do not mean that G can not impose requirements on T, just as I imposes requirements on T. The requirements just mean that G and T can be written independently. That is a highly desirable feature for generics, and I can not imagine abandoning it. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
alex
Apr 14, 2016
@ianlancetaylor https://doc.rust-lang.org/book/traits.html explains Rust's traits. While I think they're a good model in general, they would be a bad fit for Go as it exists today.
alex
commented
Apr 14, 2016
|
@ianlancetaylor https://doc.rust-lang.org/book/traits.html explains Rust's traits. While I think they're a good model in general, they would be a bad fit for Go as it exists today. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ianlancetaylor
Apr 14, 2016
Contributor
@sbunce I also thought that concepts were the answer, and you can see the idea scattered through the various proposals before the last one. But it is discouraging that concepts were originally planned for what became C++11, and it is now 2016, and they are still controversial and not particularly close to being included in the C++ language.
|
@sbunce I also thought that concepts were the answer, and you can see the idea scattered through the various proposals before the last one. But it is discouraging that concepts were originally planned for what became C++11, and it is now 2016, and they are still controversial and not particularly close to being included in the C++ language. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
joho
Apr 14, 2016
Would there be value on the academic literature for any guidance on evaluating approaches?
The only paper I've read on the topic is Do developers benefit from generic types? (paywall sorry, you might google your way to a pdf download) which had the following to say
Consequently, a conservative interpretation of the experiment
is that generic types can be considered as a tradeoff
between the positive documentation characteristics and the
negative extensibility characteristics. The exciting part of
the study is that it showed a situation where the use of a
(stronger) static type system had a negative impact on the
development time while at the same time the expected bene-
fit – the reduction of type error fixing time – did not appear.
We think that such tasks could help in future experiments in
identifying the impact of type systems.
I also see #15295 also references Lightweight, flexible object-oriented generics.
If we were going to lean on academia to guide the decision I think it would be better to do an up front literature review, and probably decide early if we would weigh empirical studies differently from ones relying on proofs.
joho
commented
Apr 14, 2016
|
Would there be value on the academic literature for any guidance on evaluating approaches? The only paper I've read on the topic is Do developers benefit from generic types? (paywall sorry, you might google your way to a pdf download) which had the following to say
I also see #15295 also references Lightweight, flexible object-oriented generics. If we were going to lean on academia to guide the decision I think it would be better to do an up front literature review, and probably decide early if we would weigh empirical studies differently from ones relying on proofs. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
benjamingr
Apr 14, 2016
Please see: http://dl.acm.org/citation.cfm?id=2738008 by Barbara Liskov:
The support for generic programming in modern object-oriented programming languages is awkward and lacks desirable expressive power. We introduce an expressive genericity mechanism that adds expressive power and strengthens static checking, while remaining lightweight and simple in common use cases. Like type classes and concepts, the mechanism allows existing types to model type constraints retroactively. For expressive power, we expose models as named constructs that can be defined and selected explicitly to witness constraints; in common uses of genericity, however, types implicitly witness constraints without additional programmer effort.
I think what they did there is pretty cool - I'm sorry if this is the incorrect place to stop but I couldn't find a place to comment in /proposals and I didn't find an appropriate issue here.
benjamingr
commented
Apr 14, 2016
|
Please see: http://dl.acm.org/citation.cfm?id=2738008 by Barbara Liskov:
I think what they did there is pretty cool - I'm sorry if this is the incorrect place to stop but I couldn't find a place to comment in /proposals and I didn't find an appropriate issue here. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
larsth
Apr 15, 2016
It could be interesting to have one or more experimental transpilers - a Go generics source code to Go 1.x.y source code compiler.
I mean - too much talk/arguments-for-my-opinion, and no one is writing source code that try to implement some kind of generics for Go.
Just to get knowledge and experience with Go and generics - to see what works and what doesn't work.
If all Go generics solutions aren't really good, then; No generics for Go.
larsth
commented
Apr 15, 2016
|
It could be interesting to have one or more experimental transpilers - a Go generics source code to Go 1.x.y source code compiler. Just to get knowledge and experience with Go and generics - to see what works and what doesn't work. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
michael-schaller
Apr 15, 2016
Contributor
Can the proposal also include the implications on binary size and memory footprint? I would expect that there will be code duplication for each concrete value type so that compiler optimizations work on them. I hope for a guarantee that there will be no code duplication for concrete pointer types.
|
Can the proposal also include the implications on binary size and memory footprint? I would expect that there will be code duplication for each concrete value type so that compiler optimizations work on them. I hope for a guarantee that there will be no code duplication for concrete pointer types. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mandolyte
Apr 16, 2016
I offer a Pugh Decision matrix. My criteria include perspicuity impacts (source complexity, size). I also forced ranked the criteria to determine the weights for the criteria. Your own may vary of course. I used "interfaces" as the default alternative and compared this to "copy/paste" generics, template based generics (I had in mind something like how D language works), and something I called runtime instantiation style generics. I'm sure this is a vast over simplification. Nonetheless, it may spark some ideas on how to evaluate choices... this should be a public link to my Google Sheet, here
mandolyte
commented
Apr 16, 2016
|
I offer a Pugh Decision matrix. My criteria include perspicuity impacts (source complexity, size). I also forced ranked the criteria to determine the weights for the criteria. Your own may vary of course. I used "interfaces" as the default alternative and compared this to "copy/paste" generics, template based generics (I had in mind something like how D language works), and something I called runtime instantiation style generics. I'm sure this is a vast over simplification. Nonetheless, it may spark some ideas on how to evaluate choices... this should be a public link to my Google Sheet, here |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
benjamingr
Apr 16, 2016
Pinging @yizhouzhang and @andrewcmyers so they can voice their opinions about genus like generics in Go. It sounds like it could be a good match :)
benjamingr
commented
Apr 16, 2016
|
Pinging @yizhouzhang and @andrewcmyers so they can voice their opinions about genus like generics in Go. It sounds like it could be a good match :) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
andrewcmyers
Apr 16, 2016
The generics design we came up with for Genus has static, modular type checking, does not require predeclaring that types implement some interface, and comes with reasonable performance. I would definitely look at it if you're thinking about generics for Go. It does seem like a good fit from my understanding of Go.
Here is a link to the paper that doesn't require ACM Digital Library access:
http://www.cs.cornell.edu/andru/papers/genus/
The Genus home page is here: http://www.cs.cornell.edu/projects/genus/
We haven't released the compiler publicly yet, but we are planning to do that fairly soon.
Happy to answer any questions people have.
andrewcmyers
commented
Apr 16, 2016
•
|
The generics design we came up with for Genus has static, modular type checking, does not require predeclaring that types implement some interface, and comes with reasonable performance. I would definitely look at it if you're thinking about generics for Go. It does seem like a good fit from my understanding of Go. Here is a link to the paper that doesn't require ACM Digital Library access: The Genus home page is here: http://www.cs.cornell.edu/projects/genus/ We haven't released the compiler publicly yet, but we are planning to do that fairly soon. Happy to answer any questions people have. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
andrewcmyers
Apr 16, 2016
In terms of @mandolyte's decision matrix, Genus scores a 17, tied for #1. I would add some more criteria to score, though. For example, modular type checking is important, as others such as @sbunce observed above, but template-based schemes lack it. The technical report for the Genus paper has a much larger table on page 34, comparing various generics designs.
andrewcmyers
commented
Apr 16, 2016
•
|
In terms of @mandolyte's decision matrix, Genus scores a 17, tied for #1. I would add some more criteria to score, though. For example, modular type checking is important, as others such as @sbunce observed above, but template-based schemes lack it. The technical report for the Genus paper has a much larger table on page 34, comparing various generics designs. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
andrewcmyers
Apr 17, 2016
I just went through the whole Summary of Go Generics document, which was a helpful summary of previous discussions. The generics mechanism in Genus does not, to my mind, suffer from the problems identified for C++, Java, or C#. Genus generics are reified, unlike in Java, so you can find out types at run time. You can also instantiate on primitive types, and you don't get implicit boxing in the places you really don't want it: arrays of T where T is a primitive. The type system is closest to Haskell and Rust -- actually a bit more powerful, but I think also intuitive. Primitive specialization ala C# is not currently supported in Genus but it could be. In most cases, specialization can be determined at link time, so true run-time code generation would not be required.
andrewcmyers
commented
Apr 17, 2016
•
|
I just went through the whole Summary of Go Generics document, which was a helpful summary of previous discussions. The generics mechanism in Genus does not, to my mind, suffer from the problems identified for C++, Java, or C#. Genus generics are reified, unlike in Java, so you can find out types at run time. You can also instantiate on primitive types, and you don't get implicit boxing in the places you really don't want it: arrays of T where T is a primitive. The type system is closest to Haskell and Rust -- actually a bit more powerful, but I think also intuitive. Primitive specialization ala C# is not currently supported in Genus but it could be. In most cases, specialization can be determined at link time, so true run-time code generation would not be required. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
gopherbot
commented
Apr 18, 2016
|
CL https://golang.org/cl/22163 mentions this issue. |
pushed a commit
to mk0x9/go
that referenced
this issue
Apr 18, 2016
pushed a commit
that referenced
this issue
Apr 18, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jba
Apr 18, 2016
A way to constrain generic types that doesn't require adding new language concepts: https://docs.google.com/document/d/1rX4huWffJ0y1ZjqEpPrDy-kk-m9zWfatgCluGRBQveQ/edit?usp=sharing.
jba
commented
Apr 18, 2016
|
A way to constrain generic types that doesn't require adding new language concepts: https://docs.google.com/document/d/1rX4huWffJ0y1ZjqEpPrDy-kk-m9zWfatgCluGRBQveQ/edit?usp=sharing. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jimmyfrasche
Apr 18, 2016
Member
Genus looks really cool and it's clearly an important advancement of the art, but I don't see how it would apply to Go. Does anyone have a sketch of how it would integrate with the Go type system/philosophy?
|
Genus looks really cool and it's clearly an important advancement of the art, but I don't see how it would apply to Go. Does anyone have a sketch of how it would integrate with the Go type system/philosophy? |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
sprstnd
Apr 27, 2016
The issue is the go team is stonewalling attempts. The title clearly states the intentions of the go team. And if that wasn't enough to deter all takers, the features demanded of such a broad domain in the proposals by ian make it clear that if you want generics then they don't want you. It is asinine to even attempt dialog with the go team. To those looking for generics in go, I say fracture the language. Begin a new journey- many will follow. I've already seen some great work done in forks. Organize yourselves, rally around a cause
sprstnd
commented
Apr 27, 2016
|
The issue is the go team is stonewalling attempts. The title clearly states the intentions of the go team. And if that wasn't enough to deter all takers, the features demanded of such a broad domain in the proposals by ian make it clear that if you want generics then they don't want you. It is asinine to even attempt dialog with the go team. To those looking for generics in go, I say fracture the language. Begin a new journey- many will follow. I've already seen some great work done in forks. Organize yourselves, rally around a cause |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
andrewcmyers
Apr 27, 2016
If anyone wants to try to work up a generics extension to Go based on the Genus design, we are happy to help. We don't know Go well enough to produce a design that harmonizes with the existing language. I think the first step would be a straw-man design proposal with worked-out examples.
andrewcmyers
commented
Apr 27, 2016
|
If anyone wants to try to work up a generics extension to Go based on the Genus design, we are happy to help. We don't know Go well enough to produce a design that harmonizes with the existing language. I think the first step would be a straw-man design proposal with worked-out examples. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mandolyte
Apr 28, 2016
@andrewcmyers hoping that @ianlancetaylor will work with you on that. Just having some examples to look at would help a lot.
mandolyte
commented
Apr 28, 2016
|
@andrewcmyers hoping that @ianlancetaylor will work with you on that. Just having some examples to look at would help a lot. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
DeedleFake
Sep 7, 2018
Even better, all of that can technically be done in Go right now, but only with a near complete loss of compile-time type-safety and with some, potentially major, runtime overhead. Generics let you do it without either of those downsides.
DeedleFake
commented
Sep 7, 2018
|
Even better, all of that can technically be done in Go right now, but only with a near complete loss of compile-time type-safety and with some, potentially major, runtime overhead. Generics let you do it without either of those downsides. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
hantuo
Sep 7, 2018
Generic function implementation:
/*
* "generic" is a KIND of types, just like "struct", "map", "interface", etc...
* "T" is a generic type (a type of kind generic).
* var t = T{int} is a value of type T, values of generic types looks like a "normal" type
*/
type T generic {
int
float64
string
}
func Sum(a, b T{}) T{} {
return a + b
}Function caller:
Sum(1, 1) // 2
// same as:
Sum(T{int}(1), T{int}(1)) // 2Generic struct implementation:
type ItemT generic {
interface{}
}
type List struct {
l []ItemT{}
}
func NewList(t ItemT) *List {
l := make([]t)
return &List{l}
}
func (p *List) Push(item ItemT{}) {
p.l = append(p.l, item)
}Caller:
list := NewList(ItemT{int})
list.Push(42)
hantuo
commented
Sep 7, 2018
|
Generic function implementation: /*
* "generic" is a KIND of types, just like "struct", "map", "interface", etc...
* "T" is a generic type (a type of kind generic).
* var t = T{int} is a value of type T, values of generic types looks like a "normal" type
*/
type T generic {
int
float64
string
}
func Sum(a, b T{}) T{} {
return a + b
}Function caller: Sum(1, 1) // 2
// same as:
Sum(T{int}(1), T{int}(1)) // 2Generic struct implementation: type ItemT generic {
interface{}
}
type List struct {
l []ItemT{}
}
func NewList(t ItemT) *List {
l := make([]t)
return &List{l}
}
func (p *List) Push(item ItemT{}) {
p.l = append(p.l, item)
}Caller: list := NewList(ItemT{int})
list.Push(42) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jlubawy
Sep 14, 2018
As someone just learning Swift and not liking it, but with plenty of experience in other languages like Go, C, Java, etc; I really believe that generics (or templating, or whatever you want to call it) is not a good thing to add to the Go language.
Maybe I'm just more experienced with the current version of Go but to me this feels like a regression to C++ in that it is more difficult to understand code that other people have written. The classic T placeholder for types makes it so difficult to understand what a function is trying to do.
I know this is a popular feature request so I can deal with it if it lands, but I wanted to add my 2 cents (opinion).
jlubawy
commented
Sep 14, 2018
|
As someone just learning Swift and not liking it, but with plenty of experience in other languages like Go, C, Java, etc; I really believe that generics (or templating, or whatever you want to call it) is not a good thing to add to the Go language. Maybe I'm just more experienced with the current version of Go but to me this feels like a regression to C++ in that it is more difficult to understand code that other people have written. The classic T placeholder for types makes it so difficult to understand what a function is trying to do. I know this is a popular feature request so I can deal with it if it lands, but I wanted to add my 2 cents (opinion). |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
keean
Sep 14, 2018
@jlubawy
Do you know another way that I never have to implement a linked list or quicksort algorithm? As Alexander Stepanov points out most programmers cannot correctly define the "min" and "max" functions so what hope do we have to correctly implement more complex algorithms without lots of debugging time. I would much rather pull standard versions of these algorithms out of a library and just apply to the types I have. What alternative is there?
keean
commented
Sep 14, 2018
|
@jlubawy |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
creker
Sep 14, 2018
or templating, or whatever you want to call it
Everything depends on the implementation. if we're talking about C++ templates then yes, they're difficult to understand in general. Even writing them is difficult. On the other hand, if we take C# generics then that's whole another thing completely. The concept itself is not a problem here.
creker
commented
Sep 14, 2018
Everything depends on the implementation. if we're talking about C++ templates then yes, they're difficult to understand in general. Even writing them is difficult. On the other hand, if we take C# generics then that's whole another thing completely. The concept itself is not a problem here. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
yookoala
Sep 14, 2018
If you didn't know, the Go Team has announced a draft of Go 2.0:
https://golang.org/s/go2designs
There is a draft to the Generics design in Go 2.0 (contract). You may want to take a look and give feedback on their Wiki.
This the relevant section:
Generics
yookoala
commented
Sep 14, 2018
•
|
If you didn't know, the Go Team has announced a draft of Go 2.0: There is a draft to the Generics design in Go 2.0 (contract). You may want to take a look and give feedback on their Wiki. This the relevant section: Generics |
bcmills
referenced this issue
Sep 14, 2018
Closed
proposal: sync/atomic: add Swap, CompareAndSwap #26728
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
luismasuelli-jobsity
Sep 17, 2018
luismasuelli-jobsity
commented
Sep 17, 2018
|
After reading the draft, I ask:
Why
T:Addable
means "a type T implementing the contract Addable"? Why adding a new
concept when we already have INTERFACES for that? Interfaces assignment is
checked in build time, so we already have the means to not need any
additional concept here. We can use this term to say something like: Any
type T implementing the interface Addable. Additionally, T:_ or T:Any
(being Any a special keyword or a built-in alias of interface{}) would do
the trick.
Just I don't know why to reimplement most of the stuff like that. Makes no
sense and WILL be redundant (as redundant is the new handling of errors wrt
the handling of panics).
2018-09-14 6:15 GMT-05:00 Koala Yeung <notifications@github.com>:
… If you didn't know, the Go Team has announced a draft of Go 2.0:
https://golang.org/s/go2designs
There is a draft to the Generics design in Go 2.0 (contract). You may want
to take a look and give feedback
<https://github.com/golang/go/wiki/Go2GenericsFeedback> on their Wiki
<https://github.com/golang/go/wiki/Go2GenericsFeedback>.
This the relevant section:
*Generics*
- Overview
<https://go.googlesource.com/proposal/+/master/design/go2draft-generics-overview.md>
- [Draft design] (https://go.googlesource.com/proposal/+/master/design/
go2draft-contracts.md)
- Wiki feedback page
<https://github.com/golang/go/wiki/Go2GenericsFeedback>
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#15292 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AlhWhS8xmN5Y85_aUKT5VnutoOKUAaLLks5ua4_agaJpZM4IG-xv>
.
--
This is a test for mail signatures to be used in TripleMint
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
luismasuelli-jobsity
Sep 17, 2018
luismasuelli-jobsity
commented
Sep 17, 2018
|
Edit: "[...] would do the trick IF YOU NEED NO PARTICULAR REQUIREMENT ON
THE TYPE ARGUMENT".
2018-09-17 11:10 GMT-05:00 Luis Masuelli <luis.masuelli@jobsity.com>:
… After reading the draft, I ask:
Why
T:Addable
means "a type T implementing the contract Addable"? Why adding a new
concept when we already have INTERFACES for that? Interfaces assignment is
checked in build time, so we already have the means to not need any
additional concept here. We can use this term to say something like: Any
type T implementing the interface Addable. Additionally, T:_ or T:Any
(being Any a special keyword or a built-in alias of interface{}) would do
the trick.
Just I don't know why to reimplement most of the stuff like that. Makes no
sense and WILL be redundant (as redundant is the new handling of errors wrt
the handling of panics).
2018-09-14 6:15 GMT-05:00 Koala Yeung ***@***.***>:
> If you didn't know, the Go Team has announced a draft of Go 2.0:
> https://golang.org/s/go2designs
>
> There is a draft to the Generics design in Go 2.0 (contract). You may
> want to take a look and give feedback
> <https://github.com/golang/go/wiki/Go2GenericsFeedback> on their Wiki
> <https://github.com/golang/go/wiki/Go2GenericsFeedback>.
>
> This the relevant section:
>
> *Generics*
>
> - Overview
> <https://go.googlesource.com/proposal/+/master/design/go2draft-generics-overview.md>
> - [Draft design] (https://go.googlesource.com/p
> roposal/+/master/design/go2draft-contracts.md
> <https://go.googlesource.com/proposal/+/master/design/go2draft-contracts.md>
> )
> - Wiki feedback page
> <https://github.com/golang/go/wiki/Go2GenericsFeedback>
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <#15292 (comment)>, or mute
> the thread
> <https://github.com/notifications/unsubscribe-auth/AlhWhS8xmN5Y85_aUKT5VnutoOKUAaLLks5ua4_agaJpZM4IG-xv>
> .
>
--
This is a test for mail signatures to be used in TripleMint
--
This is a test for mail signatures to be used in TripleMint
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
keean
Sep 17, 2018
@luismasuelli-jobsity If I read the history of generic implementations in Go correctly, then it looks like the reason to introduce Contracts is because they did not want operator overloading in Interfaces.
An earlier proposal that was eventually rejected used interfaces to constrain parametric polymorphism, but seems to have been rejected because you could not use common operators like '+' in such functions because it is not definable in an interface. Contracts allow you to write t == t or t + t so you can indicate the type must support equality or addition etc.
Edit: Also Go does not support multiple type parameter interfaces, so in a way Go has separated typeclass into two separate things, Contracts that relate the functions type parameters to each other, and interfaces which supply methods. What it looses is the ability to select a typeclass implementation based on multiple types. It is arguably simpler if you only need to use interfaces or contracts, but more complex if you need to use both together.
keean
commented
Sep 17, 2018
•
|
@luismasuelli-jobsity If I read the history of generic implementations in Go correctly, then it looks like the reason to introduce Contracts is because they did not want operator overloading in Interfaces. An earlier proposal that was eventually rejected used interfaces to constrain parametric polymorphism, but seems to have been rejected because you could not use common operators like '+' in such functions because it is not definable in an interface. Contracts allow you to write Edit: Also Go does not support multiple type parameter interfaces, so in a way Go has separated typeclass into two separate things, Contracts that relate the functions type parameters to each other, and interfaces which supply methods. What it looses is the ability to select a typeclass implementation based on multiple types. It is arguably simpler if you only need to use interfaces or contracts, but more complex if you need to use both together. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
DeedleFake
Sep 17, 2018
Why
T:Addablemeans "a type T implementing the contract Addable"?
That's actually not what it means; it just looks that way for one type argument. Elsewhere in the draft it makes the comment that you can only have one contract per function, and this is where the main difference comes in. Contracts are actually statements about the types of the function, not just the types independently. For example, if you have
func Example(type K, V someContract)(k K, v V) Vyou can do something like
contract someContract(k K, v V) {
k.someMethod(v)
}This vastly simplifies coordinating multiple types without having to redundantly specify the types in the function signature. Remember, they're trying to avoid the 'curiously repeating generic pattern'. For example, the same function with parameterized interfaces used to constrain the types would be something like
type someMethoder(V) interface {
someMethod(V)
}
func Example(type K: someMethoder(V), V)(k K, v V) VThis is kind of awkward. The contract syntax allows you to still do this if you need to, though, because the contract's 'arguments' are auto-filled by the compiler if the contract has the same number of them as the function does type parameters. You can specify them manually if you want to, though, meaning that you could do func Example(type K, V someContract(K, V))(k K, v V) V if you really wanted to, though it's not particularly useful in this situation.
One way of making it clearer that contracts are about entire functions, not individual arguments, would be to simply associate them based on name. For example,
contract Example(k K, v V) {
k.someMethod(v)
}
func Example(type K, V)(k K, v V) Vwould be the same as the above. The downside, however, is that contracts would not be re-usable and you lose that ability to specify the contract's arguments manually.
Edit: To show further why they want to solve the curiously repeating pattern, consider the shortest path problem that they kept referring to. With parameterized interfaces, the definition winds up looking like
type E(Node) interface {
Nodes() []Node
}
type N(Edge) interface {
Edges() (from, to Edge)
}
type Graph(type Node: N(Edge), Edge: E(Node)) struct { ... }
func New(type Node: N(Edge), Edge: E(Node))(nodes []Node) *Graph(Node, Edge) { ... }
func (*Graph(Node, Edge)) ShortestPath(from, to Node) []Edge { ... }
DeedleFake
commented
Sep 17, 2018
•
That's actually not what it means; it just looks that way for one type argument. Elsewhere in the draft it makes the comment that you can only have one contract per function, and this is where the main difference comes in. Contracts are actually statements about the types of the function, not just the types independently. For example, if you have func Example(type K, V someContract)(k K, v V) Vyou can do something like contract someContract(k K, v V) {
k.someMethod(v)
}This vastly simplifies coordinating multiple types without having to redundantly specify the types in the function signature. Remember, they're trying to avoid the 'curiously repeating generic pattern'. For example, the same function with parameterized interfaces used to constrain the types would be something like type someMethoder(V) interface {
someMethod(V)
}
func Example(type K: someMethoder(V), V)(k K, v V) VThis is kind of awkward. The contract syntax allows you to still do this if you need to, though, because the contract's 'arguments' are auto-filled by the compiler if the contract has the same number of them as the function does type parameters. You can specify them manually if you want to, though, meaning that you could do One way of making it clearer that contracts are about entire functions, not individual arguments, would be to simply associate them based on name. For example, contract Example(k K, v V) {
k.someMethod(v)
}
func Example(type K, V)(k K, v V) Vwould be the same as the above. The downside, however, is that contracts would not be re-usable and you lose that ability to specify the contract's arguments manually. Edit: To show further why they want to solve the curiously repeating pattern, consider the shortest path problem that they kept referring to. With parameterized interfaces, the definition winds up looking like type E(Node) interface {
Nodes() []Node
}
type N(Edge) interface {
Edges() (from, to Edge)
}
type Graph(type Node: N(Edge), Edge: E(Node)) struct { ... }
func New(type Node: N(Edge), Edge: E(Node))(nodes []Node) *Graph(Node, Edge) { ... }
func (*Graph(Node, Edge)) ShortestPath(from, to Node) []Edge { ... } |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
DeedleFake
Sep 17, 2018
Personally, I rather like the way that contracts are specified for functions. I'm not too keen on just having 'normal' function bodies as the actual contract specification, but I think a lot of the potential problems could be solved by introducing some kind of gofmt-like simplifier that auto-simplifies contracts for you, removing extraneous parts. Then you could just copy a function body into it, simplify it, and modify it from there. I'm not sure how possible this will be to implement, though, unfortunately.
Some things will still be a bit awkward to specify, though, and the apparent overlap between contracts and interfaces still seems a bit odd.
DeedleFake
commented
Sep 17, 2018
•
|
Personally, I rather like the way that contracts are specified for functions. I'm not too keen on just having 'normal' function bodies as the actual contract specification, but I think a lot of the potential problems could be solved by introducing some kind of gofmt-like simplifier that auto-simplifies contracts for you, removing extraneous parts. Then you could just copy a function body into it, simplify it, and modify it from there. I'm not sure how possible this will be to implement, though, unfortunately. Some things will still be a bit awkward to specify, though, and the apparent overlap between contracts and interfaces still seems a bit odd. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jimmyfrasche
Sep 17, 2018
Member
I find the "CRTP" version much clearer, more explicit, and easier to work with (no need to create contracts that only exist to define the relationship between pre-existing contracts over a set of variables). Admittedly, that could just be the many years of familiarity with the idea.
|
I find the "CRTP" version much clearer, more explicit, and easier to work with (no need to create contracts that only exist to define the relationship between pre-existing contracts over a set of variables). Admittedly, that could just be the many years of familiarity with the idea. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
yookoala
Sep 19, 2018
Clarifications. By the draft design, contract can be applied to both functions and types.
yookoala
commented
Sep 19, 2018
|
Clarifications. By the draft design, contract can be applied to both functions and types. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
luismasuelli-jobsity
Sep 19, 2018
"""
It is arguably simpler if you only need to use interfaces or contracts, but more complex if you need to use both together.
"""
As long as they allow you to, inside a contract, reference one or more interfaces (instead of only operators and functions, thus allowing DRY), this issue (and my claim) will be solved. There is a chance that I misread or did not completely read the contracts stuff, and also a chance that the said feature is supported and I did not notice it. If it isn't, it should be.
luismasuelli-jobsity
commented
Sep 19, 2018
|
""" As long as they allow you to, inside a contract, reference one or more interfaces (instead of only operators and functions, thus allowing DRY), this issue (and my claim) will be solved. There is a chance that I misread or did not completely read the contracts stuff, and also a chance that the said feature is supported and I did not notice it. If it isn't, it should be. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
DeedleFake
Sep 20, 2018
Can't you do the following?
contract Example(t T, v V) {
t.(interface{
SomeMethod() V
})
}You can't use an interface that's declared elsewhere because of the restriction that you can't reference identifiers from the same package as the contract is declared in, but you can do this. Or they could just remove that restriction; it seems a bit arbitrary.
DeedleFake
commented
Sep 20, 2018
|
Can't you do the following? contract Example(t T, v V) {
t.(interface{
SomeMethod() V
})
}You can't use an interface that's declared elsewhere because of the restriction that you can't reference identifiers from the same package as the contract is declared in, but you can do this. Or they could just remove that restriction; it seems a bit arbitrary. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Merovius
Sep 20, 2018
@DeedleFake No, because any interface type can be type-asserted (and then just potentially panic at runtime, but contracts aren't executed). But you can use an assignment instead.
Merovius
commented
Sep 20, 2018
•
|
@DeedleFake No, because any interface type can be type-asserted (and then just potentially panic at runtime, but contracts aren't executed). But you can use an assignment instead. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
DeedleFake
Sep 20, 2018
Good point. Woops.
The more examples of this I see, the more error-prone 'figure it out from a function body' seems to be.
DeedleFake
commented
Sep 20, 2018
|
Good point. Woops. The more examples of this I see, the more error-prone 'figure it out from a function body' seems to be. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jimmyfrasche
Sep 20, 2018
Member
There are lots of cases where it's confusing for a person, same syntax for different operations, shades of implications from different constructs, etc., but a tool would be able to take that and reduce it to a normal form. But then the output of such a tool becomes a de facto sub-language for expressing type constraints that we have to learn by rote, making it all the more surprising when someone deviates and writes a contract by hand.
I'll also note that
contract I(t T) {
var i interface { Foo() }
i = t
t.(interface{})
}
expresses that T must be an interface with at least Foo() but it could also have any other number of additional methods.
|
There are lots of cases where it's confusing for a person, same syntax for different operations, shades of implications from different constructs, etc., but a tool would be able to take that and reduce it to a normal form. But then the output of such a tool becomes a de facto sub-language for expressing type constraints that we have to learn by rote, making it all the more surprising when someone deviates and writes a contract by hand. I'll also note that
expresses that |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
DeedleFake
Sep 20, 2018
Tmust be an interface with at leastFoo()but it could also have any other number of additional methods
Is that a problem, though? Don't you usually want to constrain things so that they allow specific functionality but you don't care about other functionality? Otherwise a contract like
contract Example(t T) {
t + t
}wouldn't allow subtraction, for example. But from the point of view whatever I'm implementing, I don't care if a type allows subtraction or not. If I restricted it from being able to perform subtraction, then people would just arbitrarily not be able, to for example, pass anything that does to a Sum() function or something. That seems arbitrarily restrictive.
DeedleFake
commented
Sep 20, 2018
Is that a problem, though? Don't you usually want to constrain things so that they allow specific functionality but you don't care about other functionality? Otherwise a contract like contract Example(t T) {
t + t
}wouldn't allow subtraction, for example. But from the point of view whatever I'm implementing, I don't care if a type allows subtraction or not. If I restricted it from being able to perform subtraction, then people would just arbitrarily not be able, to for example, pass anything that does to a |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jimmyfrasche
Sep 20, 2018
Member
No, it's not a problem at all. It was just an unintuitive (to me) property, but perhaps that was due to insufficient coffee.
|
No, it's not a problem at all. It was just an unintuitive (to me) property, but perhaps that was due to insufficient coffee. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
yookoala
Sep 21, 2018
Its fair to say that the current contract declaration need to have better compiler messages to work with. And the rules for a valid contract should be strict.
yookoala
commented
Sep 21, 2018
|
Its fair to say that the current contract declaration need to have better compiler messages to work with. And the rules for a valid contract should be strict. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
surlykke
Sep 30, 2018
Hi
I made a proposal for constraints for generics that i posted in this thread about ½ a year ago.
Now I've made a version 2. The main changes are:
- The syntax has been adapted to the one proposed by the go-team.
- Constraining by fields have been omitted, which allows for quite a bit of simplifications.
- Paragraphs deemed not strictly necessary has been taken out.
surlykke
commented
Sep 30, 2018
|
Hi
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Merovius
Oct 8, 2018
I thought of an interesting (but maybe more detailed than appropriate at this stage in the design?) question regarding type identity recently:
func Foo() interface{} {
type S struct {}
return S{}
}
func Bar(type T)() interface{} {
type S struct {}
return S{}
}
func Baz(type T)() interface{} {
type S struct{t T}
return S{}
}
func main() {
fmt.Println(Foo() == Foo()) // 1
fmt.Println(Bar(int)() == Bar(string)()) // 2
fmt.Println(Baz(int)() == Baz(string)()) // 3
}
- Prints
true, because the types of the returned values are originating in the same type declaration. - Prints…?
- Prints
false, I assume.
i.e. the question is, when two types declared in a generic function are identical and when they aren't. I don't think this is described in the spec design? At least I can't find it right now :)
Merovius
commented
Oct 8, 2018
•
|
I thought of an interesting (but maybe more detailed than appropriate at this stage in the design?) question regarding type identity recently:
i.e. the question is, when two types declared in a generic function are identical and when they aren't. I don't think this is described in the |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
keean
Oct 9, 2018
@Merovius I assume the middle case was supposed to be:
fmt.Println(Bar(int)() == Bar(int)()) // 2This is an interesting case, and it depends on whether types are "generative" or "applicative". There are actually to variants of ML that take different approaches. Applicative types view the generic as a type function, and hence f(int) == f(int). Generative types view the generic as a type template that creates a new unique 'instance' type each time it is used so t<int> != t<int>. This must be approached at a whole type-system level as it has subtle implications for unification, inference and soundness. For further details and examples of then kind of problems I recommend reading Andreas Rossberg's "F-ing modules" paper: https://people.mpi-sws.org/~rossberg/f-ing/ although the paper is talking about ML "functors" this is because ML separates its type system into two levels, and functors are MLs equivalent of a generic and are only available at the module level.
keean
commented
Oct 9, 2018
•
|
@Merovius I assume the middle case was supposed to be: fmt.Println(Bar(int)() == Bar(int)()) // 2This is an interesting case, and it depends on whether types are "generative" or "applicative". There are actually to variants of ML that take different approaches. Applicative types view the generic as a type function, and hence f(int) == f(int). Generative types view the generic as a type template that creates a new unique 'instance' type each time it is used so t<int> != t<int>. This must be approached at a whole type-system level as it has subtle implications for unification, inference and soundness. For further details and examples of then kind of problems I recommend reading Andreas Rossberg's "F-ing modules" paper: https://people.mpi-sws.org/~rossberg/f-ing/ although the paper is talking about ML "functors" this is because ML separates its type system into two levels, and functors are MLs equivalent of a generic and are only available at the module level. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Merovius
commented
Oct 9, 2018
|
@keean You assume wrong. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
keean
Oct 9, 2018
@Merovius Yes, my mistake, I see the question is because the type parameter is not used (a phantom type).
With generative types, each instantiation would result in a different unique type for 'S', so even though the parameter is not used, they would not be equal.
With applicative types, the 'S' from each instantiation would be the same type, and so they would be equal.
keean
commented
Oct 9, 2018
|
@Merovius Yes, my mistake, I see the question is because the type parameter is not used (a phantom type). With generative types, each instantiation would result in a different unique type for 'S', so even though the parameter is not used, they would not be equal. With applicative types, the 'S' from each instantiation would be the same type, and so they would be equal. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
carlmjohnson
Oct 9, 2018
Contributor
It would be weird if the result in case 2 changed based on compiler optimizations. Sounds like UB.
|
It would be weird if the result in case 2 changed based on compiler optimizations. Sounds like UB. |
adg commentedApr 14, 2016
This issue proposes that Go should support some form of generic programming.
It has the Go2 label, since for Go1.x the language is more or less done.
Accompanying this issue is a general generics proposal by @ianlancetaylor that includes four specific flawed proposals of generic programming mechanisms for Go.
The intent is not to add generics to Go at this time, but rather to show people what a complete proposal would look like. We hope this will be of help to anyone proposing similar language changes in the future.