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

outcome.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 outcome
#
#  Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------

# outcome -- result type for functions that may return an error
#
# outcome is a choice type that represents the result of a routine that
# may either produce something useful or fail producing an error condition.
#
# Several error conditions are needed if there are several very different
# reasons for an operation to fail, e.g.
#
#   getData (u User, t Type) outcome data IOError PermissionError is
#     if u.allowedToAcces T
#       (readFile t.fileName)?
#     else
#       PermissionError u, t
#
#   readFile t Type outcome data IOError is
#     [..]
#
# Note that 'outcome data IOError' is not assignment compatible with
# 'outcome data IOError PermissionError', it has to be unwrapped first.
# This unwrapping, however, requires very little boilerplate, it is done
# using the '?' on the result of the call to 'readFile': This unwraps
# 'outcome data IOError' into 'IOError', which would be returned abruptly,
# and 'data', which would be returned normally. Both are assignment
# compatible to  'outcome data IOError PermissionError', so everything
# is fine.
#
outcome(T type) : choice T error /* ...  NYI: this should be open generic! */ is

  # Does this outcome contain a value of type T?
  #
  ok => (outcome.this ? T     => true
                      | error => false)


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


  # Does this outcome contain an error
  #
  isError => !ok


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


  # value of an outcome that is known to contain a value
  #
  # This can only be called in cases where it is known for sure that this
  # outcomee is not an error.  A runtime error will be created otherwise.
  #
  val T
    pre
      safety: outcome.this??
  is
    outcome.this ? v T   => v
                 | error => panic "outcome.val called on error"


  # value of an outcome or default if outcome contains err
  #
  val(default T) T
  is
    outcome.this ? v T   => v
                 | error => default


  # error of an outcome that is known to contain an error
  #
  # This can only be called in cases where it is known for sure that this
  # outcomee is an error.  A runtime error will be created otherwise.
  #
  err error
    pre
      safety: outcome.this!!
  is
    outcome.this ? T       => panic "outcome.err called on successful outcome"
                 | e error => e


  # convert this outcome to an option
  # if the outcome is an error, the option is empty
  as_option() option T is
    match outcome.this
      t T => t
      error => nil


  # converts outcome to a string
  #
  # returns the result of T.asString for a successful outcome, or
  # "--$e--" for e error.
  #
  redef asString =>
    outcome.this ? v T     => v.asString
                 | e error => "--$e--"


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