-
Notifications
You must be signed in to change notification settings - Fork 213
Should spread of a List
use the Iterable protocol or direct iteration?
#208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
cc @rakudrama |
I assume you mean In the general case, you don't know the starting position, and the result needs to be growable, so the indexing version is incorrect in allocating a fixed length list and in assuming the length is easily known and the indexes in the source and target match. dart2js would need to figure out that I think desugaring to something like I don't see why on ES6 we can't compile this to, well, Lowering to a single operation would also aid in special case recognition, e.g. of splicing into the start of a list, which might be compiled to something like JavaScript's |
Native lists are not really the problem here. If you know that you have a native list, you also know the behavior of the iterator, and you can implement it any way you want that is indistinguishable from iterating (and most approaches are, because you know the list operations do not have side effects). So, the only place where this matters is when the object is, at I was aware of the issue when writing the spec, but decided that it was best to keep things simple.
The "iteration order" is generally defined as the order the When a specification doesn't say which user-declared members it accesses, we have unspecified behavior. Different implementations may act differently on the same code, and the best suggestion to avoid that is to not use the feature. For all we know, it might use Option 2 would require using Option 3 would require using Option 4 gives implementations the option of choosing either 1., 2. or 3. on a per location basis. The reason I decided to not do any of these is that it's consistent with [for (var i = 0; i < x.length; i++) x[i]] (The only difference is that we allow spreads as constant expressions, but not the iteration that gives access to individual elements, but you shouldn't worry over the performance of constant expressions anyway). So, spreads are specified in one simple way, and if you want something else, you do have an alterntaive option. I think that's sufficient. |
Cf. #209 (comment), it might be good for the overall simplicity of the language if we could use Cf. comment from Lasse, an argument against this could be that we use iteration as the semantics of for-in statements, so it's a matter of consistency among spreads vs. consistency among different occurrences of iterables. Edit: @leafpetersen mentioned that there's strong evidence that |
I took a stab at writing a benchmark for a couple of different ways we could desugar spreads if we know the spread object is a List of some type. On my Mac laptop, here are the numbers:
The in-progress code for this is: #210 |
Apart from the general approach (iterate, List for, etc.), one thing that we might want to reserve the option to do is to build sets from existing sets with improved performance: Set<T> s1 = e; // Non-trivial expression, implementation may not be known.
var s2 = {...s1, some, extra, stuff}; The point is that it may actually be a common situation that a set is created by taking an existing set and adding a few extras to it, and in this situation we can transfer elements without any checks for having each element already: Developers would need to know that it's much better to write The new set |
We could say that we use Saying that we use I'd consider "use So, the most efficient solution is probably to allow any implementation which accesses elements in iteration order, and to use |
But instead of considering this to 'allow anything' we should probably rely on the documentation of the method (e.g., https://api.dartlang.org/stable/2.1.0/dart-core/List/addAll.html), because that's already exactly what developers have today. We might then want to specify the |
My general take is that there is no real user value in requiring spreading an Using I think overall, I would prefer that we just use the obvious list iteration loop as the specification for how we spread a |
Note that using |
Here are some updated numbers for dart2js using
|
I did some more benchmarking and investigation and wrote up my thoughts. We discussed this more in the language meeting. The decision is:
We think this should give implementations enough freedom to optimize without adding much complexity to the spec. |
The current proposed semantics given by the spread collections proposal specify spreading into a list using the
Iterable
protocol. So we have thatde-sugars to (roughly):
We could, in the case where we are statically spreading something of type
List
, use a direct loop as follows:This is likely to be significantly more efficient, but is not a valid optimization that a compiler can do in the absence of extra information about the implementation type of the
List
.cc @munificent @lrhn @ferhatb
The text was updated successfully, but these errors were encountered: