Skip to content

A Nullable type for scala3 #4822

@johnynek

Description

@johnynek

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions