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.

Partition methods unsound on infinite iterables

See original GitHub issue

There are some methods which require arrays to work correctly. Sort is an obvious example. I am going to posit that partition and multiPartition are actually another.

We already know that methods which must operate on arrays are outside the scope of iter-tools. This is primarily because we mean to support all iterables, including infinite iterables, which cannot ever be cached in arrays. This, however, is not the only pitfall of infinite iterables. Another can be easily demonstrated here:

const [winners, alsoRan] = partition(i => i < 3, range())
for (const winner of winners) {
   /* Oops, we created an infinite loop.
    * We will continue trying to pull from the infinite source iterable
    * looking for the next value less than three. There is none.
    */
}

Essentially this means that if you have an infinite iterable, the method will only work well if you are sure that one type of object will never cease appearing in the output.

Consider though the case of the async variants of these methods when they are simply run on large iterables. It would almost always be the case that it would be inappropriate to try to partition the iterables using these methods. Trying to consume any one side of the partition in its entirety would be no faster than consuming the whole source. If I were trying to write code that was responsive to an async iterable of alphas and betas, I’d do something like const [alphas, betas] = partition(isAlpha, source). Then in order to avoid being blocked, I’d have to try to consume the alphas and betas iterables simultaneously, using something like Promise.race to determine which result was actually ready. Essentially at this point the coder would be working defeat the implementation of our method, which mostly has to do with caching items, a behavior that seems to actually be undesired the more I think about it.

I think most of the time the appropriate thing to do in the code is simply

for await (const item of source) {
  if (isAlpha(item)) {
    // Whatever is supposed to happen for an alpha
  } else {
    // Whatever is supposed to happen to beta
  }
}

Can anyone imagine a situation in which it would be more suitable to use partition than to just write a loop like the one above?

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:8 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
sithmelcommented, Jul 15, 2019

Using an infinite iterable we can have basically 2 potential side effect:

  • some method will just blow up (because of memory). toArray and takeSorted for example
  • some other will run forever and never return

From a certain point of view, it should be up to the dev to ensure that this is not happening (“slice” would do the trick easily).

Technically if we don’t implement that it’s a security vulnerability.

I am not sure you could define that as a security vulnerability. It would be like saying that you have to remove the while loop from the language because it can be leveraged to run a DOS.

0reactions
conartist6commented, Jul 17, 2019

The issue partition has over and beyond other similar methods like groupBy is that with groupBy as long as you consume the all the result iterables in order you can be assured that your code will not end up in an infinite loop. With partition, the same consumption strategy will sometimes result in an infinite loop, and sometimes not. In my mind this means that the appropriate thing to do is use lodash: const [evens, odds] = _.partition([...iterable], isEven);.

Read more comments on GitHub >

github_iconTop Results From Across the Web

guava/Iterables.java at master - GitHub
* Removes, from an iterable, every element that does not belong to the provided collection. *. * <p>This method calls {@link Collection#retainAll} if...
Read more >
Iterable - Scala 2.13 Library - W3cubDocs
Inside, the string representations (w.r.t. the method toString ) of all elements ... Partitions this iterable collection into a map of iterable collections ......
Read more >
Scala Standard Library 2.13.3 - scala.collection.Iterable
Partitions this iterable collection into a map of iterable collections according to some ... Partitions elements in fixed size iterable collections.
Read more >
Iterable - Scala 3 - EPFL
Partitions this iterable collection into a map of iterable collections according to some discriminator function.
Read more >
IterableUtils (Apache Commons Collections 4.2 API)
Partitions all elements from iterable into separate output collections, based on the evaluation of the given predicates. ... Note: elements are only added...
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