Skip to content

Commit

Permalink
Make Optional an IterableOnce (#1418)
Browse files Browse the repository at this point in the history
* Make `Optional` an `IterableOnce`

So that we can:
```
def get(a: A): Optional[B] = ...
val list: List[A] = ...
val result: List[B] = list.flatMap(get)
```

* scalafmt

* fix compilation

* Make it compile with Scala 2.12

* Make tests pass

* clean

* Clean

* Make test fail

* Make test pass

* Make test fail

* Make test pass

* Fix CI
  • Loading branch information
guizmaii authored Nov 17, 2024
1 parent e59e50a commit 760c31c
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package zio.prelude.data

import zio.Scope
import zio.prelude.ZIOBaseSpec
import zio.test.{Spec, TestEnvironment, assertTrue}

object OptionalSpec extends ZIOBaseSpec {

override def spec: Spec[TestEnvironment with Scope, Any] =
suite("Optional")(
test("is an IterableOnce") {
def get(a: Int): Optional[Long] = Optional.Present(a.toLong)
val list: List[Int] = List(1, 2, 3)
val result: List[Long] = list.flatMap(get)

assertTrue(result == List(1L, 2L, 3L))
}
)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package zio.prelude

/**
* Needed because Scala 2.12 doesn't have `IterableOnce`
*/
private[prelude] trait IterableOnceCompat[+A] {

/**
* Copied from `IterableOnce#iterator`
*/
def iterator: Iterator[A]

/**
* Adapted from `IterableOnce#knownSize`
*/
def knownSize: Int

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package zio.prelude

/**
* Needed because Scala 2.12 doesn't have `IterableOnce`
*
* TODO: Remove when support for Scala 2.12 is dropped
*/
private[prelude] trait IterableOnceCompat[+A] extends IterableOnce[A]
11 changes: 9 additions & 2 deletions core/shared/src/main/scala/zio/prelude/data/Optional.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package zio.prelude.data

import zio.Chunk
import zio.prelude.IterableOnceCompat

import scala.language.implicitConversions

Expand All @@ -13,7 +14,7 @@ import scala.language.implicitConversions
* The only difference between this type and [[scala.Option]] is that there is an implicit
* conversion defined from `A`` to `Optional[A]`, and from `Option[A]`` to `Optional[A]`.
*/
sealed trait Optional[+A] { self =>
sealed trait Optional[+A] extends IterableOnceCompat[A] { self =>
val isEmpty: Boolean
val isDefined: Boolean
val nonEmpty: Boolean
Expand Down Expand Up @@ -122,7 +123,7 @@ sealed trait Optional[+A] { self =>
final def orElse[B >: A](alternative: => Optional[B]): Optional[B] =
if (isEmpty) alternative else this

final def iterator: Iterator[A] =
override final def iterator: Iterator[A] =
self match {
case Optional.Present(get) => Iterator.single(get)
case Optional.Absent => Iterator.empty
Expand All @@ -145,6 +146,12 @@ sealed trait Optional[+A] { self =>
case Optional.Present(get) => Vector(get)
case Optional.Absent => Vector.empty
}

/**
* Copied from `Option.knownSize`
*/
override final def knownSize: Int = if (isEmpty) 0 else 1

}

object Optional {
Expand Down

0 comments on commit 760c31c

Please sign in to comment.