Why do I need parens around this (method cascade)

59 views
Skip to first unread message

Danny Tuppeny

unread,
Feb 12, 2017, 11:58:26 AM2/12/17
to Dart Misc
I've had to put parents in this code ot make it compile but I don't really understand why:

Serializers serializers =
 
(
    _$serializers
   
.toBuilder()
   
..addPlugin(new StandardJsonPlugin())
 
).build();


As I understood it, the method cascade operator caused what was on its left to be returned and the return value of the right side to be discarded. Therefore, given this code:

Serializers serializers =
    _$serializers
   
.toBuilder()
   
..addPlugin(new StandardJsonPlugin())
 
.build();


My expectation was that .build() would be called on the SerializersBuilder that we called addPlugin on. However, It gives the error "The method 'build' isn't defined for class 'void'".

Have I misunderstood? It always worked as I expected before. Example 1 on Gilad's post actually shows the same, though it doesn't explain the parens :(

Brian Wilkerson

unread,
Feb 12, 2017, 12:06:27 PM2/12/17
to General Dart Discussion
Danny,

It's because of the relative precedence of the '.' and '..' constructs.

With the parentheses, you get what you're really trying to express:

Serializers serializers = _$serializers.toBuilder();
serializers.addPlugin(new StandardJsonPlugin());
serializers.build();

But without the parentheses, the code is equivalent to

Serializers serializers = _$serializers.toBuilder();
serializers.addPlugin(new StandardJsonPlugin()).build();

Brian

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.

Danny Tuppeny

unread,
Feb 12, 2017, 12:09:56 PM2/12/17
to mi...@dartlang.org
On Sun, 12 Feb 2017 at 17:06 'Brian Wilkerson' via Dart Misc <mi...@dartlang.org> wrote:
It's because of the relative precedence of the '.' and '..' constructs.

Gotcha! Can we change them around?

J/k; I'm sure it makes more sense this way, I just hadn't noticed it before. Thanks! :-)

Erik Ernst

unread,
Feb 13, 2017, 5:49:44 AM2/13/17
to Dart Misc
On Sun, Feb 12, 2017 at 6:09 PM, Danny Tuppeny <da...@tuppeny.com> wrote:
On Sun, 12 Feb 2017 at 17:06 'Brian Wilkerson' via Dart Misc <mi...@dartlang.org> wrote:
It's because of the relative precedence of the '.' and '..' constructs.

Gotcha! Can we change them around?

That would probably be too much. The grammar has the following rule:

cascadeSection:
    ‘..’ (cascadeSelector arguments*) (assignableSelector arguments*)*
    (assignmentOperator expressionWithoutCascade)?

The expressionWithoutCascade at the end allows for a large set of expressions on the right hand side of `=`, including method invocations,  and further assignments. This is quite convenient, especially in all those "building" expressions which were a major reason for having cascades in the first place, because you want to have "general expressions" available for the value which is used to build each property.

The cascadeSection occurs in a couple of locations in the grammar, but the most relevant one here is

expression:
    conditionalExpression cascadeSection* | ...

This puts cascades at the very top of the expression derivation chain (i.e., it has low precedence), which fits with the general notion that each cascade section should be able to contain almost all kinds of expressions.

If you want to do anything in the direction of swapping the precedence of `.` and `..` we'd need to append cascadeSection to some kind of expression which has higher precedence (i.e., which is lower in the derivation chain) than selector, but selector is already near the bottom:

postfixExpression: ... | primary selector*

We have '(' expression ')' as one of the alternatives in the rule for primary, so that's at the very bottom where we can manually request a high precedence (that of primary) for an expression of arbitrary precedence (expression).

I think it would be a bad idea to give selector to a lower precedence, because we want to be able to use method calls in expressions: For instance, a.foo() + b.bar() shouldn't mean (a.foo() + b).bar().

So we can't really give `..` a high enough precedence and `.` a low enough precedence to swap them.

Maybe somebody can come up with a really smart solution (that probably changes major parts of the grammar), but my impression is that you'll have to live with `(someExpression).build()` when the someExpression part contains cascades.

J/k; I'm sure it makes more sense this way, I just hadn't noticed it before. Thanks! :-)


 
With the parentheses, you get what you're really trying to express:

Serializers serializers = _$serializers.toBuilder();
serializers.addPlugin(new StandardJsonPlugin());
serializers.build();

But without the parentheses, the code is equivalent to

Serializers serializers = _$serializers.toBuilder();
serializers.addPlugin(new StandardJsonPlugin()).build();

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.

--
Erik Ernst  -  Google Danmark ApS
Skt Petri Passage 5, 2 sal, 1165 København K, Denmark
CVR no. 28866984

Reply all
Reply to author
Forward
0 new messages