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.

Reply via email to