Discussion:
[dart-misc] Dart Language and Library Newsletter (2017-11-10)
'Florian Loitsch' via Dart Misc
2017-11-10 18:13:00 UTC
Permalink
I will be traveling next week. The next newsletter is therefore only in two
weeks.

Github link for this newsletter:
https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.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/20171110.md#did-you-know>Did
You Know?
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#constructors>
Constructors

Dart has many ways to make writing constructors easier or more powerful.
The most known is probably the concise syntax for initializing instance
fields directly in the signature line (see below). This section shows some
other, less known features.

// Concise syntax for initializing fields while declaring parameters.class A {
final int x;
A(this.x);
}

<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#generative-constructors>Generative
Constructors

A constructor is "generative", if it is called on a freshly created
instance to initialize the object. This sounds complicated, but just
describes the behavior of the most common constructors.

class A {
int x;
A(int y) : this.x = y + 2;
}

When a user writes new A(), conceptually, the program first instantiates an
uninitialized object of type A, and then lets the constructor initialize it
(set the field x).

The reason for this wording is, that generative constructors can be used in
super calls in initializer lists. When called as super the generative
constructor doesn't instantiate a new object again. It just does its part
of the initialization.

class A {
int x;
A(int y) : this.x = y + 2;
}
class B extends A {
B(int z) : super(z - 1) {
print("in B constructor");
}
}

The order of evaluation is well defined: first all expressions in the
initializer list are evaluated. Then the initializer list of the super
constructor is run. This continues, until Object (the superclass of every
class) is reached. Then, the bodies of the constructors are executed in
reverse order, first starting the one from Object (not doing anything), and
working its way down the class hierarchy.

This evaluation order is usually not noticeable, but can be important when
the expressions have side-effects, and/or the bodies read final fields:

int _counter = 0;
class A {
final int aCounter;
A() : aCounter = _counter++ {
print("foo: ${foo()}");
}
}
class B extends A {
final int bCounter;
final int field;

B()
: field = 499,
bCounter = _counter++ {
print("B");
}

int foo() => field;
}
main() {
var b = new B();
print("aCounter: ${b.aCounter}");
print("bCounter: ${b.bCounter}");
}

Running this program yields:

foo: 499
B
aCounter: 1
bCounter: 0

Note that the bCounter expression is evaluated first, yielding 0, and that
aCounter, coming second, is set to 1. Furthermore, the final field field in
B is set to 499 when the constructor in A indirectly accesses the field.

Dart guarantees that final fields are only visible with their final value.
Dart ensures this property by splitting the construction of objects into
two: the initializer list, and the constructor body. Without this two-phase
initialization Dart wouldn't be able to provide this guarantee.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#factory-constructors>Factory
Constructors

Factory constructors are very similar to static functions, except that they
can be invoked with new. They don't work on an instantiated (uninitialized)
object, like generative constructors, but they must create the object
themselves.

The following example shows how Future.microtask could be implemented with
a factory and the existing Completerclass.

class Future<T> {
factory Future.microtask(FutureOr<T> computation()) {
Completer c = new Completer<T>();
scheduleMicrotask(() { ... c.complete(computation()) ... });
return c.future;
}
}

The actual implementation uses private classes to be more efficient, but is
otherwise very similar to this code.

Factory constructors cannot be used as targets of super in initializers.
(This also means that a class that only has factory constructors cannot be
extended).
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#redirecting-generative-constructor>Redirecting
Generative Constructor

When constructors want to share code it is often convenient to just forward
from one constructor to another one. This can be achieved with factory
constructors,
but if the constructor should also be usable as the target of a
super-initializer
call, then factory constructors (as described above) are not an option. In
this case, one has to use redirecting generative constructors:

class Point {
final int x;
final int y;
Point(this.x, this.y);
}
class Rectangle {
int x0;
int y0;
int x1;
int y1;

Rectangle.coordinates(this.x0, this.y0, this.x1, this.y1);

Rectangle.box(Point topLeft, int width, int height)
: this.coordinates(topLeft.x, topLeft.y, topLeft.x + width,
topLeft.y.height);
}
class Square extends Rectangle {
Box(Point topLeft, int width) : super.box(topLeft, width, width);
}

The Rectangle class has two constructors (both generative): coordinates and
box. The box constructor redirects to the coordinates constructor.

As can be seen, a subtype, here Square, can still use the constructor in
the initializer list.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#redirecting-factory-constructors>Redirecting
Factory Constructors

Frequently, factory constructors are just used to instantiate a differently
named class. For example, the Iterable class is actually abstract and a new
Iterable.empty() can't therefore be generative but must be a factory. With
factory constructors this could be implemented as follows:

abstract class Iterable<E> {
factory Iterable.empty() {
return new _EmptyIterable<E>();
}
}

There are two reasons, why we are not happy with this solution:

1. there is an unnecessary redirection: the compilers need to inline the
factory constructor, instead of seeing directly that a new
Iterable.empty() should just directly create an _EmptyIterable. (Our
compilers inline these simple constructors, so this is not a real problem
in practice).
2. A factory constructor with a body cannot be const. Clearly, there is
code being executed (even if it's just new _EmptyIterable()), which is
not allowed for const constructors.

The solution is to use redirecting factory constructors:

abstract class Iterable<E> {
const factory Iterable.empty() = _EmptyIterable<E>;
}

Now, the Iterable.empty() constructor is just a synonym for
_EmptyIterable<E>. Note that we don't even need to provide arguments to the
_EmptyIterable<E> constructor. They *must* be the same as the one of the
redirecting factory constructor.

Another example:

class C {
final int x;
final int y;
const C(this.x, this.y);
factory const C.duplicate(int x) = _DuplicateC;
}
class _DuplicateC implements C {
final int x;
int get y => x;
const _DuplicateC(this.x);
}

<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#shorter-final-variables>Shorter
Final Variables

In Dart it is now easier to declare mutable locals, than to declare
immutable variables:

var mutable = 499;final immutable = 42;

Declaring a variable as mutable, but not modifying it, isn't a real problem
per se, but it would be nice, if the var keyword actually expressed the
intent that the variable will be modified at a later point.

We recently looked at different ways to make immutable locals more
appealing. This section contains our proposal.

Instead of using a different keyword (like val) we propose to use an even
shorter syntax for immutable locals: colon-equals (:=).

In this proposal, a statement of the form identifier := expression; introduces
a new *final* local variable.

// DateTime.toString() method.
String toString() {
y := _fourDigits(year);
m := _twoDigits(month);
d := _twoDigits(day);
h := _twoDigits(hour);
min := _twoDigits(minute);
sec := _twoDigits(second);
ms := _threeDigits(millisecond);
us := microsecond == 0 ? "" : _threeDigits(microsecond);
if (isUtc) {
return "$y-$m-$d $h:$min:$sec.$ms${us}Z";
} else {
return "$y-$m-$d $h:$min:$sec.$ms$us";
}
}

As a first reaction, it feels dangerous to just use one character (":") to
introduce a new variable. In our experiments this was, however, not an
issue. In fact, single-character modifiers of = are already common: x += 3 is
also just one character on top of = and we are not aware of any readability
issues with compound assignments. Furthermore, syntax highlighting helps a
lot in ensuring that these variable declarations aren't lost in the code.

We would also like to support typed variable declarations: Type identifier
:= expression. (The following examples are just random variable
declarations of our codebase that have been rewritten to use the new
syntax).

int pos := value.indexOf(":");JSSyntaxRegExp re :=
pattern;IsolateEmbedderData ied := isolateEmbedderData.remove(portId);

For now, we are only looking at the := syntax for local variables. If it
proves to be successful, we will investigate whether we should allow the
same syntax for final (global) statics or fields.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#for-loops>For
Loops

For loops are another place where users frequently declare new variables.
There, we need to pay a bit more attention. For example, the for-in
statement doesn't even have any assignment symbol, which we could change to
:=.

When looking at uses of for-in, we found that these loops are almost never
used without introducing a loop variable:

var x;for (x in [1, 2]) {
print(x);
}

In fact, the only cases where we found this pattern was in our own tests...

We thus propose to change the meaning of for (identifier in Iterable). It
should become syntactic sugar for for (final identifier in Iterable).

Note that Dart already supports final identifier in for-in loops, since
each iteration has its own variable. This can be seen in the following
example:

main() {
var funs = [];
for (final x in [1, 2, 3]) { // With or without `final`.
funs.add(() => x);
}
funs.forEach((f) => print(f())); // => 1 2 3
}

With the new syntax the final keyword wouldn't be necessary in this example.

Finally, we also had a look at for. Similar to for-in, a for loop, already
now, does not reuse the loop variable, but introduces a fresh variable for
each iteration.

main() {
var funs = [];
for (int i = 0; i < 3; i++) {
funs.add(() => i);
}
funs.forEach((f) => print(f())); // => 0 1 2
}

This means that there is already syntactic sugar happening to make this
happen. It is thus relatively straightforward to support a version where a
loop variable introduced with := is final within the body of the loop.

main() {
var funs = [];
for (i := 0; i < 3; i++) {
funs.add(() => i);
}
funs.forEach((f) => print(f())); // => 0 1 2
}

This would be (roughly) equivalent to:

main() {
var funs = [];
var i_outer;
for (i_outer = 0; i_outer < 3; i_outer++) {
i_inner := i_outer;
funs.add(() => i_inner);
}
funs.forEach((f) => print(f())); // => 0 1 2
}

<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#summary>
Summary

We are investigating ways to make the declaration of final locals easier.
In this proposal we suggest the use of := as new syntax to concisely
declare a fresh final local.

We also propose changes to the for and for-in statements to make the
declaration of final variables concise. The for loop would support the
:= syntax,
and a for-in statement without var or type would implicitly introduce a
fresh final variable.
--
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-11-10 21:30:36 UTC
Permalink
Would it be prudent to make another step in the same direction so that we
can write
for (i := 0; i < 3; i++)
simply as
for (i :<3)
(colon followed by <)
The point is that 90+% of all loops are like this - why do we need an extra
noise, which only invites bugs?
--
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.
Randal L. Schwartz
2017-11-13 17:43:17 UTC
Permalink
Florian> We discussed "x.to(y)", but our experiments showed that most users would
Florian> misinterpret the "y"'s inclusiveness depending on the context. Depending on
Florian> where it was used, readers either expected the 'y' to be part of the range,
Florian> or not.

.upToIncluding(y)
.upToExcluding(y)

and the corresponding .downTo*

Or maybe .upTo is always including, and provide .upToExcluding as the
clear alternative.
--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<***@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/Dart consulting, Technical writing, Comedy, etc. etc.
Still trying to think of something clever for the fourth line of this .sig
--
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-11-13 18:02:18 UTC
Permalink
Or just
for (i in [0..<5])
?
--
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-11-13 18:51:00 UTC
Permalink
Post by Randal L. Schwartz
Florian> We discussed "x.to(y)", but our experiments showed that most users would
Florian> misinterpret the "y"'s inclusiveness depending on the context. Depending on
Florian> where it was used, readers either expected the 'y' to be part of the range,
Florian> or not.
.upToIncluding(y)
.upToExcluding(y)
and the corresponding .downTo*
Or maybe .upTo is always including, and provide .upToExcluding as the
clear alternative.
But then it's so long that it doesn't really buy you a lot anymore. At that
point you might as well just write a `for` loop.
Post by Randal L. Schwartz
--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777
0095 <+1%20503-777-0095>
Perl/Unix/Dart consulting, Technical writing, Comedy, etc. etc.
Still trying to think of something clever for the fourth line of this .sig
--
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
Philipp S
2017-11-13 19:35:05 UTC
Permalink
Post by Randal L. Schwartz
We discussed "x.to(y)", but our experiments showed that most users would
misinterpret the "y"'s inclusiveness depending on the context. Depending on
where it was used, readers either expected the 'y' to be part of the range,
or not.
When talking about ranges, two other use cases come to my mind.
1. bounds checks: checking `i ∈ [0, n)` looks imo better with `const
Range(0, n).contains(i)` than with `0 <= i && i < n`
2. enumerating other types than int: `for (final day in new
Range.inclusive(startDay, endDay, stepsize: const Duration(days: 1)))`

Do you have any experiences to share regarding something like a `class
Range<T extends Comparable<T>> extends Set<T>`?
--
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.
Matthew Butler
2017-11-14 17:48:32 UTC
Permalink
Post by tatumizer-v0.2
Would it be prudent to make another step in the same direction so that we
can write
for (i := 0; i < 3; i++)
simply as
for (i :<3)
(colon followed by <)
The point is that 90+% of all loops are like this - why do we need an
extra noise, which only invites bugs?
My issue with this proposal is that it's extremely limited.
1) I can't decrement?
2) I can't start with a different offset? (eg 1..3 is at least clear it
starts at 1 even if it's arguable if it ends at 2 or 3.)

Concern 1 also applies to the range proposal though as mentioned at least
it's clear that you can start from say 5 and increment to 9. Maybe range
could also support a reverse direction (5..1) which would address point 1
as well.

Both however also run into:
3) Can only increment an individual amount. Eg: I can't do
for (i := 0; i < 10; i += 2) {...}

That said, the range option is a "for in" which acts on an iterator,
whereas I'm assuming your proposal is to replace the for loop syntax based
on your example. I don't see a benefit in shortcutting that limited subset
of usage for the for loop (since it's not specifically acting on an
iterator)
--
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
'Florian Loitsch' via Dart Misc
2017-11-13 17:23:06 UTC
Permalink
On Mon, Nov 13, 2017 at 3:31 AM 'Erik Ernst' via Dart Misc <
On Mon, Nov 13, 2017 at 12:03 PM, Philipp S <
I would prioritize readability over less typing. A range operator
would be a nice addition.
Also, implicit variable declaration is scary, at least for me. I
prefer having all variables explicitly declared.
Note that no variables are declared implicitly, even though the
syntactic marker is small: The `:` in `:=` makes it explicit that this is a
declaration.
There is something else I find really confusing and off-putting about
the proposed `final` in for loops. Lets call the expressions in a for
statement "initializer", "check" and "increment". With the proposed change,
you have this weird situation where the `final` modifier of a loop variable
`i` is scoped to the loop body, but is invisible to the loop expressions.
check and increment can *write* to a final variable! That feels ... wrong,
inconsistent.
The appropriate intuition here is that each step of the iteration gets
its *own* *copy* of the iteration variable (so `i` during the first
iteration is simply a different variable than `i` during the second
iteration). So increment doesn't write to the same final variable at the
beginning of each step, it initializes a fresh final variable.
This is required in order to make function closures that capture the
iteration variable see the value of the iteration where the capture
occurred (even if it is called after the entire loop has terminated). This
is the reason why so many examples use function literals (like () => i) to
show how the iteration variable works. If a single variable had been used
for the entire loop execution then all those closures would have returned
the latest value that this variable had, so the printout would have been `2
2 2` rather than `0 1 2`.
This is not an accident: The language specification section 17.6 explains
the semantics in terms of a fresh variable per iteration, exactly because
of the confusion which is traditionally caused by captured iteration
variables that end up having "the latest value" when such a closure is
invoked.
Actually, the language specification does not spell out how an expression
like `i++` must be considered to mean `ik+1 = ik + 1`. We will fix that.
That's because `i++` only works on one instance of the variable.
The syntax expansion of a for-loop never splits the visibility of a
variable inside an update clause.
This can be observed by capturing the loop variable in the condition and/or
update clause. Then it becames clear which variables are captured.

As part of the `:=` proposal we would also like to simplify this expansion:
capturing inside the condition and update clause would capture a loop
variable (and not the body variables as is currently the case).
But I really like `final` variables in general, and I think the idea to
have them for `for` iteration counters is great! What do you think of
something along these lines: Iff a `for` loop introduces a variable `i` in
its initializer expression as final, then it is already final in the check
and increment expressions, and both must not mutate `i`; After each
iteration, `i` gets assigned the result of evaluating increment.
for (i := 0; i < 10; i + 1) print(i);
--
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
--
Erik Ernst - Google Danmark ApS
Skt Petri Passage 5
<https://maps.google.com/?q=Skt+Petri+Passage+5&entry=gmail&source=g>, 2
sal, 1165 KÞbenhavn K, Denmark
CVR no. 28866984 <28%2086%2069%2084>
--
Erik Ernst - Google Danmark ApS
Skt Petri Passage 5
<https://maps.google.com/?q=Skt+Petri+Passage+5&entry=gmail&source=g>, 2
sal, 1165 KÞbenhavn K, Denmark
CVR no. 28866984 <28%2086%2069%2084>
--
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.
tatumizer-v0.2
2017-11-13 21:00:49 UTC
Permalink
@Florian: if we put it in functional form, like range(0, 3) then it's
certainly exclusive. In dart, whenever you have start and end indexes, end
index is exclusive.
So the natural intuition for anyone who dealt with 30 methods in dart, all
exclusive, is to assume this is exclusive, too.

Elsewhere, if you have double dot for "inclusive", you also have triple dot
for "exclusive". For me, 3 dots look no more exclusive than 2 dots, not
sure what intuition is behind this distinction
--
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-11-13 21:43:47 UTC
Permalink
@Danny: 3 dots is not the point!
The point is: dart proclaims everywhere that endIndex is exclusive. Dart is
proud of his own consistency in that respect.
When I forget everything dart, and remember just 1 thing, this thing is:
endIndex is exclusive.
And suddenly, if you write it as [1..3] it's inclusive. OK, you may not
call it endIndex (that's the only choice if we want to preserve sanity).
Suppose we call it endRange, fine. (Good luck remembering that)

BUT: when you write it for iterating over an array, this "endRange" is
intuitively an "endIndex". Confusion ensues.
--
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-11-14 04:50:05 UTC
Permalink
in Swift:

1. for tickMark in 0..<minutes {
2. // render the tick mark each minute (60 times)
3. }

B I think that's a reasonable choice.

B BTW, in swift, triple dot (as in 1...5) is inclusive. I find it more
intuitive, because mnemonically, 3 dots indicate longer sequence than 2
dots.
--
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
Danny Tuppeny
2017-11-14 17:54:35 UTC
Permalink
Post by tatumizer-v0.2
@Danny: 3 dots is not the point!
The point is: dart proclaims everywhere that endIndex is exclusive. Dart
is proud of his own consistency in that respect.
Sorry, I see what you mean now. This sounds kinda crazy to me though
(endIndex sounds rather like it should be the last index, and having to
explicitly call out that one is inclusive and one is exclusive in the docs
suggests it's not obvious)... v2 is the time to fix (break?) stuff like
this, right? ;-)

Tbh, given this knowledge I think having a range operator might not be such
a great idea - having only an inclusive one would be confusing because of
the reasons above and having two would also be confusing (it's some extra
knowledge you need to know just to read the code correctly, and also may
end up being different to other languages with the same operator).

=/
--
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.
Lee Crocker
2017-11-14 18:14:45 UTC
Permalink
Isn't this a fairly well-settled issue in CS? Array indices that are
0-based and end bounds that are exclusive result in a lot fewer stray "+1"s
littering your code. The fact that ordinary humans think of 3 things as "1,
2, 3" is just a bad habit that we should break early. Maybe in a few
thousand years culture will evolve to use little-endian hexadecimal too,
but I'm not holding my breath for that one. Or maybe I am just biased by
years of Python.
Post by Danny Tuppeny
Post by tatumizer-v0.2
@Danny: 3 dots is not the point!
The point is: dart proclaims everywhere that endIndex is exclusive. Dart
is proud of his own consistency in that respect.
Sorry, I see what you mean now. This sounds kinda crazy to me though
(endIndex sounds rather like it should be the last index, and having to
explicitly call out that one is inclusive and one is exclusive in the docs
suggests it's not obvious)... v2 is the time to fix (break?) stuff like
this, right? ;-)
Tbh, given this knowledge I think having a range operator might not be
such a great idea - having only an inclusive one would be confusing because
of the reasons above and having two would also be confusing (it's some
extra knowledge you need to know just to read the code correctly, and also
may end up being different to other languages with the same operator).
=/
--
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.
Danny Tuppeny
2017-11-14 21:13:50 UTC
Permalink
Post by Lee Crocker
Isn't this a fairly well-settled issue in CS? Array indices that are
0-based and end bounds that are exclusive result in a lot fewer stray "+1"s
littering your code.
But how far should we go applying this to thinks that aren't indexes? What
is the answer to "generate the numbers from 1 to 10"? In English it would
include 10.

That aside, the status quo also isn't perfect - off-by-one/range errors are
still pretty common and people often get < and <= mixed up in conditions.
It's also pretty common to see "array.length - 1" (I actually rather liked
that VBScript had a UBound() function!). I don't know how accurate the
results are, but searching for 'off by one' on GitHub gives 15 million
commits! ;(

I think "exclusive end index" feels ok partly because we're used to it and
partly because in many cases it's the same as length/count - to a
non-programmer I think it would seem rather confusing..

*If you want items 2,3,4 from the array you pass 2 as the start index but 5
as the end index.*

Sounds kinda wonky for not a great reason. Sure, you could argue that
non-programmers aren't programming, but we should really be working to
reduce the amount of knowledge needed to get started (or at least, the
potential for people to get confused/do things wrong - especially things
that blow up at runtime).

I'm not sure we'll ever get away from exclusive-end-index but I do think in
many cases it could've been avoided (eg. maybe startIndex and length would
work in many cases and eliminate the potential for confusion - I'm aware I
said something was silly in C# yesterday, but now I'm thinking it makes
sense!). I also think we should be very careful extending the idea to
things that just aren't indexes.
--
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-11-14 21:33:21 UTC
Permalink
I don't see a benefit in shortcutting that limited subset of usage
This "limited subset" accounts for 90+% of use cases. In any natural
language, any phrase occurring with such frequency would be very quickly
abbreviated. That's why use see expressions like 'BTW', "WRT', 'LOL' so
often.
And swift realizes it, too. It provides a general construct for iteration
up or down and with step N, but this general case is intentionally made
verbose. However, for the case of (int i=0; i<n; i++) it provides a more
concise form 0..<n
--
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.
Matthew Butler
2017-11-15 16:11:56 UTC
Permalink
I don't see a benefit in shortcutting that limited subset of usage
This "limited subset" accounts for 90+% of use cases.
Based on what sample source is this? Looking through a number of projects
and the dart sdk itself, it appears that 75% of usages are for in clauses.
While the remaining clauses are roughly 80% of for (i = 0; i < value; i++)
your statement doesn't hold true in the least.
In any natural language, any phrase occurring with such frequency would be
very quickly abbreviated. That's why use see expressions like 'BTW', "WRT',
'LOL' so often.
if this were the rule, then how is it the only usage in your text is to
cite it as an example which isn't use?
And swift realizes it, too. It provides a general construct for iteration
up or down and with step N, but this general case is intentionally made
verbose. However, for the case of (int i=0; i<n; i++) it provides a more
concise form 0..<n
So you're saying swift provides a range operator (not a for loop
construct, since it's usable outside of for loops as well) Which itself is
more usable than your proposal (for instance I don't need to start at 0).
--
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-11-15 17:28:04 UTC
Permalink
Post by Matthew Butler
Based on what sample source is this?
But the discussion is not about "for ... in" ... - it's about for (i=v0;
i<v1; i++), right? I admit I took 90% from the thin air, but your 80%
don't refute that (in statistics, everything is a bit fuzzy).

As an aside: I personally use 'for in' only for the stuff that is not
performance-critical. In libraries, especially in low-level libraries, my
instinct is to avoid 'for in' because I'm not sure how well it would
perform. (I suspect it would suck, but I might be wrong).
To get good performance, compiler has to optimize 'for in' for arrays
specifically (as opposed to generic Iterable) - I have no idea if it's done
or not, and for what kinds of arrays. (Again, please correct me if I'm
wrong)

Also, you often need both element and index. And if performance is not an
issue, then why not use just functional form like "map" or forEach or
what-not? Then you don't even need 'for in'! But all this is beside the
point, b/c we are discussing traditional "for".

To find out the proportion exactly, there's no choice but writing a script
that runs through large collection of dart code. Then we will know for sure
whether it's 80% or 90% or something else, but my bet still remains :).
--
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-11-15 23:11:05 UTC
Permalink
Post by Philipp S
, I'd write: ∀i∈[0, n)∩ℕ₀
Is that notation also taught/used wherever you come from?
It might depend not so much on the country, but on specific tastes of the
author of the textbook. I find the above notation funny. Why real numbers
and open intervals should get involved here? If my memory doesn't fail me,
in Russian textbooks of the time (40 years ago), they would simply say ∀i,
0 <= i < n or maybe ∀i∈ℕ, 0 <= i < n (notice comma, which stands for "such
that")
(<= is one symbol, of course)
There was another notation like i ∈ { 0, 1, ... n-1 } - I think it was more
common. And that's the notation I meant. Maybe the times have changed
though.
--
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.
Istvan Soos
2017-11-16 06:55:49 UTC
Permalink
for (i :<3) [... vs ...] for (int i = 0; i < 3; i++)
Anecdotal evidence: I like the "for (int i = 0; i < n; i++) {}" much
better than any of the suggestions in this thread. *Explicit* in every
part, leaves no room to guesswork, and unless you have 20+ character
variables for i and n, it will fit in a single line, easily readable.

I have spent probably more time reading this thread than the time I
could have spared by not typing the additional 3-8 characters in each
of my for loops ever, no matter how clever the abbreviation could have
been. That is the cost of not being explicit: you need to interpret
it, and people from different background may interpret it differently
(and argue about it). For me, that is a good indicator that even if it
were to hit the language, I wouldn't use it, because others reading
the code will get harder time to interpret it.

Cheers,
Istvan
--
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-11-16 12:20:58 UTC
Permalink
Post by Istvan Soos
*Explicit* in every
part, leaves no room to guesswork
And a lot of room for fun debugging your nested loops where you forget to
rename i to j in i++
There;s a good summary of disadvantages here:
https://github.com/apple/swift-evolution/blob/master/proposals/0007-remove-c-style-for-loops.md
I like this argument (re-phrasing a bit)
If the for-loop did not exist, and was just submitted for discussion today,
it would most likely be rejected as a bad idea. (in dart, I'm 100% sure
about it)

I have personal grudge against for loops (on several occasions, forgot to
rename i to j), so can't be objective :)
--
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.
Istvan Soos
2017-11-16 16:21:20 UTC
Permalink
And a lot of room for fun debugging your nested loops where you forget to rename i to j in i++
I'd classify this issue in the linter-rule category: if the
middle-condition or the increment references a variable from another
for loop, but none from the current one, make it a warning. It would
still allow "for (int j = 0; j < i; j++)", but would warn about "for
(int j = 0; i < length; j++)" or "for (int j = 0; j < i; i++)".
If the for-loop did not exist, and was just submitted for discussion today, it would most likely be rejected as a bad idea.
I'd be curious if there is a serious and modern programming language
that *doesn't have* "for (int i = 0; i < n; i++)" style loop, *and*
has something else that serves similar purpose. My guess is the
traditional for loop survives across languages because it solves a
problem reasonable well.

Cheers,
Istvan
--
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-11-16 16:31:02 UTC
Permalink
Post by Istvan Soos
I'd be curious if there is a serious and modern programming language
that *doesn't have* "for (int i = 0; i < n; i++)" style loop, *and*
has something else that serves similar purpose.
Swift? Kotlin? I suspect every modern language got rid of it, no?
--
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-11-16 23:16:43 UTC
Permalink
Post by tatumizer-v0.2
Swift? Kotlin? I suspect every modern language got rid of it
Adding to the list:
nim
Julia
Rust
R
Actually, every language I looked into. The only exception is go, but it
stands out on many fronts :)

.
--
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.
Filipe Morgado
2017-11-17 13:04:03 UTC
Permalink
"For loops", "while", even "if", etc ... could be obsolete and replaced
with iterators and closures.

Range(0, 10).forEach((int i) {
... do something with 'i' ...
});

With range syntax and shorter 'forEach' (like C#):
0..10.each((/*int is inferred*/ i) {
... do something with 'i' ...
});
"0..10", "0...10", "0..<10", "10..>=0" ... whatever ... as long as it's
expressive.

And with special syntax for methods which take a closure as single argument:
0..10.each |i| {
... so something with 'i' ...
}

With good editor support, we'd just write "0..10.ea"<ENTER> and it would
insert the block above.
It's quite faster than writing "for(int i = 0; i < 10; i++) {}" by hand.

It would work well for maps:
final myMap = new Map<String, String>();
myMap.each |k, v| { // String k, String v is inferred
... do something with 'k', 'v' ...
}
// Or ...
myMap.each |k, v| => DoSomething(k, v);

It's "different" (compared to old mainstream languages) and would hinder
the Dart's familiarity goal, but I think it would be a nice improvement.

Of course, this would only work if the abstraction is zero-cost, all
structures inlined and all allocations sunk.

I'd vote for this.
--
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-11-19 23:33:36 UTC
Permalink
I think it would be interesting to add not just one, but 2 tricks:
1) support a literal [x..<y] (e.g. [0..<3] which returns an Iterable<int>,
same as [0, 1, 2]
2) for Iterable<int>, support operators *int and +int, so we can write
[0..<3]*2+1 - which is equivalent to [1, 3, 5]
Then we can write
for (i in [0..<3]*2+1) {...}
and
for (i in [0..<3]*-2-1) // descending sequence

Cute? Stupid? All of the above? :)
Not sure there's a language that provides this feature. I think it will
become an instant hit!
(In principle, we can multiply Iterables<int> - in the sense of Cartesian
product. But here the things become a bit complicated :)
--
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.
'Erik Ernst' via Dart Misc
2017-11-14 09:31:42 UTC
Permalink
On Mon, Nov 13, 2017 at 6:23 PM, 'Florian Loitsch' via Dart Misc <
Post by 'Florian Loitsch' via Dart Misc
On Mon, Nov 13, 2017 at 3:31 AM 'Erik Ernst' via Dart Misc <
On Mon, Nov 13, 2017 at 12:03 PM, Philipp S <
I would prioritize readability over less typing. A range operator
would be a nice addition.
Also, implicit variable declaration is scary, at least for me. I
prefer having all variables explicitly declared.
Note that no variables are declared implicitly, even though the
syntactic marker is small: The `:` in `:=` makes it explicit that this is a
declaration.
There is something else I find really confusing and off-putting about
the proposed `final` in for loops. Lets call the expressions in a for
statement "initializer", "check" and "increment". With the proposed change,
you have this weird situation where the `final` modifier of a loop variable
`i` is scoped to the loop body, but is invisible to the loop expressions.
check and increment can *write* to a final variable! That feels ... wrong,
inconsistent.
The appropriate intuition here is that each step of the iteration gets
its *own* *copy* of the iteration variable (so `i` during the first
iteration is simply a different variable than `i` during the second
iteration). So increment doesn't write to the same final variable at the
beginning of each step, it initializes a fresh final variable.
This is required in order to make function closures that capture the
iteration variable see the value of the iteration where the capture
occurred (even if it is called after the entire loop has terminated). This
is the reason why so many examples use function literals (like () => i) to
show how the iteration variable works. If a single variable had been used
for the entire loop execution then all those closures would have returned
the latest value that this variable had, so the printout would have been `2
2 2` rather than `0 1 2`.
This is not an accident: The language specification section 17.6
explains the semantics in terms of a fresh variable per iteration, exactly
because of the confusion which is traditionally caused by captured
iteration variables that end up having "the latest value" when such a
closure is invoked.
Actually, the language specification does not spell out how an expression
like `i++` must be considered to mean `ik+1 = ik + 1`. We will fix that.
That's because `i++` only works on one instance of the variable.
The syntax expansion of a for-loop never splits the visibility of a
variable inside an update clause.
I just noted that the current specification, avoiding such a split into two
variables in the update clause, will not work when the loop variable is
final. In the concrete example it would make an attempt to evaluate `ik+1++`
(17.6.1 says evaluate [*v''/v*]*e*, where *v''* is ik+1, *v* is i, and *e*
is i++). So we will need to say it in a slightly different way.

This can be observed by capturing the loop variable in the condition and/or
Post by 'Florian Loitsch' via Dart Misc
update clause. Then it becames clear which variables are captured.
As part of the `:=` proposal we would also like to simplify this
expansion: capturing inside the condition and update clause would capture a
loop variable (and not the body variables as is currently the case).
But I really like `final` variables in general, and I think the idea to
have them for `for` iteration counters is great! What do you think of
something along these lines: Iff a `for` loop introduces a variable `i` in
its initializer expression as final, then it is already final in the check
and increment expressions, and both must not mutate `i`; After each
iteration, `i` gets assigned the result of evaluating increment.
for (i := 0; i < 10; i + 1) print(i);
--
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
--
Erik Ernst - Google Danmark ApS
Skt Petri Passage 5
<https://maps.google.com/?q=Skt+Petri+Passage+5&entry=gmail&source=g>,
2 sal, 1165 KÞbenhavn K, Denmark
CVR no. 28866984 <28%2086%2069%2084>
--
Erik Ernst - Google Danmark ApS
Skt Petri Passage 5
<https://maps.google.com/?q=Skt+Petri+Passage+5&entry=gmail&source=g>, 2
sal, 1165 KÞbenhavn K, Denmark
CVR no. 28866984 <28%2086%2069%2084>
--
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
--
Erik Ernst - Google Danmark ApS
Skt Petri Passage 5, 2 sal, 1165 KÞbenhavn K, Denmark
CVR no. 28866984
--
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
Danny Tuppeny
2017-11-13 18:14:24 UTC
Permalink
This only supports a fixed start though, it'd probably be better as
range(int x, int y)..
I realise I misread the suggestion now - I guess it meant 10.upTo(20)
rather than int.upTo(20).

Feels a bit weird to me having an Iterable<int>-returning method hanging
off an int though.
--
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.
Randal L. Schwartz
2017-11-13 19:27:33 UTC
Permalink
Danny> Feels a bit weird to me having an Iterable<int>-returning method hanging
Danny> off an int though.

Any worse than String.split?
--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<***@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/Dart consulting, Technical writing, Comedy, etc. etc.
Still trying to think of something clever for the fourth line of this .sig
--
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.
Philipp S
2017-11-13 13:00:50 UTC
Permalink
I would prioritize readability over less typing. A range operator
would be a nice addition.
Also, implicit variable declaration is scary, at least for me. I
prefer having all variables explicitly declared.
Note that no variables are declared implicitly, even though the
syntactic marker is small: The `:` in `:=` makes it explicit that this is a
declaration.
There is something else I find really confusing and off-putting about
the proposed `final` in for loops. Lets call the expressions in a for
statement "initializer", "check" and "increment". With the proposed change,
you have this weird situation where the `final` modifier of a loop variable
`i` is scoped to the loop body, but is invisible to the loop expressions.
check and increment can *write* to a final variable! That feels ... wrong,
inconsistent.
The appropriate intuition here is that each step of the iteration gets
its *own* *copy* of the iteration variable (so `i` during the first
iteration is simply a different variable than `i` during the second
iteration). So increment doesn't write to the same final variable at the
beginning of each step, it initializes a fresh final variable.
Sure, I get what the language does and why it is necessary. I see why a
shared counter variable would be a bad idea. Even though I've never
consciously thought about it before, the distinction between variables
i_{k} and i_{k+1} is what my subconsciousness always expected to happen, as
your example demonstrates.
I think the definition of counter variables with `:=` is different. Now,
you ask the compiler for an immutable variable `i`, and that's what you
get. You're not allowed to assign to `i`. Except for one magic place, the
loop expressions, where assignment to `i` is allowed. This "upgrading a
final variable to a non-final one" is a completely new concept in Dart that
I've never encountered before. This unfamiliarity makes it difficult for me
to predict it's exact functionality and limits.
For example, I couldn't confidently answer the question: "is the check
expression allowed to mutate `i`?" or "Can a final variable be promoted to
non-final if it was not declared in the loop initializer? (probably not)"
But maybe that's just me :-)
I'm just trying to say: Make it more transparent where the expression
i_{k+1} = i_{k} is allowed. When does `i` refer to i_{k}, and when to
i_{k+1}? Sorry for the confusion.
--
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.
Man Hoang
2017-11-15 02:24:11 UTC
Permalink
We can go further by introducing a new for loop to solve the 90+% case.

forn (i, n) {
print(i);
}

// Equivalent to
for (final i = 0; i < n; i++) {
print(i);
}

Another proposal is adding const class.

// Implicit default const constructor.
const class Injectable {}

// Only a const class can extend another const class.
const class Directive extends Injectable {
// Fields are final, no need to include the `final` keyword.
String selector;

// Constructors are const, no need for the `const` keyword.
Directive({this.selector});
}


I actually fired an issue here
<https://github.com/dart-lang/sdk/issues/31372>.
Post by 'Florian Loitsch' via Dart Misc
I will be traveling next week. The next newsletter is therefore only in
two weeks.
https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md
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/20171110.md#did-you-know>Did
You Know?
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#constructors>
Constructors
Dart has many ways to make writing constructors easier or more powerful.
The most known is probably the concise syntax for initializing instance
fields directly in the signature line (see below). This section shows some
other, less known features.
// Concise syntax for initializing fields while declaring parameters.class A {
final int x;
A(this.x);
}
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#generative-constructors>Generative
Constructors
A constructor is "generative", if it is called on a freshly created
instance to initialize the object. This sounds complicated, but just
describes the behavior of the most common constructors.
class A {
int x;
A(int y) : this.x = y + 2;
}
When a user writes new A(), conceptually, the program first instantiates
an uninitialized object of type A, and then lets the constructor
initialize it (set the field x).
The reason for this wording is, that generative constructors can be used
in super calls in initializer lists. When called as super the generative
constructor doesn't instantiate a new object again. It just does its part
of the initialization.
class A {
int x;
A(int y) : this.x = y + 2;
}
class B extends A {
B(int z) : super(z - 1) {
print("in B constructor");
}
}
The order of evaluation is well defined: first all expressions in the
initializer list are evaluated. Then the initializer list of the super
constructor is run. This continues, until Object (the superclass of every
class) is reached. Then, the bodies of the constructors are executed in
reverse order, first starting the one from Object (not doing anything),
and working its way down the class hierarchy.
This evaluation order is usually not noticeable, but can be important when
int _counter = 0;
class A {
final int aCounter;
A() : aCounter = _counter++ {
print("foo: ${foo()}");
}
}
class B extends A {
final int bCounter;
final int field;
B()
: field = 499,
bCounter = _counter++ {
print("B");
}
int foo() => field;
}
main() {
var b = new B();
print("aCounter: ${b.aCounter}");
print("bCounter: ${b.bCounter}");
}
foo: 499
B
aCounter: 1
bCounter: 0
Note that the bCounter expression is evaluated first, yielding 0, and
that aCounter, coming second, is set to 1. Furthermore, the final field
field in B is set to 499 when the constructor in A indirectly accesses
the field.
Dart guarantees that final fields are only visible with their final value.
Dart ensures this property by splitting the construction of objects into
two: the initializer list, and the constructor body. Without this two-phase
initialization Dart wouldn't be able to provide this guarantee.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#factory-constructors>Factory
Constructors
Factory constructors are very similar to static functions, except that
they can be invoked with new. They don't work on an instantiated
(uninitialized) object, like generative constructors, but they must create
the object themselves.
The following example shows how Future.microtask could be implemented
with a factory and the existing Completerclass.
class Future<T> {
factory Future.microtask(FutureOr<T> computation()) {
Completer c = new Completer<T>();
scheduleMicrotask(() { ... c.complete(computation()) ... });
return c.future;
}
}
The actual implementation uses private classes to be more efficient, but
is otherwise very similar to this code.
Factory constructors cannot be used as targets of super in initializers.
(This also means that a class that only has factory constructors cannot be
extended).
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#redirecting-generative-constructor>Redirecting
Generative Constructor
When constructors want to share code it is often convenient to just
forward from one constructor to another one. This can be achieved with
factory constructors, but if the constructor should also be usable as the
target of a super-initializer call, then factory constructors (as
described above) are not an option. In this case, one has to use
class Point {
final int x;
final int y;
Point(this.x, this.y);
}
class Rectangle {
int x0;
int y0;
int x1;
int y1;
Rectangle.coordinates(this.x0, this.y0, this.x1, this.y1);
Rectangle.box(Point topLeft, int width, int height)
: this.coordinates(topLeft.x, topLeft.y, topLeft.x + width, topLeft.y.height);
}
class Square extends Rectangle {
Box(Point topLeft, int width) : super.box(topLeft, width, width);
}
The Rectangle class has two constructors (both generative): coordinates
and box. The box constructor redirects to the coordinates constructor.
As can be seen, a subtype, here Square, can still use the constructor in
the initializer list.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#redirecting-factory-constructors>Redirecting
Factory Constructors
Frequently, factory constructors are just used to instantiate a
differently named class. For example, the Iterable class is actually
abstract and a new Iterable.empty() can't therefore be generative but
must be a factory. With factory constructors this could be implemented as
abstract class Iterable<E> {
factory Iterable.empty() {
return new _EmptyIterable<E>();
}
}
1. there is an unnecessary redirection: the compilers need to inline
the factory constructor, instead of seeing directly that a new
Iterable.empty() should just directly create an _EmptyIterable. (Our
compilers inline these simple constructors, so this is not a real problem
in practice).
2. A factory constructor with a body cannot be const. Clearly, there
is code being executed (even if it's just new _EmptyIterable()), which
is not allowed for const constructors.
abstract class Iterable<E> {
const factory Iterable.empty() = _EmptyIterable<E>;
}
Now, the Iterable.empty() constructor is just a synonym for
_EmptyIterable<E>. Note that we don't even need to provide arguments to
the _EmptyIterable<E> constructor. They *must* be the same as the one of
the redirecting factory constructor.
class C {
final int x;
final int y;
const C(this.x, this.y);
factory const C.duplicate(int x) = _DuplicateC;
}
class _DuplicateC implements C {
final int x;
int get y => x;
const _DuplicateC(this.x);
}
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#shorter-final-variables>Shorter
Final Variables
In Dart it is now easier to declare mutable locals, than to declare
var mutable = 499;final immutable = 42;
Declaring a variable as mutable, but not modifying it, isn't a real
problem per se, but it would be nice, if the var keyword actually
expressed the intent that the variable will be modified at a later point.
We recently looked at different ways to make immutable locals more
appealing. This section contains our proposal.
Instead of using a different keyword (like val) we propose to use an even
shorter syntax for immutable locals: colon-equals (:=).
In this proposal, a statement of the form identifier := expression; introduces
a new *final* local variable.
// DateTime.toString() method.
String toString() {
y := _fourDigits(year);
m := _twoDigits(month);
d := _twoDigits(day);
h := _twoDigits(hour);
min := _twoDigits(minute);
sec := _twoDigits(second);
ms := _threeDigits(millisecond);
us := microsecond == 0 ? "" : _threeDigits(microsecond);
if (isUtc) {
return "$y-$m-$d $h:$min:$sec.$ms${us}Z";
} else {
return "$y-$m-$d $h:$min:$sec.$ms$us";
}
}
As a first reaction, it feels dangerous to just use one character (":") to
introduce a new variable. In our experiments this was, however, not an
issue. In fact, single-character modifiers of = are already common: x += 3 is
also just one character on top of = and we are not aware of any
readability issues with compound assignments. Furthermore, syntax
highlighting helps a lot in ensuring that these variable declarations
aren't lost in the code.
We would also like to support typed variable declarations: Type
identifier := expression. (The following examples are just random
variable declarations of our codebase that have been rewritten to use the
new syntax).
int pos := value.indexOf(":");JSSyntaxRegExp re := pattern;IsolateEmbedderData ied := isolateEmbedderData.remove(portId);
For now, we are only looking at the := syntax for local variables. If it
proves to be successful, we will investigate whether we should allow the
same syntax for final (global) statics or fields.
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#for-loops>For
Loops
For loops are another place where users frequently declare new variables.
There, we need to pay a bit more attention. For example, the for-in
statement doesn't even have any assignment symbol, which we could change to
:=.
When looking at uses of for-in, we found that these loops are almost never
var x;for (x in [1, 2]) {
print(x);
}
In fact, the only cases where we found this pattern was in our own tests...
We thus propose to change the meaning of for (identifier in Iterable). It
should become syntactic sugar for for (final identifier in Iterable).
Note that Dart already supports final identifier in for-in loops, since
each iteration has its own variable. This can be seen in the following
main() {
var funs = [];
for (final x in [1, 2, 3]) { // With or without `final`.
funs.add(() => x);
}
funs.forEach((f) => print(f())); // => 1 2 3
}
With the new syntax the final keyword wouldn't be necessary in this example.
Finally, we also had a look at for. Similar to for-in, a for loop,
already now, does not reuse the loop variable, but introduces a fresh
variable for each iteration.
main() {
var funs = [];
for (int i = 0; i < 3; i++) {
funs.add(() => i);
}
funs.forEach((f) => print(f())); // => 0 1 2
}
This means that there is already syntactic sugar happening to make this
happen. It is thus relatively straightforward to support a version where a
loop variable introduced with := is final within the body of the loop.
main() {
var funs = [];
for (i := 0; i < 3; i++) {
funs.add(() => i);
}
funs.forEach((f) => print(f())); // => 0 1 2
}
main() {
var funs = [];
var i_outer;
for (i_outer = 0; i_outer < 3; i_outer++) {
i_inner := i_outer;
funs.add(() => i_inner);
}
funs.forEach((f) => print(f())); // => 0 1 2
}
<https://github.com/dart-lang/sdk/blob/master/docs/newsletter/20171110.md#summary>
Summary
We are investigating ways to make the declaration of final locals easier.
In this proposal we suggest the use of := as new syntax to concisely
declare a fresh final local.
We also propose changes to the for and for-in statements to make the
declaration of final variables concise. The for loop would support the := syntax,
and a for-in statement without var or type would implicitly introduce a
fresh final variable.
--
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-11-15 05:35:40 UTC
Permalink
Post by Man Hoang
forn (i, n) {
print(i);
}
+1. Simplicity is the mother of beauty :)

For "const"- we need a different keyword for immutable classes. Const is
reserved only for the stuff known at compile time (AFAIK), and this
limitation is much more severe than we need for everything "final".
--
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-11-15 13:07:34 UTC
Permalink
Post by Man Hoang
We can go further by introducing a new for loop to solve the 90+% case.
forn (i, n) {
print(i);
}
// Equivalent to
for (final i = 0; i < n; i++) {
print(i);
}
This doesn't resolve the ambiguity though... In the for loop it's clear
whether n is included or not, but in the forn loop it's not (also, you
can't control the starting number and it seems weird that the i is a
decleration when it looks very similar to the n).

Out of curiosity, I just quizzed a bunch of my colleagues (all pretty
experienced devs). I gave them absolutely no context and just asked them
what they expect "for (i in 1..5)" to do. Only two people didn't say
"1,2,3,4,5" and their answers were:

- I'd expect 1,2,3,4 but only because this seems like a trick question
- 1,2,3,4,5 but I was caught out recently expecting this operator in F# to
work like C#'s Enumerable.Range having the second argument be the count (he
said although it surprised him, it kinda obvious when he realised what it
did)

It's a very small sample (6) but does suggests that an exclusive range is
not a commonly expected result. I don't think introducing a new way of
doing loops that doesn't make it clear whether it's inclusive/exclusive at
the upper bound would be a great idea (depending on whether you're looping
an array or outputting numbers, it would end up wonky with a +1/-1). I
think it's blurring an already confusing concept (array indexes) with
something that doesn't need to be confusing (a sequence of numbers from x
to y).
--
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-11-15 14:22:58 UTC
Permalink
@Danny: I think there's a big difference between
for (i in 1..n)
and
forn (i, n)

The reason for the latter to be perceived as inclusive is that the notation
like '1,...n' is standard in math, and there, it's inclusive.

You have to repeat your (unscientific) poll :)

In dart, all endIndexes are exclusive (as they should be). As soon as just
a single inclusive pattern is introduced - it will ruin the whole show IMO.
--
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.
Philipp S
2017-11-15 15:21:49 UTC
Permalink
the notation like '1,...n' is standard in math, and there, it's
inclusive.
I'm currently studying at a german university, and I've never seen that
notation. When I want to specify an integer range, I'd write: ∀i∈[0, n)∩ℕ₀,
where [0, n) is the range of real numbers from 0 (inclusive) to n
(exclusive), and the intersection with ℕ₀ (non-negative integers) yields
the set {0, 1, 2, ..., n-2, n-1}. Is that notation also taught/used
wherever you come from?

Also, while arguing about a range operator, do you keep in mind that `..`
is already in use for the cascade operator? How about a `to` operator
instead, possibly in conjunction with the range brackets, like so: `[0 to
n], [0 to n), (0 to n], (0 to n)`? One would have to come up with a way to
specify the stepsize, though – or something else that represents the `∩ℕ₀`.
:-)
--
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...