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

Provide better clarity around operator precedence and associativity #4332

Merged
merged 10 commits into from Nov 21, 2022

Conversation

parlough
Copy link
Member

@parlough parlough commented Oct 31, 2022

While the precedence outlined by the table should only be used as a guideline, users are instead finding third-party sources when googling which do not highlight potential issues and are not able to identify/search that this table still approximates the behavior even if they navigate to the language tour.

This PR makes the table more searchable and identifiable as outlining the approximate precedence, while also clarifying the warning which was a bit confusing, focusing on that it can just be used as a "helpful guide". Beyond that, this adds the associativity labels present on the language spec's "helpful guide".

Fixes #4287

Staged: https://dart-dev--pr4332-feature-document-ass-ys8cfbyn.web.app/guides/language/language-tour#operators

@parlough parlough added review.copy Awaiting Copy Review review.tech Awaiting Technical Review labels Oct 31, 2022
@github-actions
Copy link

github-actions bot commented Oct 31, 2022

Visit the preview URL for this PR (updated for commit e6ed24c):

https://dart-dev--pr4332-feature-document-ass-ys8cfbyn.web.app

(expires Tue, 15 Nov 2022 01:48:10 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: d851bc446d3c4d7394c5406c6f07255afc7075f3

@parlough
Copy link
Member Author

parlough commented Oct 31, 2022

@eernstg What do you think about these clarifications? I know we want to avoid highlighting this table as outlining operator precedence as the concept has some flaws, but users seem to be finding alternate sites which do not highlight this concern when searching on Google. I tried to make the table a bit more searchable in terms of this, while also making the warning more clear.

src/_guides/language/language-tour.md Outdated Show resolved Hide resolved
src/_guides/language/language-tour.md Outdated Show resolved Hide resolved
Copy link
Member

@eernstg eernstg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I suggested adding an example showing how the grammar can give rise to an operator precedence relationship.

src/_guides/language/language-tour.md Outdated Show resolved Hide resolved
Comment on lines 1754 to 1759
The operator precedence outlined here
is only an approximation of the precedence and associativity
given implicitly by Dart's grammar
and should only be used as a helpful guide.
For definitive answers, consult the grammar in the
[Dart language specification][].
Copy link
Contributor

@atsansone atsansone Nov 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Why does this only approximate precedence? Is there a difficulty in providing the specific precedence? What is that difficulty?

suggestion: Tighten the language and use active voice.

Suggested change
The operator precedence outlined here
is only an approximation of the precedence and associativity
given implicitly by Dart's grammar
and should only be used as a helpful guide.
For definitive answers, consult the grammar in the
[Dart language specification][].
The previous table provides a rough guide to operator precedence.
You can find the authoritative precedence and associativity for Dart
in the [Dart language specification][].

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not that you can find any authoritative precedence and associativity in the language specification as they aren't really defined (or able to be exactly), but rather you need to look at the whole grammar to understand the relationships between operators.

I've took some of your changes and Erik's, while also being clear about it only be used as a guide (which was the source of confusion that caused the introduction of the note a long time ago).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could comment a bit more on why operator precedence is not a precise concept.

If you settle on a specific class of parsers (say, table driven LALR(1) parsers) then you can have a technically precise notion of precedence. In case of an ambiguity, the parser will then use the assigned precedence values to make the decision about whether to shift or reduce, and which rule to reduce. This makes sense if we have a grammar where a lot of different expressions use the same nonterminal:

...
expr ::= expr ('+' | '-') expr @precedence(5)
expr ::= expr ('*' | '/') expr @precedence(6)
...

Precedence has a precise meaning in this context, and it is a tool outside the underlying context free grammar formalism (it is defined in terms of the chosen parser algorithm, it's not a property of the grammar — the grammar is simply ambiguous).

If we are using a different approach to parsing (for instance, Dart has always used an enhanced recursive descent parser, which is more like ANTLR) then there is no reason to assume that there exists any assignment of precedence to any set of operators that will describe the behavior of the parser correctly. In other words, the whole concept of precedence doesn't necessarily fit that approach to parsing. When using that approach, the ambiguities simply do not arise, because we use different nonterminals to establish a similar property:

...
additiveExpression ::= multiplicativeExpression (('+' | '-') multiplicativeExpression)*
multiplicativeExpression ::= someOtherExpression (('*' | '/') someOtherExpression)*
...

Looking at the grammar you can see that an additive expression can consist of a sequence of multiplicative expressions, separated by '+' or '-' (and not the other way around), and that makes it tempting to say that '*' has a higher precedence than '+'. (Of course, there would be more rules about additiveExpression, because it can also derive other things than a sum of products, but this is the core part with respect to precedence.)

However, the source of truth is the grammar, and if we settle on a particular set of precedence values, it takes a non-trivial proof to verify that this precedence table describes the derivable programs with that grammar precisely (and maybe that proof doesn't exist, because it just isn't true).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@parlough : I'd still recommend the tighter language.

@eernstg : Thanks for the explanation!

Copy link
Member Author

@parlough parlough Nov 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@atsansone Any suggestions on how to make it tighter? I'm having trouble focusing it even more while still answering the three questions and concerns commonly raised (in the linked issue, past issues, in the language repo about this table, and by Erik):

  1. How it should only be used as a "helpful guide" not definitive
  2. Briefly explaining why it can only be used as a helpful guide
  3. Where/how to find and understand the authoritative behavior

Copy link
Contributor

@atsansone atsansone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@parlough : I have a few comments for your review.

@parlough parlough force-pushed the feature/document-associativity-precedence branch from c888fee to 6db681a Compare November 4, 2022 21:41
@parlough parlough assigned atsansone and unassigned parlough Nov 4, 2022
Copy link
Contributor

@atsansone atsansone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM % 1 suggestion.

@atsansone atsansone added st.RFM Ready to merge or land and removed review.copy Awaiting Copy Review review.tech Awaiting Technical Review labels Nov 9, 2022
@atsansone atsansone assigned parlough and unassigned atsansone Nov 9, 2022
Comment on lines 1725 to 1729
Dart supports the operators shown in the following table.
The table shows Dart's operator associativity
and [operator precedence](#operator-precedence-example) from highest to lowest,
which are an **approximation** of Dart's operator relationships.
You can implement many of these [operators as class members](#_operators).
Copy link
Contributor

@atsansone atsansone Nov 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: To tighten language, sometimes you need to write more, shorter sentences.

Suggested change
Dart supports the operators shown in the following table.
The table shows Dart's operator associativity
and [operator precedence](#operator-precedence-example) from highest to lowest,
which are an **approximation** of Dart's operator relationships.
You can implement many of these [operators as class members](#_operators).
The following table lists the operators that Dart supports.
The table sorts the operators from highest to lowest precedence.
When determining which operator to apply first, Dart compares operators.
When comparing two different operators,
Dart applies the operator with greater precedence first.
When comparing two of the same operator,
Dart applies the operator from the associative direction first.
Complex expressions may apply operators in a recursive fashion.
Due to the complexity of precedence, keep your expressions short,
store stages in varables, then chain those variables into further
expressions.
Consider this table a guideline only.
To learn more about the specifics, refer to the [Dart grammar](https://github.com/dart-lang/sdk/blob/main/tools/spec_parser/Dart.g).
You can use many of these operators as class members.
  • How it should only be used as a "helpful guide" not definitive
  • Briefly explaining why it can only be used as a helpful guide
  • Where/how to find and understand the authoritative behavior

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't help commenting here! ;-)

This doesn't tell the reader that the whole concept of operator precedence is imprecise. It's not a matter of complexity, there's just no reason to assume that there exists an operator precedence table which is a correct description of the behavior of a Dart parser. It would certainly be a non-trivial effort to establish any firm results in this area.

Copy link
Member Author

@parlough parlough Nov 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also a bit worried about providing so much information in the opening here, when most readers are just looking for the table. We expand on the the precedence right after the table already, and I like your comments around that, so I'll try to incorporate some of that there.

Copy link
Member

@eernstg eernstg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We talked about it, this makes sense, thanks!

@atsansone atsansone merged commit 0099ada into main Nov 21, 2022
@parlough parlough deleted the feature/document-associativity-precedence branch November 21, 2022 18:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
st.RFM Ready to merge or land
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Operator precedence table
4 participants