Dear Developers: You have spent several years on this and I'm impressed by the result, it looks beautiful! I'm stunned.
As you can see from the recent spotlight shown on this syntax, in the meanwhile people have resorted to using unicode characters that sort of look like delimiters but are just part of the variable name, and then parsing them outside of Golang while the compiler doesn't realize the shenanigans that are going on with variable names that have Canadian Aboriginal Syllabics, resulting in a single variable name that looks like ImmutableTreeListᐸElementTᐳ but which contains no angle brackets. (In fact here is what it looks like with angle brackets:ImmutableTreeList<ElementT> , a barely discernible difference.) No one will soon forget this example. I think that reflecting on the importance of visual distinction, the admirable step you have taken moving away from parentheses is not enough: If [ and ] seem to work and can always be parsed unambiguously I would be very humbled and gracious if the designers could please show me me how the various examples and edge cases that have come up over the years would look if gofmt changed [ and ] in these places and, indeed, instead, [_ and _] were the standard format in these spots: 2 characters, an opening bracket followed by an underscore, and an underscore followed by a closing bracket. (Which gofmt could convert these spots into.) The suggestion is meant to resemble a blank spot someone has written in, as on a form. The reason for letting gofmt convert it to that is to let people enter [ and ] at the keyboard, since you have done the hard work of making the spots unambiguous; this saves a character while entering at the keyboard, at the small expense of the formater removing a character from any identifier that happens to start or end with _ when used in that spot and using the short form syntax instead of the full gofmt syntax: in that case the formatter has no way of knowing that they meant to write the sloppy [ form for it to correct to [_ on its own. (Since identifiers may, of course, both begin and end with an underscore themselves.) *Edge Cases Because Identifiers may begin or end with an undscore (or both) * This allowance would in fact make _int_ wholly ambiguous: it could be a variable named _int_, or a type named int depending on where in the code it occurred. (If it occurred in an array index position it would refer to a variable.) However, you have ensured that in fact the syntax itself makes these positions totally distinct even without the visual difference. (And not many variables are being used which both begin and end in a _.) Therefore at the spots where you have parsed [] as a generic, if someone were to enter [_int_] at the keyboard, it would be considered only as int - for something named _int you would have to enter [__int_] and for something named int_ you would have to enter [_int__], both of which seem pretty clear to me and an edge case that would not often come up.) Supposing that the user were allowed to continue to enter [ and ] on the keyboard, since you have made the syntax unambiguous to the compiler in these spots, gofmt would turn them into [_ and _] wherever they refer to the generic syntax. The constraint behind choosing [_ and _] is that it is visually distinct - always important for programmers - and unambiguous. It is within the character set easily accessible by programmers and which Go already understands, and all Go programmers use ['s and _'s all the time. Nobody looking at code with [_ _] can ever suppose it is anything other than a new syntax. Look at the following and imagine that the [_ _] is like a form into which someone has entered with a typewriter: using () using [_ _] func f((T(int)) func f(T[_int_]) struct{ (T(int)) } struct{ T[_int_] } interface{ (T(int)) } interface{ T[_int_] } [](T(int)){} []T[_int_]{} I don't like different things to look the same. [ and ] look the same as an array index. They aren't an array index, so they shouldn't look like an array index. But if you clever coders have made it so that it is unambiguous to the compiler when you mean to use the generic syntax, though you've written an opening or closing array limiter, then by all means let the programmer save having to search around for _ and allow them to use a bracket for gofmt to convert later. The reference says: Array types are always one-dimensional but may be composed to form multi-dimensional types. [32]byte [2*N] struct { x, y int32 } [1000]*float64 [3][5]int [2][2][2]float64 // same as [2]([2]([2]float64)) Look at that final example! [2][2][2] I think that it would be unforutnately if some of those [ and ['s in some contexts can end up enclosing a type, and in other contexts enclose a value, depending on where you are in the parse tree, and for the programmer to never realize what is going on. For all of these reasons I would greatly appreciate if you would show me all the possible edge cases you've discovered for types. I would like to know whether the [_int_] notation would look beautiful for all of them. To me it is orthogonal; uses the character set used by all versions of Go since the very beginning; breaks any Go version that doesn't know about them; looks easy on the eye; and can be checked for intent by the Go formatter, gofmt How would it look at the edges? Please let me know by filling out this form: [__] 2020. július 14., kedd 23:56:01 UTC+2 időpontban gri a következőt írta: > > We have received a variety of feedback on the generics draft design > <https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-contracts.md> > > (blog <https://blog.golang.org/generics-next-step>). Thanks to everyone > who took the time to read it, play with generics code in the playground > <https://go2goplay.golang.org/>, file issues, and send us their thoughts. > > Not unexpectedly, many people raised concerns about the syntax, > specifically the choice of parentheses for type parameter declarations and > generic type and function instantiations. > > A typical computer keyboard provides four easily accessible pairs of > single-character symmetrical "brackets": parentheses ( and ), square > brackets [ and ], curly braces { and }, and angle brackets < and >. Go uses > curly braces to delineate code blocks, composite literals, and some > composite types, making it virtually impossible to use them for generics > without severe syntactic problems. Angle brackets require unbounded parser > look-ahead or type information in certain situations (see the end of this > e-mail for an example). This leaves us with parentheses and square > brackets. Unadorned square brackets cause ambiguities in type declarations > of arrays and slices, and to a lesser extent when parsing index > expressions. Thus, early on in the design, we settled on parentheses as > they seemed to provide a Go-like feel and appeared to have the fewest > problems. > > As it turned out, to make parentheses work well and for > backward-compatibility, we had to introduce the type keyword in type > parameter lists. Eventually, we found additional parsing ambiguities in > parameter lists, composite literals, and embedded types which required more > parentheses to resolve them. Still, we decided to proceed with parentheses > in order to focus on the bigger design issues. > > The time has come to revisit this early decision. If square brackets alone > are used to declare type parameters, the array declaration > > type A [N]E > > cannot be distinguished from the generic type declaration > > type A[N] E > > But if we are comfortable with the extra type keyword, the ambiguity > disappears: > > type A[type N] E > > (When we originally dismissed square brackets, the type keyword was not > yet on the table.) > > Furthermore, the ambiguities that arise with parentheses appear not to > arise with square brackets. Here are some examples where extra parentheses > are not needed with square brackets: > > using () using [] > > func f((T(int)) func f(T[int]) > > struct{ (T(int)) } struct{ T[int] } > > interface{ (T(int)) } interface{ T[int] } > > [](T(int)){} []T[int]{} > > To test this better understanding, and to get a feel for this alternative > notation, we will begin to make changes to our prototype implementation > such that it accepts either parentheses or square brackets (only one or the > other) in a generic Go package. Those changes will first appear as commits > to the dev.go2go branch > <https://go.googlesource.com/go/+/refs/heads/dev.go2go>, and eventually > in the playground <https://go2goplay.golang.org/>. > > If square brackets don't lead to unforeseen issues, we have another fully > explored notation to choose from, which will allow us to make a more > informed decision. > > - gri, iant > > PS: For ambiguities with angle brackets consider the assignment > > a, b = w < x, y > (z) > > Without type information, it is impossible to decide whether the > right-hand side of the assignment is a pair of expressions > > (w < x), (y > (z)) > > or whether it is a generic function invocation that returns two result > values > > (w<x, y>)(z) > > In Go, type information is not available at compile time. For instance, in > this case, any of the identifiers may be declared in another file that has > not even been parsed yet. > -- 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/85e3c09c-6fe3-40da-be3f-0cd6cb677eeco%40googlegroups.com.