Discussion:
[dart-misc] Dart Language and Library Newsletter (2017-10-06)
'Florian Loitsch' via Dart Misc
2017-10-06 19:47:19 UTC
Permalink
Github link for this newsletter:
https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md
Earlier newsletters:
https://github.com/dart-lang/sdk/tree/master/docs/newsletter

Dart Language and Library Newsletter

Welcome to the Dart Language and Library Newsletter.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#did-you-know>Did
You Know?
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#static-initializers>Static
Initializers

This section discusses initializers of static variables. For example, the
following program has 3 static variables (seenIds, someDouble and
A._hashIdCounter) that are all initialized with a value:

import 'dart:math';
final seenIds = new Set<int>();var someDouble = sin(0.5);class A {
static int _hashIdCounter = 0;
A();
final hashCode = _hashIdCounter++;
}
main() {
print(new A().hashCode); // => 0.
print(new A().hashCode); // => 1.
print(someDouble); // => 0.479425538604203.
print(seenIds); // => {}.
}

This program is pretty straightforward and its output should not surprise
anyone.

Things get more interesting when the initializers have side effects:

int _counter = 0;int someInt() => _counter++;
var foo = someInt();final bar = someInt();
class A {
static int gee = someInt();
}
main() {
print("A.gee: ${A.gee}");
print("foo: $foo");
print("bar: $bar");
}

The initializers of foo, bar and A.gee all call someInt which has a
side-effect of updating the _counter variable (which, itself, is
initialized with a side-effect-free value: 0).

The output of this program is:

A.gee: 0
foo: 1
bar: 2

Dart simply evaluates the initial value at first access. This is a
consequence of one of Dart's fundamental properties: *no* code is executed
before entering main. Every code is run as the consequence of the program's
actions.

This choice has many nice properties. For example, loading additional
classes doesn't slow down a program. Instantiating an instance of a class
will not initialize the static members of that class, and the instantiation
is thus very fast.

Conceptually, lazy initialization is done with a getter that checks if the
field has already been initialized. If not, it evaluates the initializer
expression and sets the value of the field first. That's, at least, the
simple version. There is much more that the getter needs to handle.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#some-interesting-questions>Some
Interesting Questions

*What happens, if the field is assigned to before the first reading access
to it?*

int foo() { throw "bad?"; }var x = foo();
main() {
x = 0;
print(x);
}

This is allowed and prints 0. The initializer expression is simply ignored.

*What happens when the initializer tries to read the field that is
currently initialized?*

var x = foo();int foo() => x + 1;
main() { print(x); }

Dart requires implementations to throw an exception in this case:

Unhandled exception:
Reading static variable 'x' during its initialization

However, initializers are allowed to read the field if it has been assigned
to first:

int foo() {
x = 0;
return x + 1;
}
var x = foo();
main() { print(x); } // => 1.

*What happens when the initializer throws and the variable is accessed
again?*

int foo() { throw "bad"; }
var x = foo();
main() {
try {
print(x);
} catch (e) {
print("caught");
}
print(x);
}

The result of this program is:

caught
null

When an initializer throws, the field is simply initialized with null and
there is no further attempt to run the initializer again.

As a language team we would need to have another look at this behavior,
when non-nullable types enter the equation...

*What happens when the initializer throws, but the field is already
initialized?*

int foo() {
x = 0;
throw "bad";
}
var x = foo();
main() {
try {
print(x);
} catch (e) {
print("caught");
}
print(x);
}

This program outputs:

caught
null

An exception during initialization *resets* the value to null.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#implementation>
Implementation

As shown, there are many edge cases that need to be covered when a variable
is lazily initialized. Fortunately, the cost for these cases are only paid
at first access. Here is, for example, dart2js' lazy initializer routine
(with some comments):

prototype[getterName] = function() {
var result = this[fieldName];
// If we are already initializing the variable, throw.
if (result == sentinelInProgress)
H.throwCyclicInit(staticName || fieldName);
try {
// If the field hasn't been set yet, it needs to be initialized.
if (result === sentinelUndefined) {
// Make sure that we can detect cycles.
this[fieldName] = sentinelInProgress;
try {
// Run the expression that gives the initial value.
result = this[fieldName] = lazyValue();
} finally {
// If we didn't succeed, set the value to `null`.
if (result === sentinelUndefined) {
this[fieldName] = null;
}
}
}
return result;
} finally {
// Replace this getter with a much more efficient version that
// just looks at the field instead.
this[getterName] = function() {
return this[fieldName];
};
}
};

There are two important things to notice:

1. This routine is shared among all lazily initialized variables. There
is thus little cost in code size for lazily initialized variables.
2. The finally block replaces the lazy getter with a function that just
returns the contents of the field. After the first access, JavaScript
engines thus see a simple *small* function that can be inlined. This
means that lazily-initialized fields behave very efficiently after the
first access.

The finally optimization is not the only thing that our compilers do to
make static variables more efficient: before even generating the lazy
getters, an analysis inspects the initialization-value and determines
whether it's just cheaper to initialize the field with that value instead.
For example, var x = 0, does *not* need a lazy initialization. It's much
cheaper to just initialize the field with that value directly. Obviously,
this replacement can only be made if the evaluation of the expression is
cheap, and is guaranteed not to have any side-effect.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#evaluation-order>Evaluation
Order

The language team is planning to change the evaluation order of method
calls. This section covers the change and explains why it is not as
breaking as it might sound.

In general, Dart evaluates all its expressions from left to right. However,
there is an interesting exception: the arguments to a method invocation are
evaluated before the receiver function is evaluated. Concretely, given
o.foo(e1,
..., eN), Dart requires o, e1, ..., eN to be evaluated before evaluating
o.foo. Most of the time o.foo is a method and the evaluation doesn't matter
(since evaluating to a method doesn't have any visible side-effect).
However, it makes a difference when o.foo is a getter.

class A {
get getter {
print("evaluating getter");
return (x) {};
}
}
int bar() {
print("in bar");
return 499;
}
main() {
var a = new A();
a.getter(bar());
}

According to the specification, this program should print:

in bar
evaluating getter

Even though the a.getter is syntactically before the call to bar() Dart
requires the argument to the call to be evaluated first.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#reasoning>
Reasoning

This exception was put into the specification on purpose and was added for
performance reasons. Previous experience with other virtual machines (like
V8) showed that this approach yielded a simpler calling convention which
leads to a slightly faster method call.

It's instrumental to compare the two conventions:

With the current Dart convention the VM can start by evaluating the
arguments first, and then, when all the arguments are nicely pushed on the
stack, it can look up the target function and do the call.

If the target function needs to be evaluated first, then there is an
additional value that the VM needs to keep alive while it evaluates the
arguments. That is, while it evaluates the arguments, it might run out
registers (and thus spill to the stack), because there is now one more
value (the target function address) that needs to be kept alive.

With few exceptions, evaluating the receiver last, doesn't really affect
any user and the Dart team thus opted for the unexpected evaluation order
in return for less register pressure. In fact, most of the time this
inverted evaluation order was actually beneficial to our users: it provided
more information to our users when they had bugs in their programs:
noSuchMethod errors (including on null) had the arguments that were passed
to the non-existing method.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#nosuchmethod-and-null>noSuchMethod
and null

Whenever a member doesn't exist (or the shape/signature doesn't match), the
noSuchMethod function is invoked. This method receives a filled
Invocation object
which contains the arguments to the non-existing member. This means that
for non-existing members, arguments *also* need to be executed first.

This has important properties for null errors. Since null errors are mapped
to noSuchMethod executions on null, the arguments to null calls are
evaluated before the error is thrown:

int bar() {
print("in bar");
return 499;
}main() {
null.foo(bar());
}

A valid output for this program is:

in bar
Unhandled exception:
NoSuchMethodError: The method 'foo' was called on null.
Receiver: null
Tried calling: foo(499)
#0 Object._noSuchMethod (dart:core-patch/object_patch.dart:44)
#1 Object.noSuchMethod (dart:core-patch/object_patch.dart:47)
#2 main (null.dart:6:8)
#3 _startIsolate.<anonymous closure>
(dart:isolate-patch/isolate_patch.dart:261)
#4 _RawReceivePortImpl._handleMessage
(dart:isolate-patch/isolate_patch.dart:148)

Note how the error message contains the argument 499 that was passed to the
function. This is only possible, because the argument was evaluated before
the target function was evaluated. Note: this information is only available
on the VM, since the null-errors in the browser are triggered by the
JavaScript engine which doesn't capture any argument values.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#changing-the-evaluation-order>Changing
the Evaluation Order

Despite the benefits of the current semantics, we decided to change the
behavior so that the evaluation is strictly from left to right.

There are 4 main reasons for the change:

1. The behavior is unexpected.
2. Seemingly similar invocations don't behave the same.
3. Because of static types, it's easier to know whether the evaluation
of the target function can be evaluated last (as an optimization).
4. Implementing the specification-behavior is hard when compiling to
JavaScript and is actually detrimental to code size and performance. For
this reason, and because of minor bugs, our implementations don't correctly
implement the specification.

<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#expected-behavior>Expected
Behavior

We found that our users don't expect that the target of member invocation
is evaluated last. In practice, this was not a problem, but we would prefer
to match our user's expectations.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#related-equivalences>Related
Equivalences

Because of the evaluation order and noSuchMethod we currently end up with
different behavior for seemingly similar constructs:

// The following invocations are *usually* the same, but aren't when
`o` is null, or when// `foo` is not a member of `o`.
o.foo(e1);
o.foo.call(e1);
(o.foo)(e1);

<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#implementations>
Implementations

Our implementations (VM, dart2js and DDC) all behave differently, and
dart2js and DDC aren't even internally consistent. Dart2js' behavior
depends on optimizations, and DDC treats dynamic and non-dynamic calls (on
the same member) differently.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#static-typing>Static
Typing

Since Dart is getting more static, in most cases a method call is known not
to go through getters or through noSuchMethod. For the majority of calls
that are known to hit a "normal" method, the compilers can keep evaluating
the function target last (since it doesn't have any side-effects). In those
simple cases the only change consists of making sure that the receive isn't
null before evaluating any arguments.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#conclusion>
Conclusion

The original reason for the inverted evaluation order doesn't apply
anymore, and it's time to bring Dart's evaluation order in line with what
our users expect. A simple o.foo(bar()) should not be a "Dart Puzzler".
--
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+***@dartlang.org.
Danny Tuppeny
2017-10-08 09:28:10 UTC
Permalink
On Fri, 6 Oct 2017 at 20:47 'Florian Loitsch' via Dart Misc <
Post by 'Florian Loitsch' via Dart Misc
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#changing-the-evaluation-order>Changing
the Evaluation Order
Despite the benefits of the current semantics, we decided to change the
behavior so that the evaluation is strictly from left to right.
1. The behavior is unexpected.
I'm slightly confused by this - the example given behaves how I would
expect, and (if I'm understanding correctly) if I do the same thing in C#
<https://dotnetfiddle.net/OpL4j1> it seems to behave the same.. given:

Object a = null;
a.Equals(bar());

bar() is invoked before this throws a NullReferenceException. To me, the
change to make this throw before evaluating bar() seems unusual (though
admittedly, I don't know how other languages behave, C# might be the odd
one!).

I don't object to this change (it actually seems quite logical and I don't
think it's likely to affect anything I do), it just surprised me that this
wasn't deemed to be expected behaviour. I tried, but failed, at Googling to
see what other languages do!
--
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+***@dartlang.org.
Mark Nordine
2017-10-08 14:22:52 UTC
Permalink
Agreed, I'm not against it either, but saying the behavior is unexpected is
a pretty contentious claim. I expected bar() to evaluate first.
Post by Danny Tuppeny
On Fri, 6 Oct 2017 at 20:47 'Florian Loitsch' via Dart Misc <
Post by 'Florian Loitsch' via Dart Misc
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#changing-the-evaluation-order>Changing
the Evaluation Order
Despite the benefits of the current semantics, we decided to change the
behavior so that the evaluation is strictly from left to right.
1. The behavior is unexpected.
I'm slightly confused by this - the example given behaves how I would
expect, and (if I'm understanding correctly) if I do the same thing in C#
Object a = null;
a.Equals(bar());
bar() is invoked before this throws a NullReferenceException. To me, the
change to make this throw before evaluating bar() seems unusual (though
admittedly, I don't know how other languages behave, C# might be the odd
one!).
I don't object to this change (it actually seems quite logical and I don't
think it's likely to affect anything I do), it just surprised me that this
wasn't deemed to be expected behaviour. I tried, but failed, at Googling to
see what other languages do!
--
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+***@dartlang.org.
'Florian Loitsch' via Dart Misc
2017-10-09 12:34:22 UTC
Permalink
Thanks for the feedback.
I have to admit, that I missed C# and Java evaluate their arguments first.
From what I can see, C++ and JavaScript evaluate left-to-right, though.

I will write a follow-up in the next newsletter.
Post by Mark Nordine
Agreed, I'm not against it either, but saying the behavior is unexpected
is a pretty contentious claim. I expected bar() to evaluate first.
Post by Danny Tuppeny
On Fri, 6 Oct 2017 at 20:47 'Florian Loitsch' via Dart Misc <
Post by 'Florian Loitsch' via Dart Misc
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#changing-the-evaluation-order>Changing
the Evaluation Order
Despite the benefits of the current semantics, we decided to change the
behavior so that the evaluation is strictly from left to right.
1. The behavior is unexpected.
I'm slightly confused by this - the example given behaves how I would
expect, and (if I'm understanding correctly) if I do the same thing in C#
Object a = null;
a.Equals(bar());
bar() is invoked before this throws a NullReferenceException. To me, the
change to make this throw before evaluating bar() seems unusual (though
admittedly, I don't know how other languages behave, C# might be the odd
one!).
I don't object to this change (it actually seems quite logical and I
don't think it's likely to affect anything I do), it just surprised me that
this wasn't deemed to be expected behaviour. I tried, but failed, at
Googling to see what other languages do!
--
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
--
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+***@dartlang.org.
Benjamin Strauß
2017-10-09 14:21:54 UTC
Permalink
Having left to right would be completely counterintuitive. I also would
like to know where this data comes from.

I expect (in dynamic lanugages) something that is inside braces to be
evaluated first, this is also how it works in Javascript.

https://jsfiddle.net/1x3tdf0r/
Post by 'Florian Loitsch' via Dart Misc
Thanks for the feedback.
I have to admit, that I missed C# and Java evaluate their arguments first.
From what I can see, C++ and JavaScript evaluate left-to-right, though.
I will write a follow-up in the next newsletter.
Post by Mark Nordine
Agreed, I'm not against it either, but saying the behavior is unexpected
is a pretty contentious claim. I expected bar() to evaluate first.
Post by Danny Tuppeny
On Fri, 6 Oct 2017 at 20:47 'Florian Loitsch' via Dart Misc <
Post by 'Florian Loitsch' via Dart Misc
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#changing-the-evaluation-order>Changing
the Evaluation Order
Despite the benefits of the current semantics, we decided to change the
behavior so that the evaluation is strictly from left to right.
1. The behavior is unexpected.
I'm slightly confused by this - the example given behaves how I would
expect, and (if I'm understanding correctly) if I do the same thing in
C# <https://dotnetfiddle.net/OpL4j1> it seems to behave the same..
Object a = null;
a.Equals(bar());
bar() is invoked before this throws a NullReferenceException. To me,
the change to make this throw before evaluating bar() seems unusual
(though admittedly, I don't know how other languages behave, C# might be
the odd one!).
I don't object to this change (it actually seems quite logical and I
don't think it's likely to affect anything I do), it just surprised me that
this wasn't deemed to be expected behaviour. I tried, but failed, at
Googling to see what other languages do!
--
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
--
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+***@dartlang.org.
Sean Eagan
2017-10-09 17:34:01 UTC
Permalink
Post by Benjamin Strauß
Having left to right would be completely counterintuitive. I also would
like to know where this data comes from.
I expect (in dynamic lanugages) something that is inside braces to be
evaluated first, this is also how it works in Javascript.
https://jsfiddle.net/1x3tdf0r/
Post by 'Florian Loitsch' via Dart Misc
Thanks for the feedback.
I have to admit, that I missed C# and Java evaluate their arguments
first. From what I can see, C++ and JavaScript evaluate left-to-right,
though.
I will write a follow-up in the next newsletter.
Agreed, I'm not against it either, but saying the behavior is unexpected
Post by 'Florian Loitsch' via Dart Misc
Post by Mark Nordine
is a pretty contentious claim. I expected bar() to evaluate first.
Post by Danny Tuppeny
On Fri, 6 Oct 2017 at 20:47 'Florian Loitsch' via Dart Misc <
Post by 'Florian Loitsch' via Dart Misc
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171006.md#changing-the-evaluation-order>Changing
the Evaluation Order
Despite the benefits of the current semantics, we decided to change
the behavior so that the evaluation is strictly from left to right.
1. The behavior is unexpected.
I'm slightly confused by this - the example given behaves how I would
expect, and (if I'm understanding correctly) if I do the same thing in
C# <https://dotnetfiddle.net/OpL4j1> it seems to behave the same..
Object a = null;
a.Equals(bar());
bar() is invoked before this throws a NullReferenceException. To me,
the change to make this throw before evaluating bar() seems unusual
(though admittedly, I don't know how other languages behave, C# might be
the odd one!).
I don't object to this change (it actually seems quite logical and I
don't think it's likely to affect anything I do), it just surprised me that
this wasn't deemed to be expected behaviour. I tried, but failed, at
Googling to see what other languages do!
--
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
--
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
--
Thanks,
Sean Eagan
--
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+***@dartlang.org.
'Lasse R.H. Nielsen' via Dart Misc
2017-10-09 19:57:01 UTC
Permalink
Post by Benjamin Strauß
Having left to right would be completely counterintuitive. I also would
like to know where this data comes from.
I expect (in dynamic lanugages) something that is inside braces to be
evaluated first, this is also how it works in Javascript.
https://jsfiddle.net/1x3tdf0r/
Just for the record, JavaScript does evaluate the function expression
before the arguments. This was changed in ECMAScript 5.0. See
http://es5.github.io/#x11.2.3
The change was that GetValue(ref) in step 2 is now evaluated before
evaluating the arguments, not after like in ECMAScript 3 (section "11.2.3
Function Calls" of https://www-archive.mozilla.org/js/language/E262-3.pdf).

In your example, the function expression (x.foo) evaluates to undefined,
then the arguments are evaluated, and then it tries to call "undefined",
which fails.
If your example started with:
var x = null;
then you would see an error without a console.log output, because
evaluating `x.foo` fails to evaluate entirely (and doesn't just fail to
evaluate to a callable value);

/L
--
Lasse R.H. Nielsen - ***@google.com
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 KÞbenhavn K
- Denmark - CVR nr. 28 86 69 84
--
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+***@dartlang.org.
Benjamin Strauß
2017-10-09 20:14:12 UTC
Permalink
Thanks for the detailed spec info! :)

Am Montag, 9. Oktober 2017 21:57:27 UTC+2 schrieb Lasse Reichstein Holst
Post by 'Lasse R.H. Nielsen' via Dart Misc
Post by Benjamin Strauß
Having left to right would be completely counterintuitive. I also would
like to know where this data comes from.
I expect (in dynamic lanugages) something that is inside braces to be
evaluated first, this is also how it works in Javascript.
https://jsfiddle.net/1x3tdf0r/
Just for the record, JavaScript does evaluate the function expression
before the arguments. This was changed in ECMAScript 5.0. See
http://es5.github.io/#x11.2.3
The change was that GetValue(ref) in step 2 is now evaluated before
evaluating the arguments, not after like in ECMAScript 3 (section "11.2.3
Function Calls" of https://www-archive.mozilla.org/js/language/E262-3.pdf
).
In your example, the function expression (x.foo) evaluates to undefined,
then the arguments are evaluated, and then it tries to call "undefined",
which fails.
var x = null;
then you would see an error without a console.log output, because
evaluating `x.foo` fails to evaluate entirely (and doesn't just fail to
evaluate to a callable value);
/L
--
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 KÞbenhavn K
- Denmark - CVR nr. 28 86 69 84
--
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+***@dartlang.org.
tatumizer-v0.2
2017-10-10 04:33:13 UTC
Permalink
Getter is just a syntactic sugar for a regular method. Suppose I'm not
aware about this sugar, and I implement 'getter' as a regular method.
The invocation looks like a.getter()(bar()) - so a.getter() is obviously
invoked before the bar().
Then I find out about the existence of said sugar, and add 'get' keyword
accordingly. I fix my program by just erasing parens: a.getter(bar())
The question is: in this scenario, what evaluation strategy would seem more
intuitive? The one that preserves the order, or the one that changes it?
--
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+***@dartlang.org.
'Lasse R.H. Nielsen' via Dart Misc
2017-10-10 07:51:07 UTC
Permalink
Post by tatumizer-v0.2
Getter is just a syntactic sugar for a regular method. Suppose I'm not
aware about this sugar, and I implement 'getter' as a regular method.
The invocation looks like a.getter()(bar()) - so a.getter() is obviously
invoked before the bar().
Then I find out about the existence of said sugar, and add 'get' keyword
accordingly. I fix my program by just erasing parens: a.getter(bar())
The question is: in this scenario, what evaluation strategy would seem
more intuitive? The one that preserves the order, or the one that changes
it?
Or another way to frame the same question:

Is o.foo(bar()) the same as (o.foo)(bar())?
- when o.foo is a getter
- when o.foo is a method.
- when o.foo doesn't exist (dynamic calls only in Dart 2).

We want it to be the case for getters, and for all successful method
invocations (there are some issues around which noSuchMethod gets invoked
when you dynamically call a method or method tear-off with the wrong number
of arguments, but bad code is bad).

/L
--
Lasse R.H. Nielsen - ***@google.com
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 KÞbenhavn K
- Denmark - CVR nr. 28 86 69 84
--
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+***@dartlang.org.
Continue reading on narkive:
Loading...