question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Iterables (and possible breaking change for `$each` and other navigators)

See original GitHub issue

I’d like to add support for iterables. This would automatically add support for Map, Immutable.js, etc.

One immediately obvious problem is the semantics of $each. Currently, $each iterates over each value of an array or object. This mirrored Lodash’s _.each semantics. If you want to iterate over each pair, you use $eachPair.

Iterating over an iterable though is meant to iterate over each of its “entries”. So in the case of Map, that’s each key/value pair. In the case of an array, that’s each value. There’s also a stage 4 proposal for Object.entries which behaves the same way as Map.prototype.entries.

This probably means that $each should probably change to be values for an array and pairs for an object. But that means this:

select([$each], {x: 1, y: 2})
// [1, 2]

Would have to become this:

select([$each, 1], {x: 1, y: 2})
// [1, 2]

Which is kind of ugly. And it prevents you from being able to use the same query on an array or an object, which is often useful. To mitigate that, the current $each behavior could probably move to $eachValue (which is what it was originally named). If an object has a .values function, that can be used as the iterable for $eachValue. So you could have:

select([$eachValue], {x: 1, y: 2})
// [1, 2]

Another option would be to leave $each as-is and add an $eachEntry navigator, but that feels like it’s just adding more API surface area.

A less significant question is whether or not to keep $eachPair after this change. It has arguably limited usefulness for arrays, and for objects, it would effectively be a duplicate of $each. There’s no pairs method for iterables, but looking for keys function should be enough of a clue to determine if entries returns pairs. There’s no rule that says an iterable has to implement these though, or that they have to keep the naming convention, so it’s kind of ambiguous how it should behave in those cases. Throw an error? qim could offer a custom protocol for filling in these gaps (like transducers).

There’s also the question of $first and $last. Currently, they return the first and last value. So after this change, should they return the first and last entry instead? Should there be an equivalent $firstValue and $lastValue to grab the first and last value? The first and last value of an object has less meaning than for arrays, so I think the semantics change here is of less impact, and $firstValue and $lastValue can wait until there’s a real need.

I’ll have to dig into code more to figure out how iterables will affect creating custom navigators, i.e. $traverse. I wanted to surface this change right away though.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:9 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
jdealcommented, May 22, 2017

Practicality trumps purity

That’s kind of where I’m landing @bryanhelmig.

I see no reason to not add $eachEntry

There already is an $eachPair navigator, and I think its behavior is what you’re describing for $eachEntry. When I mentioned $eachEntry, I was talking about perhaps adding something that iterated according to Symbol.iterator behavior:

➜  ~ node
> const array = ['a','b']
undefined
> [...array]
[ 'a', 'b' ]
> const map = new Map()
undefined
> map.set(0, 'a')
Map { 0 => 'a' }
> map.set(1, 'b')
Map { 0 => 'a', 1 => 'b' }
> [...map]
[ [ 0, 'a' ], [ 1, 'b' ] ]

However, I was surprised (just now) to find out that Array.prototype.entries actually returns pairs.

> [...array.entries()]
[ [ 0, 'a' ], [ 1, 'b' ] ]
> [...map.entries()]
[ [ 0, 'a' ], [ 1, 'b' ] ]

So I guess “entry” is just a synonym for “pairs”, so scratch a lot of what I said when I opened this issue, since I should have done a bit more digging first! I think the current behavior of $each, $eachPair and $eachKey is pretty reasonable, so I’m going to leave that as-is. Point taken that $eachKey is unnecessary sugar, but it’s a tad more performant than $eachPair, 0, so I’m going to leave it for now too.

I still think there’s some ambiguity around $first, $slice, etc. that should be cleaned up, and that might be better handled by adding $values, $keys, and $pairs, so I’ll leave this open while I play around with a lazy iterator there.

0reactions
jdealcommented, Jul 8, 2017

Closing this issue, but I wrote another book if you want to check that out.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Iterable support, Map/Set/Immutable support, lazy values/sequences ...
Support iterables like Map and Set and possibly even Immutable.js's ... Iterables (and possible breaking change for $each and other navigators) #4.
Read more >
Iterables - The Modern JavaScript Tutorial
Iterable objects are a generalization of arrays. That's a concept that allows us to make any object useable in a for..of loop.
Read more >
itertools — Functions creating iterators for efficient looping ...
It generates a break or new group every time the value of the key function changes (which is why it is usually necessary...
Read more >
syntax - Why does Java not allow foreach on iterators (only on ...
The way "for each" is in Java (A) is very consistent, it causes very little programming errors, and it allows for the possible...
Read more >
Deprecation Policy - SymPy 1.11 documentation
Discuss the API change with the community. Be sure that the improved API is indeed better, and worth a breakage. · If it...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found