albrow / fo

An experimental language which adds functional programming features to Go.
Other
1.24k stars 34 forks source link

Alternative generic syntax discussion #10

Open maxekman opened 6 years ago

maxekman commented 6 years ago

IMO it would be easier to read code which uses < and > instead of [ and ]. Have you considered it during the design? What is the reason behind the current choice?

My two arguments for < and >:

  1. It is common in other languages.
  2. It is not used elsewhere in Go (I think!?)

(Really cool experiment btw!)

skaldesh commented 6 years ago

To extend this, it would also make it easier to differentiate between slices and the generics.

albrow commented 6 years ago

I first started out by trying to use angled brackets since that is the syntax I was familiar with from other languages. I quickly found that it made the parser too difficult. Consider the following pathological example: f(g<a, b>(c)). You can't differentiate whether the brackets encapsulate type arguments or are part of an expression involving "less than" and "greater than". Go has a simple parser with only single-token lookahead and I wanted to avoid changing it as much as possible.

Square brackets still lead to ambiguity in the parser, but it is much easier to deal with. The expression a[b] can mean either a type argument expression with a single type argument or an index/slice expression. However, that kind of ambiguity is a lot easier to resolve later on because it doesn't effect the overall structure of the AST. In fact, Go already has a really similar ambiguity for function calls and conversions. a(b) can be either a function call with a single argument or a type conversion. In practice, it's not hard to differentiate between the two cases in the type-checker. Additionally, syntax-highlighters and other static analysis tools often don't need to worry about the distinction (because it doesn't change the overall structure).

Other languages such as Scala and Nim also use square brackets for generics.

All that being said, I don't want to say that the syntax will never change. Feel free to propose alternatives here but try to keep in mind the trade-offs and why I chose square brackets. I'll also mention that I'm probably not going to change the syntax anytime soon. Since this syntax works for now, I'd rather focus on fixing bugs and adding new features.

There are also some relevant comments on Reddit about this issue.

albrow commented 6 years ago

@ohir proposed using special unicode characters. I'm not in favor of this proposal because they are hard to type and can look too similar to other characters.

maxekman commented 6 years ago

That’s a really exhaustive (and understandable) answer, thanks for taking the time!

ohir commented 6 years ago

Lets start with shortened examples (see #12 for more)

func (b Box∘T∘) Map∘U∘ (f func(T) U) Box∘U∘ {}
func (b Box∫T∫) Map∫U∫ (f func(T) U) Box∫U∫ {}
func (b Box⟅T⟆) Map⟅U⟆ (f func(T) U) Box⟅U⟆ {}
func (b Box⟨T⟩) Map⟨U⟩ (f func(T) U) Box⟨U⟩ {}

@NullVoxPopuli (of #12) yes, math angle brackets glyphs are, esp for an old eye and in some fonts, are similar in shape to the parenthesis. That's why I'd shown more possibilities.

@albrow > they are hard to type and can look too similar

> can look too similar The ⟨T⟩ can be mistaken for (T). Though neither ∘T∘ nor ⟅U⟆ nor ∫U∫ in any known to me font can be mistaken for anything else in Go source. Contrary to the [T] especially in usage context. Lets rewrite y.Map[string](strconv.Itoa) to y.Map[MFT](strconv.Itoa) where one who writes knows that MFT stands for MyFancyType, but reader will need to do a trip through sources for this knowledge.

> they are hard to type On linux do on your (x)console (assuming gui/xterm, hence xmodmap, for real console use modmap):

$ xmodmap -e 'keycode 59 = comma less U222b U27e8 U27c5 U222b'
$ xmodmap -e 'keycode 60 = period greater U2218 U27e9 U27c6 U2218'

and voilá - you have all four ⟅ ⟆ ∫ ∘ characters mapped under comma(,<) and period(.>) keys. With AltGr and/or Meta (I put mappings for both above). Try for yourself.

On other platforms are either vimmers who will use maps coming from vim-go (or vim-fo) or non-vimers who will use such mapping in the go (fo) plugins for their IDE – regardless of the OS.

@albrow > I quickly found that it made the parser too difficult. Bag runes come in a pair. But even with a single rune or you need not to take syntactical dances in the parser. Hello, XXI century is calling. Lets go beyond 1960s ASA codes. :)

P.S. For persistent map you may put

keycode 59 = comma less U222b U27e8 U27c5 U222b
keycode 60 = period greater U2218 U27e9 U27c6 U2218

into your ~/.Xmodmap file.

maxekman commented 6 years ago

I’m happy with the answer given, will close this for now. If the time and effort needed to use < and > is available some day I’m all for it!

Feel free to reopen if you want. 😊

albrow commented 6 years ago

@maxekman I'm actually going to re-open this so that it is more obvious for anyone who wants to continue the discussion. I don't want people opening new issues for the same thing and would rather keep the discussion in one place.

albrow commented 6 years ago

@mandolyte asked on #26:

With the go2 generics proposal that is very close to your own experiments (except for the contract part), wondered if you were considering switching to the proposed syntax. It would be nice to have some early way to play with it. Of course, I have little idea of what I'm asking :-)

I have read through the go2 generics proposal. While there are definitely some good ideas in there, I'm not the biggest fan of the proposed syntax. I'm not planning to switch Fo to the proposed syntax at this time, especially since the proposal could change. Once the go2 generics proposal(s) become more mature, it is probably worth taking another look.

albrow commented 6 years ago

@zenhack had this to say on #28 Syntactic ambiguity in generic type declarations:

This is another issue that was raised in the go 2 generics draft design, and was cited as the reason not to use square brackets for type parameters:

https://go.googlesource.com/proposal/+/master/design/go2draft-contracts.md#design-summary-discarded-ideas-why-not-use-1

To summarize: what is the meaning of type Foo [T] int? is it an a generic type which does not actually use its type parameter, or is it an array with size T (where T would have to be a constant)?

Right now fo seems to treat it as an array if T is in scope, or a type parameter otherwise -- which is confusing, and I really don't like that it needs a symbol table to disambiguate.

@alanfo proposed using this syntax instead: type Foo[type T] int

The original gist:

https://gist.github.com/alanfo/72f07362d687f625a958bde1808e0c87#the-syntax-for-declaring-type-parameters