Fuzion Logo
fuzion-lang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

option.fz


# This file is part of the Fuzion language implementation.
#
# The Fuzion language implementation is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, version 3 of the License.
#
# The Fuzion language implementation is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License along with The
# Fuzion language implementation.  If not, see <https://www.gnu.org/licenses/>.


# -----------------------------------------------------------------------
#
#  Tokiwa Software GmbH, Germany
#
#  Source code of Fuzion standard library feature option
#
#  Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------

# option -- feature wrapping a value or nothing
#
# option represents an optional value of type T
#
public option(public T type)
  : switch T nil,
    property.orderable,
    property.hashable

is


  # equality of two options is true iff `a` and `b` are both nil or `a` and `b` are both
  # `T` and T.equality a.get b.get.
  #
  # This is defined only if T : property.equatable, it will result in a compile-time panic
  # if this is not the case.
  #
  public redef fixed type.equality(a, b option T) bool
  =>
    if T : property.equatable
      match a
        av T =>
          match b
            bv T => T.equality av bv
            nil  => false
        nil =>
          match b
            _ T => false
            nil  => true
    else
      compile_time_panic


  # A total order for options is defined as follows: `nil` is always less-than-or-equal
  # any other value and iff `a` and `b` both contain values of type `T`, then
  # `T.lteq a.get b.get`.
  #
  # This is defined only if T : property.orderable, it will result in a compile-time panic
  # if this is not the case.
  #
  public redef fixed type.lteq(a, b option T) bool
  =>
    if T : property.orderable
      match a
        av T =>
          match b
            bv T => T.lteq av bv
            nil  => false
        nil =>
          true
    else
      compile_time_panic


  # create hash code for this option
  #
  # This is defined only if T : property.hashable, it will result in a compile-time panic
  # if this is not the case.
  #
  public redef fixed type.hash_code(a option T) u64
  =>
    if T : property.hashable
      match a
        v T => T.hash_code v
        nil => 0xfe6f6476106a56b6  # generated using secure random generator at https://cryptotools.dev/
    else
      compile_time_panic


  # Does this option contain no value of type T?
  #
  public is_nil bool => !exists


  # monadic operator
  #
  # Same as non-generic >>=, but also maps to a different type B.
  #
  public bind(B type, f T -> option B) option B =>
    option.this ? v T => f v
                | nil => nil


  # converts option to a string
  #
  # returns the result of $T for an option containing an instance
  # of T, alternatively returns $nil for an option that is nil.
  #
  public redef as_string String =>
    option.this ? v T => $v
                | nil => $nil


  # monadic operator for bool result, false for nil
  #
  public infix >>? (f T -> bool) bool
  =>
    option.this ? v T => f v
                | nil => false


  # 'prefix +' (identity)
  #
  public prefix +? option T
  pre
    T : numeric
  => option.this >>= v -> +v


  # 'prefix -' (negation)
  #
  public prefix -? option T
  pre
    T : numeric
  => option.this >>= v -> -?v


  # addition operator
  #
  public infix +? (other option T) option T
  pre
    T : numeric
  => option.this >>= v -> other >>= w -> v +? w


  # subtraction operator
  #
  public infix -? (other option T) option T
  pre
    T : numeric
  => option.this >>= v -> other >>= w -> v -? w


  # multiplication operator
  #
  public infix *? (other option T) option T
  pre
    T : numeric
  => option.this >>= v -> other >>= w -> v *? w


  # exponentation operator
  #
  public infix **?(other option T) option T
  pre
    T : numeric
  => option.this >>= v -> other >>= w -> v **? w


  # division operator
  #
  public infix /? (other option T) option T
    pre
      T : numeric
      safety: !other.is_zero
  =>
    option.this >>= v -> other >>= w -> v / w


  # modulo operator
  #
  public infix %? (other option T) option T
    pre
      T : numeric
      safety: !other.is_zero
  =>
    option.this >>= v -> other >>= w -> v % w


  # equals operator
  #
  public infix ==? (other option T) bool
  pre
    T : numeric
  => option.this >>? v -> other >>? w -> v = w


  # not equals operator
  #
  public infix !=? (other option T) bool
  pre
    T : numeric
  => option.this >>? v -> other >>? w -> v != w


  # lower than operator
  #
  public infix <?  (other option T) bool
  pre
    T : numeric
  => option.this >>? v -> other >>? w -> v <  w


  # lower or equal than operator
  #
  public infix <=? (other option T) bool
  pre
    T : numeric
  => option.this >>? v -> other >>? w -> v ? w


  # greater than operator
  #
  public infix >?  (other option T) bool
  pre
    T : numeric
  => option.this >>? v -> other >>? w -> v >  w


  # greater or equal than operator
  #
  public infix >=? (other option T) bool
  pre
    T : numeric
  => option.this >>? v -> other >>? w -> v ? w


  # is zero
  #
  public is_zero bool
  pre
    T : numeric
  => sign ==? 0


  # sign function resulting in `-1`/`0`/`+1` depending on whether `numeric.this`
  # is less than, equal or larger than zero
  #
  public sign option i32
  pre
    T : numeric
  =>
    bind i32 v->v.sign


  # absolute value
  #
  public abs option T
  pre
    T : numeric
  =>
    option.this >>= v -> if v.sign ? 0 v else -?v



# option with 1 argument provides an shorthand to wrap a value into an option
#
# Using this enables to write
#
#     o := option x
#
# instead of
#
#     o option TypeOfX := x
#
public option(T type, o option T) option T => o

last changed: 2026-03-09