-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
#each over iterables #4289
Comments
Duplicate of #2968 See the discussion there. You can achieve the same thing using proxy object (yeah, @pngwn, I know you're not a fan 😛 ). See my implementation of Python-like range function: |
This isn’t about syntax sugar for ranges. This is about supporting the core iteration protocol of JavaScript. Once you do that, ranges and iterating over |
Things that are iterable out-of-the-box in ES2015:
…and any custom object that has a |
Yeah, I get it... please read the entire thread of the mentioned issue. |
Sure, but your actual iterable proposal is nestled deep within a thread about Python-style ranges.
I guess I don’t understand the above assertion from @pngwn. Iterators are fundamental to JavaScript. There’s nothing to understand unless you don’t use |
Because it was in response to a custom function that iterates. To write such a function you would need to understand the protocol. We weren’t discussing changes to the compiler at that point. |
I don't really see how Svelte could write compiled code that would be any more efficient than something that's equivalent to |
This is about developer ergonomics, not performance. I tried to do an ‘{#each}’ on a ‘Set’ and it didn’t work. I was assuming ‘for…of’ semantics because that’s built into the language. |
Allowing the same syntax to be used for both array-like objects and iterables is something that's come up before, and has been rejected before because it adds an extra check to everyone's each blocks, whether they want to use this feature or not. It does seem helpful and practical though to add a dev mode runtime check to ensure that the object passed to an each is indeed an array-like - with a specific human-readable error message if not. It wouldn't help having to type the extra characters, but it would help with confusing runtime behavior. |
If someone can point me to the relevant section in the compiler, I’d love to take a crack at a PR. Mostly for my own edification; it doesn’t sound like there’s much support here. (That's OK and an expected part of the process.) Thanks, all. |
@Conduitry, Sorry, I know this is closed, but is that right? Surely: if (Array.isArray(things)) {
for (; i < things.length; i += 1) {
callback(things[i], i, i);
}
} else if (typeof Symbol !== 'undefined' && Symbol.iterator in things) {
for (const thing of things) {
callback(thing, i, i++);
}
} taken directly from #894 (comment) is already a lot more efficient for iterables? And only slightly less efficient than currently, for arrays? (I mean surely, really not a significant impact - neither in bundle size nor speed - especially not for the gain of making the API much less surprising, as well as more efficient for what might be a common, growing use-case.) |
@Conduitry, @mikebeaton, using a the compiler now compiles for (let i = 0; i < each_value.length; i += 1) {
each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i));
} but, it can compile to let i = 0;
for (let x of each_value) {
each_blocks[i] = create_each_block(get_each_context(ctx, x, i++));
} no check, no conditionals, no worries... |
This sounds right, and is obviously related to this comment #894 (comment) by @Rich-Harris . May be an issue around support in different versions of JS? I know @sw-yx is interested in this too. |
This should've been implemented honestly, what is wrong with absolux's suggestion? Just compile |
I would also like to see each support iterable. As for large number of elements it is not prefarable to convert the iterable to an array and sometimes it can be problamatic. |
@jmakeig Could you please consider reopening this issue? |
The people have spoken? |
I noticed another issue which possibly is similar to this one, #7425. |
Yes, thank you - closing as duplicate of #7425 |
Or vice versa. Sigh. |
@dummdidumm This issue is 2 years older and has more upvotes than #7425. |
Is your feature request related to a problem? Please describe.
Today,
{#each}
only works overArray
andArray
-like objects (i.e. that have a numericlength
property). However, ES2015 introduces iterables using the built-inSymbol.iterator
. To use{#each}
with an iterable you have to remember to convert it to anArray
first, such as{#each [...myIterable] as item}
. (This conversion probably does more work too, but I’m more concerned with developer ergonomics than performance or overhead.)#894 muddies the water because
Object
properties aren’t iterable. As that issue concludes, the proper way to iterate over properties is by getting an iterable fromObject.keys()
or the newerObject.entries()
.#3225 illustrates the problem of having to sniff out the type of iterable before looping over it.
Set
is notArray
-like by design but is iterable.Describe the solution you'd like
I’d expect
{#each}
to work with any iterable.Array
would work as it does today becauseArray
instances are iterable. Duck typedArray
-like objects would be the outlier. However, converting anArray
-like object to an iterable is trivial and could happen under-the-covers.Describe alternatives you've considered
{#each [...myIterable] as item}
works, but it’s an extra conversion to remember. Iterators were designed just for this purpose.How important is this feature to you?
In the grand scheme of things, not super important, but one of those things you bump up against periodically.
Additional context
Here a reproduction.
The text was updated successfully, but these errors were encountered: