-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Open
Description
I was using explicit nulls recently in a scala3 only project and had to deal with a java API that returned null. I took a moment to make a small wrapper to use a more FP style:
import scala.quoted.*
opaque type Nullable[+T] = T | Null
object Nullable:
extension [T](inline nullable: Nullable[T])
transparent inline def fold[A](inline ifNull: => A)(inline fn: T => A): A =
${ foldImpl('nullable, 'ifNull, 'fn) }
inline def isNull: Boolean =
fold(true)(_ => false)
inline def nonNull: Boolean =
fold(false)(_ => true)
inline def map[B](inline fn: T => B): Nullable[B] =
fold(null: Null)(fn)
inline def flatMap[B](inline fn: T => Nullable[B]): Nullable[B] =
fold(null: Null)(fn)
inline def toOption: Option[T] =
fold(None)(Some(_))
inline def iterator: Iterator[T] =
fold(Iterator.empty)(Iterator.single(_))
inline def apply[A](inline a: A | Null): Nullable[A] =
a
private def foldImpl[T: Type, A: Type](
nullable: Expr[Nullable[T]],
ifNull: Expr[A],
fn: Expr[T => A]
)(using Quotes): Expr[A] =
'{
val n = $nullable
given CanEqual[T | Null, Null] = CanEqual.derived
if (n == null) $ifNull
else {
val safe: T = n.asInstanceOf[T]
${ Expr.betaReduce('{ $fn(safe) }) }
}
}I think this type could have lawful implementations of many typeclasses: Monad, Traverse, Foldable, Hash, Order, Eq, Monoid, Group (maybe more algebraic typeclasses).
Should I flesh this out and make a PR to add it to cats.data perhaps? It could be nice to have a zero-cost abstraction for nullable types from Java and javascript interop.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels