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 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> : 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 a 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 => fuzion.std.panic "outcome.val called on error"


  # 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       => fuzion.std.panic "outcome.err called on successful outcome"
                 | e error => e


  # 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
#
# insted of
#
#   o outcome<TypeOfX> := x
#
outcome<T> (o outcome<T>) => o