Skip to content

Instantly share code, notes, and snippets.

@johnhungerford
Last active November 10, 2023 18:35
Show Gist options
  • Select an option

  • Save johnhungerford/b3ccf0f46783db765688dba19bfba4a3 to your computer and use it in GitHub Desktop.

Select an option

Save johnhungerford/b3ccf0f46783db765688dba19bfba4a3 to your computer and use it in GitHub Desktop.

Revisions

  1. johnhungerford revised this gist Nov 9, 2023. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions ZeroOverHeadOption.scala
    Original file line number Diff line number Diff line change
    @@ -22,7 +22,7 @@ object Opt:
    def isDefined: Boolean = !isEmpty
    def nonEmpty: Boolean = isDefined

    def fold[O](default: => O)(f: T => O): O =
    def fold[U](default: => U)(f: T => U): U =
    if nullable == null then default
    else f(nullable.asInstanceOf[T])

    @@ -35,17 +35,17 @@ object Opt:
    def toStringTagged: String =
    fold("None")(v => s"Some($v)")

    def map[O](f: T => O): Opt[O] =
    def map[U](f: T => U): Opt[U] =
    flatMap(f)

    def flatMap[O](f: T => Opt[O]): Opt[O] =
    def flatMap[U](f: T => Opt[U]): Opt[U] =
    if nullable == null then null else f(nullable.asInstanceOf[T])

    def zip[U](other: => Opt[U]): Opt[(T, U)] =
    flatMap(t => other.flatMap(u => t -> u))

    def getOrElse[O >: T](o: => O): O =
    if nullable == null then o else nullable.asInstanceOf[T]
    def getOrElse[U >: T](u: => U): U =
    if nullable == null then u else nullable.asInstanceOf[T]

    def get : T =
    nullable.getOrElse(throw new NullPointerException())
  2. johnhungerford revised this gist Nov 9, 2023. 1 changed file with 0 additions and 4 deletions.
    4 changes: 0 additions & 4 deletions ZeroOverHeadOption.scala
    Original file line number Diff line number Diff line change
    @@ -14,10 +14,6 @@ object Opt:

    val None: Opt[Nothing] = null

    extension (none: Opt[Nothing])
    def unapply(isNone: Null): Option[Unit] =
    scala.Some(())

    object Some:
    def apply[T](value: T): Opt[T] = value

  3. johnhungerford renamed this gist Nov 9, 2023. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. johnhungerford created this gist Nov 9, 2023.
    122 changes: 122 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,122 @@
    //> using scala 3.3.0

    import scala.util.{Try, Success, Failure}
    import scala.reflect.Typeable
    import scala.util.NotGiven
    import scala.annotation.implicitNotFound

    type Opt[T] = Opt.Opt[T]

    object Opt:
    opaque type Opt[+T] = T | Null

    def apply[T](value: T): Opt[T] = value

    val None: Opt[Nothing] = null

    extension (none: Opt[Nothing])
    def unapply(isNone: Null): Option[Unit] =
    scala.Some(())

    object Some:
    def apply[T](value: T): Opt[T] = value

    extension [T](nullable: Opt[T])
    def isEmpty: Boolean = nullable == null
    def isDefined: Boolean = !isEmpty
    def nonEmpty: Boolean = isDefined

    def fold[O](default: => O)(f: T => O): O =
    if nullable == null then default
    else f(nullable.asInstanceOf[T])

    def contains(t: T): Boolean = fold(false)(_ == t)
    def exists(f: T => Boolean): Boolean = fold(false)(f)

    def flatten[U](using hasInnerOpt: T =:= Opt[U]): Opt[U] =
    fold(None)(t => hasInnerOpt(t))

    def toStringTagged: String =
    fold("None")(v => s"Some($v)")

    def map[O](f: T => O): Opt[O] =
    flatMap(f)

    def flatMap[O](f: T => Opt[O]): Opt[O] =
    if nullable == null then null else f(nullable.asInstanceOf[T])

    def zip[U](other: => Opt[U]): Opt[(T, U)] =
    flatMap(t => other.flatMap(u => t -> u))

    def getOrElse[O >: T](o: => O): O =
    if nullable == null then o else nullable.asInstanceOf[T]

    def get : T =
    nullable.getOrElse(throw new NullPointerException())

    def toOption: Option[T] = fold(scala.None)(scala.Some.apply)

    def toRight[L](left: => L): Either[L, T] =
    if nullable == null then Left(left) else Right(nullable.asInstanceOf[T])

    def toLeft[R](right: => R): Either[T, R] =
    if nullable == null then Right(right) else Left(nullable.asInstanceOf[T])

    def toList: List[T] = fold(Nil)(_ :: Nil)
    def toSet: Set[T] = fold(Set.empty[T])(t => Set(t))
    def toMap[K, V](using T =:= (K, V)): Map[K, V] =
    fold(Map.empty)(tup => Map(tup))
    def toVector: Vector[T] = fold(Vector.empty)(t => Vector(t))

    object syntax:
    extension[L, R](either: Either[L, R])
    def toOpt: Opt[R] = either match
    case Left(_) => null
    case Right(value) => value

    def toOptLeft: Opt[L] = either match
    case Left(value) => value
    case Right(_) => null

    extension[T](_try: Try[T])
    def toOpt: Opt[T] = _try match
    case Success(value) => value
    case Failure(_) => null

    def toOptFail: Opt[Throwable] = _try match
    case Success(_) => null
    case Failure(err) => err

    extension[T](option: Option[T])
    def toOpt: Opt[T] = option.fold(Opt.None)(Opt.apply)


    object Main:
    def main(args: Array[String]): Unit =
    import Opt.syntax.*

    val a : Opt[String] = Opt("hi")
    val b : Opt[String] = Opt(null)
    val c : Opt[String] = Opt("what")
    val d : Opt[String] = Right("hello").toOpt
    val e : Opt[String] = Left('c').toOpt

    println(a.toStringTagged)
    println(b.toStringTagged)
    println(c.toStringTagged)
    println(d.toStringTagged)
    println(e.toStringTagged)

    val res1 = for {
    aVal <- a
    bVal <- b
    } yield aVal + aVal

    val res2 = for {
    aVal <- a
    cVal <- c
    } yield aVal + cVal

    println(res1.toStringTagged)
    println(res2.toStringTagged)