Vacuous
A simple representation of optional values
About
Scala's
Option
is the traditional way to represent values which may be either
present (in which case a value is specified) or absent. Option
is a
simple ADT, but union types, along with some helper methods, can provide much
better ergonomics in most circumstances. Vacuous offers an Optional
type
which provides this functionality.
Features
- Provides an implementation of optional values using union types
- No need to wrap present values in
Some
- Flattened representation, prohibiting ambiguous
Some(None)
representation - Lightweight
let
,lay
andor
methods covermap
,flatMap
,fold
,orElse
andgetOrElse
- Performant inlined implementations of all critical methods
- Especially convenient use case for default parameters
Availability
Vacuous is available as a binary for Scala 3.4.0 and later,
from Maven Central.
To include it in an sbt
build, use the coordinates:
libraryDependencies += "dev.soundness" % "vacuous-core" % "0.1.0"
Getting Started
The Optional
type
An optional value, which might be an instance of ValueType
, or may be
absent, may be given the type Optional[ValueType]
. If it is absent, then it
has the value, Unset
, which is a singleton object. Optional[ValueType]
is
an alias for the union type, ValueType | Unset.type
.
Note that the declarations,
val value: Text = t"Hello world"
and,
val value: Optional[Text] = t"Hello world"
differ only in their types; the syntax of the expression is identical, and does
not need to be wrapped with another factory method, like Some
.
Since union types are unordered sets of types, nesting two Optional
s, for
example in Optional[Optional[Int]]
expands to
Int | Unset.type | Unset.type
, which is identical to Int | Unset.type
. And
this is the same as Optional[Int]
. While there is nothing to prevent nesting
one Optional
within another Optional
, it's impossible to distinguish
between the types, and impossible for an Unset
value to be considered
present rather than absent; it is the definition of absence.
or
, let
and lay
An Optional[Text]
value may seem very similar to a Text
value, but the
possibility that it might be Unset
makes it impossible to use any methods
defined on Text
on an Optional[Text]
, since those methods are not
applicable to just one of the possible values of the type, Unset
. So several
convenience methods are provided to make Optional
s easy to work with.
The method or
replaces the Unset
value with another value, eliminating the
optionality from the type. This is equivalent to both getOrElse
and
orElse
on Option
. This equivalence comes from the lack of nesting of
Optional
values.
Similarly, let
applies a lambda to the present values, and leaves the
absent value unchanged. It is equivalent to both map
and flatMap
on
Option
s.
Finally, lay
combines or
and let
in a single, two-parameter method: the
alternative value for Unset
is specified first, followed by the lambda
mapping the present values. This is equivalent to fold
on an Option
.
These method names were deliberately chosen to be short, as they are intended to be used frequently and are rarely the most interesting part of an expression.
License
Vacuous is copyright © 2024 Jon Pretty & Propensive OÜ, and is made available under the Apache 2.0 License.