-
Notifications
You must be signed in to change notification settings - Fork 48
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
Array spread operator #187
Comments
+1! I'd expect |
Requiring spacing is imho something needed anyway. |
With partially-applied operators from LiveScript and Prelude.ls, this becomes a little gratuitous. |
You forgot a |
@Nami-Doc: Whoops, I was thinking about Haskell. |
However, this would run Other thoughts: I can imagine extending this proposal to pipes as well, since they are essentially applicable expressions:
Or even more crazy overloads of
|
Another thought:
|
Destructuring is indeed nice there, and unrelated to the issue (tbh I thought coco allowed it since LS does, suprised here) |
Whoops, coco does indeed support destructuring forms in the for loop, didn't test it beforehand. |
Two concerns OTTOMH: EvaluationWhile the simple unrolling to For comparison, Groovy's spread evaluates the arguments first, then passes the values around:
NarrownessThe proposed syntax limits its application to property access and method calling. This is much less useful in JS (especially ES3 where extensions of native prototypes are frowned upon) than Groovy. I'd prefer something more generic, say:
as an analogue to:
|
Like it. Would have done this already if we were assuming ES5. |
|
Shim-able, but we wouldn't since We could do without |
I actually ran into this problem where I discovered this use case:
Where To solve this, the spread operator could cache any complex expressions in the RHS: var len, ref$, i, ref$x
for (i = 0, ref$ = $$('.file'), len = ref$.length, ref$x = constructClickFn('type'); i < len; ++i) {
ref$[i].addEventListener('click', ref$x)
} Similar to other sugars in coco.
True that the spread star is pretty limited, but it's hard to beat the conciseness as opposed to
At the very least, it's no more narrow in application than the repeat For the more general case:
This syntax would be good, or perhaps a "spread pipe":
Though you could also cache complex expressions in this syntax, it's probably harder to avoid caching wanted side effects, e.g.
But the Array extras are still quite a bit slower than the for loop, which I think is a bigger argument for keeping it.
Couldn't we still compile that sugar to for loops?
I used |
I love both syntaxes. One without side effects (*), the other with (for &) |
The RHS can be arbitrarily complex. Caching is nonviable unless we limit it to a single access/call, narrowing it further.
I was assuming an idealistic ES5 where those methods and closures were so well-optimized that we wouldn't have to avoid them. |
Yeah, but the spread operator is such a simple sugar that the RHS is very likely not complex, so as long as we choose a working compilation strategy (cache all expressions in the RHS, perhaps), It's unlikely anybody will notice. It's kind of like destructuring; you can do really complicated destructures like And in regards to narrowing it further, such a neutered spread operator would still be at least as useful as, say, the prototypical clone unary operator I'll draw the parallel to jQuery again: all its methods are spread by default. Having syntax-level support for spreads essentially enables to use jQuery without including jQuery, while also freeing ourselves from predefined spread methods that operate only on DOM elements (or writing boilerplate for custom methods). Similarly, cascades are just syntax-level method chaining. There's clearly a demand for these sugars, even as slower function calls, so if we can get them faster, without writing any extra code, that's a win. |
Your example with multi-level access ( To rephrase, there would be no way to cache if the spread were to consume the rest of the chain. It'd have to be either Groovy-style (single access/call with arguments caching) or soak-style (simple unrolling). |
But unlike
Sure, this can break if some of the properties are actually getters with side effects, or some of the method calls have side-effects that would have affected the cached value of an expression, but that shouldn't stand in the way of a compilation strategy that will work in the majority of cases. Furthermore, if the caching style of
For a simpler but still syntactically shorter compilation. |
That way you mess up the evaluation order, which I think is worse than leaving them uncached. |
var ref$, ref1$, i$, ref$, len$, el, ref2$;
for (i$ = 0, len$ = (ref$ = expr).length; i$ < len$; ++i$) {
el = ref$[i$];
if ((ref1$ = el.safe) != null) {
ref1$.access.butWith((ref$ == null && $ref = complicated()(arguments, function(){
throw Error('unimplemented');
}), ref$));
}
} |
Similar to Groovy's spread operator:
as sugar for:
Essentially, the spread operator is a syntax level
map
orforEach
for simple cases, without the performance hit of the ES5 versions and more compact syntax. Also somewhat an extension of unary spread (#98).Use cases
Sub-decisions
Precedence
Should:
compile to:
or:
Guards
The groovy spread desugars as:
Note the guarded property access. I don't think the coco version needs the guard by default. Perhaps instead we could provide a separate
expr*?prop
syntax (distinct fromexpr?*prop
).ADI
ADI for the spread operator would clobber compact multiplication
a*b
, though it's not a huge deal sincedash-identifiers
does the same to subtraction.The text was updated successfully, but these errors were encountered: