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

Clarify possible ambiguity when omitting parentheses #463

Closed
oneeman opened this issue Feb 13, 2015 · 4 comments
Closed

Clarify possible ambiguity when omitting parentheses #463

oneeman opened this issue Feb 13, 2015 · 4 comments

Comments

@oneeman
Copy link
Contributor

oneeman commented Feb 13, 2015

From what I've seen, the documentation just says that you can omit parentheses (at http://elixir-lang.org/crash-course.html#calling-functions). In some cases of ambiguity a syntax error is thrown, whereas in others one of the possible interpretations is used. For example, func func :a, :b is interpreted as func(func(:a,:b)) as opposed to func(func(:a), :b). So it'd be nice to have some guidance on the site regarding the types of cases which (a) lead to syntax errors, (b) are valid but possibly ambiguous, or (c) are unproblematic (func func :a). Needless to say, in ambiguous cases it's better to use parentheses rather than lean on the parser's rules, but it'd help to have some good exposition highlighting those cases so that developers can be more aware of them.

Might perhaps also be a good place to present some of the points from https://groups.google.com/forum/#!topic/elixir-lang-talk/MvZq30BYMqs since it's roughly the same topic (ambiguity when omitting parentheses) and it'd be nice to have it on the language's site to reach a broader audience.

I'd be happy to tackle this once I've got a proper grasp of the grammar rules in elixir_parser.yrl... which could be a while.
P.S. @ericmj might remember a line he reviewed in a code snippet of mine that went PowerSet.of Enum.into [1,2,3], HashSet.new, his comment on which got me looking at this.

@josevalim
Copy link
Member

The rules should be this: allowing a function call inside another function call without parenthesis is only allowed if the first call contains only on argument:

foo bar 1, 2, 3 # foo(bar(1, 2, 3))

Not ok:

foo 1, bar 2, 3 # ERROR: is 3 in foo or bar?

Data structures are a bit more strict as they lend more to confusion:

[bar 1] # ok
[bar 1, 2, 3] # error

I don't think the crash course is the place for this though. It is meant to be a crash course and not a complete reference. I wouldn't add it to the getting started guide too because I would say it would be counter productive to go into such details such early on.

@oneeman
Copy link
Contributor Author

oneeman commented Feb 13, 2015

Thanks, that's helpful. But I don't think the rule for functions as stated is quite accurate.

a function call inside another function call without parenthesis is only allowed if the first call contains only on argument

For one thing, foo :a, bar :b is valid (and unambiguous), but wouldn't be valid according to the rule as stated.

The rule also assumes that the number of arguments to the first function can be identified unambiguously to begin with, which isn't the case. foo bar a, b could (unless I'm missing something) also be intuitively interpreted as foo(bar(a), b), in which case foo would have 2 arguments.

I've tried to think of an alternative phrasing for the rule that would cover all cases, but haven't managed to.

At any rate, I do take the point that this is advanced and complex, so shouldn't be included in the beginner resources (except perhaps as a link to a page with the qualification that it's an advanced topic). And perhaps this is material for an eventual reference guide.

Tangential question: is operator precedence order listed somewhere on the site? I ask because I think maybe , having higher precedence than + makes
foo :a, 10 + bar 5, :c valid whereas foo :a, bar 5, :c isn't.

@josevalim
Copy link
Member

foo :a, bar :b actually fits the constraint once you consider it is called as: z(foo(:a, bar :b)).

The rule also assumes that the number of arguments to the first function can be identified unambiguously to begin with, which isn't the case.

Right, all those cases are ambiguous, the difference is if we decided to raise or choose one side. If they were not ambiguous, we wouldn't have this discussion. :)

Btw, this may help:

iex> Macro.to_string quote do: (foo :a, 10 + bar 5, :c)
"foo(:a, 10 + bar(5, :c))"

:)

@oneeman
Copy link
Contributor Author

oneeman commented Feb 14, 2015

Absolutely. And thanks for the quoting tip, I'd forgotten about that :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants