Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The block parameter syntax ("|x|") might be misinterpreted as "a pipe through x"? #25

Closed
practicalswift opened this issue Dec 15, 2014 · 32 comments

Comments

@practicalswift
Copy link
Contributor

The similarity between the flow operator (|) and the block parameter syntax (|x|) will probably be a source of some confusion since |x| can be misinterpreted as "a pipe through x".

The problem is not the flow operator (|). On the contrary – using the pipe as the flow operator conveys the meaning very intuitively for everyone who has ever used a shell, so let's keep that very good choice.

Instead I suggest switching from |x| to say (x) ->, (x) or x -> to denote block parameters.

The (…) -> alternative is implemented here: https://github.com/practicalswift/streem/commit/193fa8413d14dce03d609ec597006a40ca678ec1

Reasoning:

  • (parameter1, parameter2, parameter3, …) should be familiar to most programmers.
  • -> is used for assignment in the Streem syntax (see op_rasgn in lex.l).

Summary of discussed alternatives:

Alternative 1 (current syntax).

seq(100) | { |x|
  if x % 15 == 0 {
    "FizzBuzz"
  }
...
} | STDOUT

Alternative 2 (implemented here: https://github.com/practicalswift/streem/commit/193fa8413d14dce03d609ec597006a40ca678ec1).

seq(100) | { (x) ->
  if x % 15 == 0 {
    "FizzBuzz"
  }
...
} | STDOUT

Alternative 3.

seq(100) | { (x)
  if x % 15 == 0 {
    "FizzBuzz"
  }
...
} | STDOUT

Alternative 4.

seq(100) | { x ->
  if x % 15 == 0 {
    "FizzBuzz"
  }
...
} | STDOUT
@alexispurslane
Copy link

👍 for Alt. 4! Heres another idea:
Alternative 5:

seq(100) | (x) -> {
  if x % 15 == 0 {
    "FizzBuzz"
  }
...
} | STDOUT

@nickserv
Copy link
Contributor

I agree, I think it's a lot more clear without |x|. I think I like alternatives 2, 4, and 5 the most so far.

@hhff
Copy link

hhff commented Dec 15, 2014

👍 for Alternatives 2 & 5

@caseycole589
Copy link

I vote 1 & 3

On Mon, Dec 15, 2014 at 4:34 PM, Hugh Francis [email protected]
wrote:

[image: 👍] for Alternatives 2 & 5


Reply to this email directly or view it on GitHub
#25 (comment).

@ekg
Copy link

ekg commented Dec 15, 2014

I don't understand the { |x| ... } syntax. Should we understand this to be an anonymous (stream-oriented) function? If so, the syntax for function definition, anonymous function definition, and this example should be harmonized.

@acangiano
Copy link

3 is the most ruby-like among the alternatives. I like it.

@matz
Copy link
Owner

matz commented Dec 15, 2014

I feel same way, and agree to change. But I am afraid that alternatives in OP cause shift/reduce conflict. I am thinking of ->x{...} as function objects/blocks.

FYI, op_rasgn is not mandatory. we can remove it.

@tbodt
Copy link

tbodt commented Dec 16, 2014

If op_rasgn was removed, how would you use variables? (I don't think you can have a programming language without variables.)

@matz
Copy link
Owner

matz commented Dec 16, 2014

you can assign using =, e.g. s = socket.accept(), instead of socket.accept() -> s.

@alexispurslane
Copy link

@acangiano why are we trying to be like Ruby? Sure, Matz designed ruby, but that doesn't mean everything that has anything to do with him should look like Ruby. Also, I am in favor of keeping the op_rasgn for assignments, as that is in keeping with the stream-oriented idea. So how about another alternative?
Alt. 6:

seq(100) | (x) => {
  if x % 15 == 0 {
    "FizzBuzz"
  }
...
} | STDOUT

That seems still in keeping with most other languages, (including CoffeeScript and ES6), and wouldn't lead to any shift/reduce conflicts. Also, I do thing that #26 would be something to think about as far as shorthand for transforming and filtering streams.

@practicalswift
Copy link
Contributor Author

What about simplifying the syntax further and introducing shorthand argument names $0, $1, $2, etc:

Alternative 7.

seq(100) | {
  if $0 % 15 == 0 {
    "FizzBuzz"
  }
...
} | STDOUT

foo | {
  zip($0, $1)
} | STDOUT

Reasoning:

  • In many cases – and especially when the number of arguments are few – the meaning of $0, $1, etc should be obvious from the preceding command/function (seq(100) in this case).

In cases where argument names are needed for readability the syntax would be a slightly modified version of alternative 3 above to avoid the shift/reduce conflict that @matz mentioned in his comment:

Alternative 8.

seq(100) | (x) {
  if x % 15 == 0 {
    "FizzBuzz"
  }
...
} | STDOUT

foo | (arg1, arg2) {
  zip(arg1, arg2)
} | STDOUT

Reasoning:

  • The (arg1, arg2) { … } can be read as a shorthand for the familiar function_name(arg1, arg2) { … }.

So I suggest to allow for BOTH alternative #7 and alternative #8 depending on if named arguments are required or not :-)

@shouya
Copy link

shouya commented Dec 16, 2014

I like the haskell-like lambda syntax:

seq 1 100 | \x -> length x | print
seq 1 100 | lines | map (\x -> length x) | fold sum | print

Of course if currying is good supported, \x -> length x can be simplified into a sole length. Pretty neat I consider this syntax :)

If a block is wanted, we could take

seq 1 100 | \x -> {
   do something...
} | print

Probably alternative #9? Actually it's just similar to alternative #5.

@Krysl
Copy link

Krysl commented Dec 16, 2014

I don‘t like (arg) to be outside of the {…}.
because if I want to write some codes to calculate 1/1+1/2+…+1/10 and print sum at last like this:

seq(10) | (x) {
  sum += 1/(x)
  {
    print sum
  }
}

It looks like a num divided by a function!
At last,I give a alternative too:

seq(100) | { (x => f b)
  if x % 3 == 0 {
    f = x
  }
  else if x % 5 == 0 {
    b = x
  }
} | { (x y) 
  printf("total fizz:%d\n", count(x))
  printf("total buzz:%d\n", count(y))
}

@mitchellmcmillan
Copy link

@Krysl please edit your comment to mark your code as a code block to make it more readable

@haiyuofow
Copy link

I like alternative 3

@tbodt
Copy link

tbodt commented Dec 17, 2014

👍 alternative 5

@mySingleLive
Copy link

seq(100) | #(x) {
| x % 3 == 0 --> f = x
| x % 5 == 0 --> b = x
} | print

@mySingleLive
Copy link

seq(100) | #{
   | Odd --> f = x
   | Even --> b = x
} | print

@mySingleLive
Copy link

Perhaps the closure parameter can be omitted when there is only one argument

@dbohdan
Copy link
Contributor

dbohdan commented Dec 17, 2014

Alternative 7 can be implemented alongside any other block parameter syntax for when no block parameters are explicitly declared, kind of like Clojure's compact lambda syntax. It would be nice for one-liners. The downside is that it makes a class of typos hard to detect, e.g., if you type $1 instead of $0 on accident how can the interpreter tell if you meant it? For this reason you'd want a more explicit syntax to be there as well for longer scripts.

@alexispurslane
Copy link

👍 Alternative 7 & 5 together. Like in Clojure.

@nickserv
Copy link
Contributor

I liked @tbodt's idea of creating a table of votes in #24, so I'll add one for the alternatives here:

Alternative Votes Syntax Note
1 2 `{ x
2 3 { (x) -> … }
3 4 { (x) … }
4 2 { x -> … }
5 5 (x) -> { … }
6 1 (x) => { … }
7 2 { } parameters are $0, $1, $2, etc.
8 1 (x) { … }
9 1 \x -> { … }

Last updated: this comment.

Sorry if I excluded anyone, I tried to only include votes that were more explicit, and only alternatives that were numbered to make things simpler.

@nickserv
Copy link
Contributor

By the way, in the future, it might be easier to use some sort of wiki and/or poll site to organize alternative ideas. http://poll.gitrun.com seems interesting.

@vtenfys
Copy link

vtenfys commented Dec 21, 2014

I like alternative 3

@matz
Copy link
Owner

matz commented Dec 21, 2014

I am afraid alternatives 2,3,5,6,8 will cause shift-reduce conflict. I like alternative 10, which is

-> x { ... }

similar to Ruby's lambda.

@alexispurslane
Copy link

That might be confusing if you want to assign a lambda to a variable. Alt. 6, 8, and 4 are the least likely to cause conflicts.

@practicalswift
Copy link
Contributor Author

@matz Let's say you decide to go with alternative 10, would you consider also having alternative 7 available? As I see it those should not be mutually exclusive, and I think alternative 7 is proper for quick Streem scripts (c.f. shell scripts) where the number of parameters are few and naming them feels overkill.

Just as the meaning | is immediately obvious to everyone with shell experience (which should be more or less all programmers), I think the numbered arguments ($0, $1, etc.) in alternative 7 has the same intuitive appeal for anyone with shell scripting experience :-)

My suggestion:

  • Alternative 10 (or whichever @matz decides :-)) for named arguments
  • Alternative 7 for unnamed arguments

@s-aida
Copy link

s-aida commented Dec 22, 2014

From a pure standpoint of appearance, I don't like Ruby's lambda syntax at all. Most modern languages go with something like (x) -> {}, and every time I return to write codes in Ruby, the very syntax feels like pretty weird.

So big 👎 10, but 👍 5 (6 is also okay).

Or, once again, the parser of Streem is supposed to be so complicated and chaotic that you can't implement a standard syntax?

@matz
Copy link
Owner

matz commented Dec 22, 2014

@shunsukeaida I don't know how other language works (yet), but when the parser see

(a)->{...}

it's quite difficult for the parser to distinguish (a)-> (beginning of a function object) and (a) (a variable surrounded by parentheses), without shift-reduce conflicts. Other parsers may do precedence tricks, or ignore conflicts.

@alexispurslane
Copy link

Alt. 6 is very similar to Alt. 5. Maybe that's what we should go with.

@spuk-
Copy link

spuk- commented Dec 22, 2014

Anyone here knows Microsoft Powershell (http://technet.microsoft.com/en-us/library/hh847902.aspx - "about_Pipelines")? Streem immediately reminds me of it.

In Powershell, objects sent thru the pipeline get assigned to '$_' by default, which would be like option 7, but a single parameter (not sure if you can have more than 1 object sent thru at a time), which is good for quick scripting/oneliners, but when declaring functions you can assign them to named variables (in a more bureaucratic way than most *nixers are probably used to).

Anyway, I personally don't fancy the little arrows, typing '()' or '||' requires less finger traveling.

So I'd like 7 (by default) plus 3.

Also I'd like to note this looks to me like a language/shell for sysadmins, not necessarily full blown programmers. :]

@britishtea
Copy link

{ <a, b> ... } or <a, b> { ... } cannot be confused with pipes.

@matz matz closed this as completed in 2b8cc84 Jan 22, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests