Skip to content
This repository has been archived by the owner on Mar 10, 2024. It is now read-only.
This repository has been archived by the owner on Mar 10, 2024. It is now read-only.

Using iterable rest syntax #31

Open
jridgewell opened this issue Jan 31, 2020 · 8 comments
Open

Using iterable rest syntax #31

jridgewell opened this issue Jan 31, 2020 · 8 comments

Comments

@jridgewell
Copy link
Member

jridgewell commented Jan 31, 2020

I recently had the need to get the last-ish elements again. Twice actually:

  1. Getting matchIndex from String.p.replace when using a function:

    string.replace(pattern, (fullMatch, ...submatches, matchIndex, fullString) => {
      // `matchIndex` is always the second to last param (the full string is the last param).
      // There may be many submatch params, depending on the pattern.
    });
  2. Getting the last element of an array of IntersectionObserverEntry:

    const io = new IntersectionObserver(entries => {
      // There may be many entries, but only the last one
      // is needed to see if element is currently visible.
      // The rest are stale.
      const [..., last] = entries;
    })

I propose repurposing iterable's rest ... syntax (with an optional binding) to get the last (or last-ish) elements:

// Grab the last, don't care about anything else.
const [..., last] = iterable;

// Grab second-to-last, throw the rest away.
const [..., secondToLast, last] = iterable;

// Can even keep the initial elements
const [...initial, last] = iterable;

// Can repurpose inside params:
function foo(..., last) {
}

It's not perfect (there's no equivalent way to set the last item), but it seems natural with destructuring syntax. We just need to prevent multiple ... from being used it the same iterable destructure.

@keithamus
Copy link
Member

I really like this, it can provide a great deal of flexibility in getting first/last elements, I could imagime it being used like [first, second, ..., last] = iterable. My only concern is that it'd have to consume the entire iterator, unless we added new protocols to more efficiently get elements at arbitrary indexes (which is antithetical to Iterator's design).

@ljharb
Copy link
Member

ljharb commented Jan 31, 2020

if this worked with just the three dots, I’d also expect to be able to put a binding there and collect the third through penultimate items.

Also, I’d expect [first, ...] to exhaust the iterator (where [first] does not exhaust it)

@keithamus
Copy link
Member

I’d also expect to be able to put a binding there and collect the third through penultimate items.

I assume you mean converting it to [first, second, ...some, last], right?

@ljharb
Copy link
Member

ljharb commented Jan 31, 2020

Yes, exactly that :-)

@jridgewell
Copy link
Member Author

My only concern is that it'd have to consume the entire iterator, unless we added new protocols to more efficiently get elements at arbitrary indexes (which is antithetical to Iterator's design).

I think they can optimize this for arrays that have not been patched. For anything else, yes, I think they'll have to consume the iterator.

@hax
Copy link
Member

hax commented Feb 1, 2020

I like the idea, python support similar feature. But there are some problems:

  1. Performance. It seems these syntax need to exhaust the iterator, so it would be bad for potential long list when you could use O(1) access time. And how to handle infinite iterable, is it just make your browser halted? Could we have some way to throw preventatively for these cases? For example, iterator[Symbol.disallowReverse]()?

  2. What happened on [...rest, secondToLast, last] = [1]? I suppose the answer would be rest=[], secondToLast=1, last=undefined, so conceptually last is not last, but secondToLast in this case 😂 . Note, we could make it rest=[], secondToLast=undefined, last=1, but we need also explain how [a, b, ...c, d, e] = [1, 2, 3] behave. I remember vaguely there are some weird cases in other language which have similar feature, but can't find the discussion now.

@hax
Copy link
Member

hax commented Feb 1, 2020

Maybe [...rest, secondToLast, last] = o could be sugar to [last, secondToLast, ...rest] = o[Symbol.reverse]() ? See https://gist.github.com/leobalter/092fc36adccfcc86e8e7b074817078e1 for stage 1 reverse iterator proposal.

@hax
Copy link
Member

hax commented Feb 1, 2020

Have an idea and create a gist for it: https://gist.github.com/hax/285172c95550d3a46c4c997a13ce3614

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants