one of the annoying things you have to deal with as a team member is being assigned an "update" of code written by someone who no longer works for the team. What makes this annoying is possibility of running into code sections that contain "crytic" statements that require lots of effort to understand. After looking at the link you provided my input, based on dealing with cryptic C++ is: Go should not allow cryptic syntax.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAO6k0usA%3D6EdH6mpTPqYnpnEBWNu8GST%2Bam-G2rQEZNPGUPC7A%40mail.gmail.com.
Currently, the type-checker has to distinguish between three kinds of generic parameters:
1. Any type.
2. Any type with `==`.
3. Integer constant.
This list could be extended to include support for _any numeric type_ (with operators like `+`, `-`, ...). This would make it possible to make functions like `Min`, `Max`, and so on.
The identifier after `gen` is then a generic type identifier visible in the whole rest of the function (signature and body).
One of my guidelines for an acceptable generics proposal is that
people can write Min and Max. Your proposal admits that it doesn't
permit that. I think that is a problem. I'm fine with the general
idea of "do 80% of the job" but in practice people really do want to
write Min and Max. I think they are part of the 80% that needs to be
handled, not the 20% that can be omitted.
@Ian, I have been thinking and I’ve come up with a possible solution to yours and some other problems. I’d love to hear your thoughts on it. Note, that this is a very fresh idea.
I’m addressing two problems here:
Inability to do Min
/Max
and other generic numeric functions.
There are a few kinds of generic parameters, but the kind is always implicit. This can be a problem because changing the body of a function can result in a backward-incompatible change, even when the signature remains the same.
Here are the ideas (also described in the proposal now, in the section called ‘Further ideas’).
The kind of a generic parameters is currently completely implicit. Some annotation could be added. One possible syntax could be like this:
gen n
for generic array lengths.gen T
for arbitrary types (convertible to interface{}
).gen eq T
for equalable types (comparable with ==
and usable as map keys).gen num T
for numeric types (with operators like +
, -
, <
, …).Array lengths and arbitrary types can have the same notation because it’s always possible to distinguish them by context. Alternatively, they could be distinguished by capitalization (lower-case for array lengths, upper-case for types).
Syntax-wise, eq
and num
would not be keywords on their own. Rather, gen eq
and gen num
would be two-word keywords.
The syntax is rather ad-hoc, I admit. It’s a very fresh idea, completely open to refinement. However, since there are only four cases, an ad-hoc syntax may actually be the right choice.
It’s also easily extensible with new possible “contracts”, but I’d generally advise against that.
The addition of the num
restriction would actually enable many cool things. First, the Min
/Max
functions:
func Min(x, y gen num T) T {
if x < y {
return x
}
return y
}
It would also be useful for generic math types, like vector and matrices. The matrix example above uses float64
, but it could be generalized to all numeric types.
As an example, let’s take a look at a possible implementation of a 2D vector type:
type Vec2(T) struct {
X, Y T
}
There are no restrictions specified in the type definition. This is because it’s methods and functions that require restrictions, not the types themselves. For example, this String
method requires no restrictions:
func (u Vec2(gen T)) String() string {
return fmt.Sprintf("(%v, %v)", u.X, u.Y)
}
This Eq
method requires the types to be comparable with ==
:
func (u Vec2(gen eq T)) Eq(v Vec2(T)) bool {
return u.X == v.X && u.Y == v.Y
}
But, this Add
method requires the types to be numeric:
func (u Vec2(gen num T)) Add(v Vec2(T)) Vec2(T) {
return Vec2(T){u.X+v.X, u.Y+v.Y}
}
Consequently, Vec2([]float64)
would only have the String
method, Vec2(string)
would have the Eq
method in addition, and Vec2(float64)
, Vec2(int32)
, and so on, would have all the methods.
Yes, the idea basically is to introduce two "contracts" into the system. However, there's no ability to create own contracts and the syntax is very concise and non-disruptive. I believe this would really cover the vast majority of use-cases.
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CA%2Bctqro9o-RAa6QRVCEQ%2BPu_tre%2BCtJQZaP4LbBTB_6LQntWyg%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/176439122.1772.1559317546587%40wamui-hyena.atl.sa.earthlink.net.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/739d147e-162d-14fc-a13a-9e7962f074e2%40mb0.org.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/068a6b44-4c52-73fc-9ac7-fe46b4cdbe1d%40mb0.org.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/11395c55-4cd4-7c35-2f39-77e49b28799a%40mb0.org.
> It at least
feels more like go, syntax-wise, than most, except for the num part,
which seems like an afterthought.It is an afterthought. It wasn't in the original proposal and was invented as a way to enable functions like Min, Max, and so on. But I realized that it actually enables many cool things like various generic math structures, vectors, matrices to work with arbitrary numeric types.It is a special case, but if you try and make it general, you end up with some sort of contracts, which may or may not be what you want, but is what I've been trying to avoid here.
Ian, have you had the time to evaluate the improvements to my proposal (the original one in this thread)? I'd love to hear if it has some more significat shortcomings and know what to think about. Or, if it has no perspective, I'd love to hear why.I know you're busy, so responding with "I haven't had the time yet" is completely understandable.Thanks
On Wed, Jun 5, 2019, 22:18 Robert Engels <ren...@ix.netcom.com> wrote:
-----Original Message-----
>From: Randall O'Reilly <rcore...@gmail.com>
>Sent: Jun 5, 2019 2:33 PM
>To: Robert Engels <ren...@ix.netcom.com>
>Cc: Ian Lance Taylor <ia...@golang.org>, Michal Strba <faifa...@gmail.com>, golang-nuts <golan...@googlegroups.com>
>Subject: Re: [go-nuts] Go 2 generics counterproposal: giving up restricting types
>
>That is a good point of clarification about the specific limitation of this proposal: it specifically reifies the existing Go type system and does NOT enable the generic-ification of arbitrary novel types. If you can build a specialized type out of generic versions of existing Go types, then you’re good, but if you need something entirely different, then this won’t do it. The key question is whether having a really simple and tractable “native types” version of generics solves enough problems, while avoiding the challenges of going “fully generic”, to hit that “Go” minimalism sweet spot..
>
>- Randy
>
>> On Jun 5, 2019, at 1:17 PM, Robert Engels <ren...@ix.netcom.com> wrote:
>>
>> That is not sufficient. You can't require the usage of the built-in map, as specialized maps may have a completely different structure (special hash tables when the keys are ints, or more commonly special CAS techniques for highly concurrent lock-free maps).
>
>--
>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 golan...@googlegroups.com.
Hi Gophers! :)I've been thinking about generics in Go 2 ever since the original contracts proposal and few days ago, ideas finally clicked. One of the main things about this proposal is that it deliberately omits the ability to restrict the set of types a function can work with. This is a limitation, but I hope to convince you that we can still do a vast majority of the things we were missing, when we were missing generics.I'd love to share my proposal with you and engage in a good faith conversation.
Here's what the proposal covers:1. Syntax of a new gen keyword.2. Generic functions.3. Unnamed generic arguments (a.k.a. a way to gve a type to the built-in new function).4. Semantics of generic values (ability to use them as map keys, ...).5. Generic array lengths.6. Reflection and interface{}.
7. Generic types (with two examples: List and Matrix).
I really can’t promise to ever fully evaluate all generics proposals.
Perfectly understandable. I’ll show the benefits without you needing to fully evaluate the proposal then :)
it’s still unusual in Go for a name that appears in a list to become in scope for the rest of the list and for the following body.
Okay, so here is the main benefit of the scoping.
Let’s take this simple function that returns a static array with all elements filled with some provided value.
Here’s how the signature would look in my proposal:
func Filled(gen n, x gen T) [n]T
And here’s how it would look if we had to list the generic arguments in a separate list (feel free to supply gen
with any other word):
func Filled(gen n, T)(x T) [n]T
Now, in this latter version, it’s not really clear how and where the generic type gets inferred. Do I need to specify it manually? Under what circumstances? When is the compiler able to infer it for me? Answers to these questions are not clear.
On the other hand, in my proposal, the answers are very clear: unnamed arguments get specified, everything else gets inferred.
func Filled(gen n, x gen T) [n]T
// ^ ^
// specified inferred
Furthermore, there is never a choice between specifying and inferring a generic type. The signature tells exactly which one the user must do.
One more minor benefit of this syntax is that it eliminates any extra parentheses, keeping the clutter down and parsing easy.
I’ll respond to one more of your concerns.
There is also integer, signed integer, unsigned integer, comparable, ordered, float, complex. One can even think of addable (includes string) and indexable and sliceable.
Sure, we can imagine many ways of dividing types into groups. But just because we can imagine that does not mean we need to.
I would argue that the “number contract” is far more useful than “addable”, “indexable”, or anything else you can imagine.
The “number contract” would include all the number types (int*
, uint*
, float*
, complex*
). Arithmetic and logic operations common to these types would be available. This is a rich set of operations: +
, -
, *
, /
, <
, >
, and so on. Also, all of these types allow using untyped integer constants as their values.
Sure, you wouldn’t be able to put strings in Sum
function with this proposal, but do you really need to do that? I don’t think so.
contract stringer(x T) { var s string = x.String() }
type stringer generic{ contract String() string }
contract adjustable(x T) { var _ T = x.Adjust() x.Apply() }
type adjustable generic{ contract ( Adjust() adjustable Apply() ) }