Skip to content

Nil.par.reduceLeft should throw UnsupportedOperationException, not NoSuchElementException #137

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

Closed
retronym opened this issue Nov 10, 2020 · 3 comments

Comments

@retronym
Copy link
Member

% scala --scala-version 2.13.3 -Corg.scala-lang.modules::scala-parallel-collections:1.0.0-RC1
Welcome to Scala 2.13.3 (OpenJDK 64-Bit Server VM, Java 14.0.1).
Type in expressions for evaluation. Or try :help.

scala> List.empty[String].reduce(_ + _)
java.lang.UnsupportedOperationException: empty.reduceLeft
  at scala.collection.IterableOnceOps.reduceLeft(IterableOnce.scala:723)
  at scala.collection.IterableOnceOps.reduceLeft$(IterableOnce.scala:720)
  at scala.collection.AbstractIterable.reduceLeft(Iterable.scala:920)
  at scala.collection.IterableOnceOps.reduce(IterableOnce.scala:692)
  at scala.collection.IterableOnceOps.reduce$(IterableOnce.scala:692)
  at scala.collection.AbstractIterable.reduce(Iterable.scala:920)
  ... 32 elided

scala> import scala.collection.parallel.CollectionConverters._
import scala.collection.parallel.CollectionConverters._

scala> List.empty[String].par.reduce(_ + _)
java.util.NoSuchElementException: None.get
  at scala.None$.get(Option.scala:627)
  at scala.None$.get(Option.scala:626)
  at scala.collection.parallel.ParIterableLike.reduce(ParIterableLike.scala:361)
  at scala.collection.parallel.ParIterableLike.reduce$(ParIterableLike.scala:360)
  at scala.collection.parallel.immutable.ParVector.reduce(ParVector.scala:40)
  ... 32 elided
@xirc
Copy link
Contributor

xirc commented Mar 19, 2021

Nil.par.min and Nil.par.max may have the same issue.

I have used "org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.1".

root@9d686781776b:/opt/scala-parallel-collections/sandbox# sbt
[info] welcome to sbt 1.4.3 (AdoptOpenJDK Java 11.0.9.1)
[info] loading project definition from /opt/scala-parallel-collections/sandbox/project
[info] loading settings for project sandbox from build.sbt ...
[info] set current project to sandbox (in build file:/opt/scala-parallel-collections/sandbox/)
[info] sbt server started at local:///root/.sbt/1.0/server/ac048f6b25b988f0e872/sock
[info] started sbt server
sbt:sandbox> console
[info] Starting scala interpreter...
Welcome to Scala 2.13.5 (OpenJDK 64-Bit Server VM, Java 11.0.9.1).
Type in expressions for evaluation. Or try :help.

scala> import scala.collection.parallel.CollectionConverters._
import scala.collection.parallel.CollectionConverters._

scala> List.empty[Int].min
java.lang.UnsupportedOperationException: empty.min
  at scala.collection.IterableOnceOps.min(IterableOnce.scala:914)
  at scala.collection.IterableOnceOps.min$(IterableOnce.scala:912)
  at scala.collection.AbstractIterable.min(Iterable.scala:919)
  ... 35 elided

scala> List.empty[Int].par.min
java.util.NoSuchElementException: None.get
  at scala.None$.get(Option.scala:627)
  at scala.None$.get(Option.scala:626)
  at scala.collection.parallel.ParIterableLike.min(ParIterableLike.scala:466)
  at scala.collection.parallel.ParIterableLike.min$(ParIterableLike.scala:465)
  at scala.collection.parallel.immutable.ParVector.min(ParVector.scala:40)
  ... 35 elided

scala> List.empty[Int].max
java.lang.UnsupportedOperationException: empty.max
  at scala.collection.IterableOnceOps.max(IterableOnce.scala:945)
  at scala.collection.IterableOnceOps.max$(IterableOnce.scala:943)
  at scala.collection.AbstractIterable.max(Iterable.scala:919)
  ... 35 elided

scala> List.empty[Int].par.max
java.util.NoSuchElementException: None.get
  at scala.None$.get(Option.scala:627)
  at scala.None$.get(Option.scala:626)
  at scala.collection.parallel.ParIterableLike.max(ParIterableLike.scala:470)
  at scala.collection.parallel.ParIterableLike.max$(ParIterableLike.scala:469)
  at scala.collection.parallel.immutable.ParVector.max(ParVector.scala:40)
  ... 35 elided

But, Nil.par.minBy and Nil.par.maxBy don't have.

scala> List.empty[String].minBy(_.length)
java.lang.UnsupportedOperationException: empty.minBy
  at scala.collection.IterableOnceOps.minBy(IterableOnce.scala:1025)
  at scala.collection.IterableOnceOps.minBy$(IterableOnce.scala:1023)
  at scala.collection.AbstractIterable.minBy(Iterable.scala:919)
  ... 35 elided

scala> List.empty[String].par.minBy(_.length)
java.lang.UnsupportedOperationException: empty.minBy
  at scala.collection.parallel.ParIterableLike.minBy(ParIterableLike.scala:480)
  at scala.collection.parallel.ParIterableLike.minBy$(ParIterableLike.scala:479)
  at scala.collection.parallel.immutable.ParVector.minBy(ParVector.scala:40)
  ... 35 elided

scala> List.empty[String].maxBy(_.length)
java.lang.UnsupportedOperationException: empty.maxBy
  at scala.collection.IterableOnceOps.maxBy(IterableOnce.scala:978)
  at scala.collection.IterableOnceOps.maxBy$(IterableOnce.scala:976)
  at scala.collection.AbstractIterable.maxBy(Iterable.scala:919)
  ... 35 elided

scala> List.empty[String].par.maxBy(_.length)
java.lang.UnsupportedOperationException: empty.maxBy
  at scala.collection.parallel.ParIterableLike.maxBy(ParIterableLike.scala:474)
  at scala.collection.parallel.ParIterableLike.maxBy$(ParIterableLike.scala:473)
  at scala.collection.parallel.immutable.ParVector.maxBy(ParVector.scala:40)
  ... 35 elided

@xirc
Copy link
Contributor

xirc commented Mar 19, 2021

maxBy throws UnsupportedOperationException if a collection is empty 😄 .

https://github.com/scala/scala-parallel-collections/blob/v1.0.1/core/src/main/scala/scala/collection/parallel/ParIterableLike.scala#L473-L477

  def maxBy[S](f: T => S)(implicit cmp: Ordering[S]): T = {
    if (isEmpty) throw new UnsupportedOperationException("empty.maxBy")

    reduce((x, y) => if (cmp.gteq(f(x), f(y))) x else y)
  }

reduce does not 😢 .
tasksupport.executeAndWaitResult(new Reduce(op, splitter)) produces None if a collection is empty.
Then, None.get throws NoSuchElementException.

https://github.com/scala/scala-parallel-collections/blob/v1.0.1/core/src/main/scala/scala/collection/parallel/ParIterableLike.scala#L360-L362

  def reduce[U >: T](op: (U, U) => U): U = {
    tasksupport.executeAndWaitResult(new Reduce(op, splitter)).get
  }

IMO, it would be nice to check whether a collection is empty or not at first in the reduce function.

FYI, scala.collection.IterableOnce also does.

https://github.com/scala/scala/blob/2.13.x/src/library/scala/collection/IterableOnce.scala#L724-L741

  def reduceLeft[B >: A](op: (B, A) => B): B = {
    val it = iterator
    if (it.isEmpty)
      throw new UnsupportedOperationException("empty.reduceLeft")
    //...

@xirc
Copy link
Contributor

xirc commented Mar 19, 2021

I attempt to resolve this issue at #167 😃

@lrytz lrytz closed this as completed Mar 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants