Last active
May 20, 2021 03:09
-
-
Save ChristopherDavenport/9159d81353ac6c8a61ac38e6d2678d14 to your computer and use it in GitHub Desktop.
Zero Allocation Option Alternative
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Note `Opt[Opt[A]]` is always a lie, and can and should be flattened to `Opt[A]` | |
* | |
* Any layer of `Opt` is equivalent to `| Null`, which in terms of union types | |
* means that more than 1 layer of `| Null` is the same as the first, so don't | |
* attempt to use this with more than 1 layer, | |
* | |
* If you want more than 1 layer ever, you should probably use Option. | |
* You should probably use Option regardless, Some(None) is a meaningful type, and there is | |
* no way to represent that with this type. | |
*/ | |
opaque type Opt[A] = A | Null | |
object Opt { | |
def apply[A](a: A): Opt[A] = a | |
def empty[A]: Opt[A] = null | |
def lift[A](a: A | Null): Opt[A] = a | |
def fromOption[A](opt: Option[A]): Opt[A] = opt.orNull | |
def when[A](cond: Boolean)(a: => A): Opt[A] = | |
if (cond) Opt(a) else Opt.empty | |
def guard(cond: Boolean): Opt[Unit] = | |
when(cont)(()) | |
def unless[A](cond: Boolean)(a: => A): Opt[A] = | |
when(!cond)(a) | |
} | |
extension [A](opt: Opt[A]) | |
/** Show Method, cannot override toString on opaque type which is at runtime the underlying type */ | |
def show: String = | |
fold("None")((a: A) => s"Some(${a.toString})") | |
def orNull: A | Null = opt | |
def map[B](f: A => B): Opt[B] = | |
if (opt == null) then | |
opt.asInstanceOf[Opt[B]] | |
else | |
f(opt) | |
def foreach[U](f: A => U): Unit = | |
fold(()){(a: A) => f(a); ()} | |
def flatMap[B](f: A => Opt[B]): Opt[B] = | |
if (opt == null) then | |
opt.asInstanceOf[Opt[B]] | |
else | |
f(opt) | |
def flatten[B](implicit ev : A <:< Opt[B]): Opt[B] = flatMap(identity) | |
def toOption: Option[A] = | |
if opt == null then | |
Option.empty[A] | |
else | |
Some(opt) | |
def toList: List[A] = | |
if opt == null then | |
Nil | |
else opt :: Nil | |
def fold[B](ifEmpty: => B)(f: A => B): B = | |
if (opt == null) then | |
ifEmpty | |
else | |
f(opt) | |
def getOrElse(orElse: => A): A = fold(orElse)(identity) | |
def orElse(orElse: => Opt[A]): Opt[A] = fold(orElse)(Opt(_)) | |
def isDefined: Boolean = fold(false)(_ => true) | |
def nonEmpty: Boolean = isDefined | |
def isEmpty: Boolean = !isDefined | |
/** Returns true if this option is nonempty and the predicate p returns true when applied to this scala.Option's value. */ | |
def exists(f: A => Boolean): Boolean = fold(false)(a => f(a)) | |
/** Returns true if this option is empty or the predicate p returns true when applied to this scala.Option's value. */ | |
def forall(f: A => Boolean): Boolean = fold(true)(a => f(a)) | |
/** Returns a scala.Some containing the result of applying pf to this scala.Option's contained value, if this option is nonempty and pf is defined for that value. Returns None otherwise. */ | |
def collect[B](f: PartialFunction[A, B]): Opt[B] = flatMap{(a: A) => | |
if (f.isDefinedAt(a)) then | |
Opt(f(a)) | |
else | |
Opt.empty | |
} | |
/** Returns this scala.Option if it is nonempty and applying the predicate p to this scala.Option's value returns true. Otherwise, return None. */ | |
def filter(f: A => Boolean): Opt[A] = fold(Opt.empty[A]){(a: A) => | |
if f(a) then | |
Opt(a) | |
else | |
Opt.empty | |
} | |
/** Returns this scala.Option if it is nonempty and applying the predicate p to this scala.Option's value returns false. Otherwise, return None. */ | |
def filterNot(f: A => Boolean): Opt[A] = filter(f.andThen(!_)) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment