Fuzion Logo
flang.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
#
option(T type) :
  choice T nil,
  monad T (option T)
is

  # Does this option contain a value of type T?
  #
  exists => (option.this ? T   => true
                         | nil => false)


  # short-hand postfix operator for 'exists'
  #
  postfix ?? => exists


  # Does this option contain no value of type T?
  #
  isNil => !exists


  # short-hand postfix operator for 'isNil'
  #
  postfix !! => isNil


  # monadic operator
  #
  # This is handy to implement functions on optional values. As an example,
  # take an option string and you would like to add a filename suffix to
  # this string if it is present. Then you can do this as follows:
  #
  #   addTxt(o option string) => o >>= s -> option string is s + ".txt"
  #
  # NYI: With better type inference and syntactic sugar, this should be
  #
  #   addTxt(o option string) => o >>= s -> s + ".txt"
  #
  # NYI: Should maybe have generic parameter B and result in option B
  #
  redef infix >>= (f T -> option T) => option.this.bind f


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


  # synonyme for infix >>=
  andThen (f T -> option T) => option.this >>= f


  # map this option using f, i.e., map nil to nil and any value v to f v
  #
  map(B type, f T -> B) option B is
    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.
  #
  redef asString string is
    option.this ? v T => $v
                | nil => $nil


  # unwraps an option that is known to contain a value
  #
  # this can only be called in cases where it is known for sure that this option
  # is not nil.  A runtime error will be created otherwise.
  #
  get
    pre
      safety: option.this??
    =>
      option.this ? v T => v
                  | nil => fuzion.std.panic "option.get called on nil"


  # unwraps an option if it exists, returns default value otherwise.
  #
  get(default T)
    =>
      option.this ? v T => v
                  | nil => default

  # unwraps an option if it exists, returns default value otherwise. default
  # is evaluated lazily.
  #
  lazyGet(default ()->T)
    =>
      option.this ? v T => v
                  | nil => default()


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


# type related to option declaring features not requiring an instance of option
#
options(redef A type) : monads A (option A) is


  # return function
  #
  return (a A) => option a