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

switch.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 switch
#
# -----------------------------------------------------------------------

# switch is the parent feature of all choices
# that encode success and failure,
# e.g.    option  (something/nil)
#      or outcome (something/error)
#
public switch(A type, B type /* NYI: B should be open generic */)
  : choice A B,
    monad A switch.this,
    Sequence A,
    property.equatable
is

  # NYI: CLEANUP: decide name: exists/ok, get/val?

  # Does this switch contain a value of type A?
  #
  public exists bool =>
    switch.this ? A => true
                | B => false


  # Does this switch contain a value of type A?
  #
  public ok bool => exists


  # shorthand postfix operator for 'exists'
  #
  public postfix ?? bool => exists


  # shorthand postfix operator for '!exists'
  #
  public postfix !! bool => !exists


  # shorthand prefix operator for '!exists'
  #
  public prefix ! bool => !exists


  # value of a switch or default if switch contains B
  #
  public or_default(default A) A
  =>
    switch.this ? a A => a
                | B   => default


  # synonym for infix >>=
  #
  public and_then (f A -> switch.this) switch.this =>
    match switch.this
      a A => f a
      b B => b


  # returns o if switch is of type A, otherwise return the
  # switches B.
  #
  public and (O type, o switch.this) switch.this =>
    match switch.this
      A   => o
      b B => b


  # if this switch is a B return the result of f
  # otherwise just return this switch.
  #
  public or (f Lazy switch.this) switch.this =>
    match switch.this
      a A => a
      B   => f()


  # unwraps an switch if it exists, returns default value otherwise.
  #
  public or_else(default Lazy A) A =>
    switch.this ? v A => v
                |   B => default



  # converts switch into a list of either a single element in case
  # switch.this.exists or `nil` otherwise
  #
  public redef as_list list A
  =>
    switch.this ? a A => a : nil
                | B => nil


  # convert this switch to an option
  #
  public as_option option A
  =>
    switch.this ? a A => a
                | B => nil


  # convert this switch to an outcome
  #
  public as_outcome outcome A
  =>
    switch.this ? a A => a
                | B => error "switch.as_outcome: no error message provided"


  # convert this switch to an outcome
  #
  public as_outcome(e error) outcome A
  =>
    switch.this ? a A => a
                | B => e


  # monadic operator
  #
  public redef infix >>= (f A -> switch.this) switch.this =>
    switch.this ? a A => f a
                | b B => b


  # return function
  #
  # NYI: BUG:
  #
  # ./build/modules/base/src/switch.fz:180:21: error 1: Wrong result type in redefined feature
  #   public redef type.return (a A) => a
  #
  # In 'switch.type.return' that redefines 'monad.type.return'
  # result type is       : 'switch.type.A'
  # result type should be: 'switch.this switch.type.A switch.type.B' (from 'monad.type.MA')
  #
  #
  # public redef type.return (a A) switch.this => a


  # get A or cause an `exception T`
  #
  public or_cause(T type, e B->error) A =>
    match switch.this
      a A => a
      b B => (exception T).env.cause (e b)


  # get A or panic with `B.as_string`
  #
  public or_panic A =>
    match switch.this
      a A => a
      b B => panic $b


  # fold this choice to new type `C`.
  #
  # this is useful when you don't want to break
  # fluent-style code.
  #
  # example:
  #
  #     "haystack"
  #       .find "needle"
  #       .fold (idx -> "found needle at {idx}") (_ -> "could not find needle")
  #
  #
  public fold(C type, fa A->C, fb B->C) C =>
    match switch.this
      a A => fa a
      b B => fb b


  # converts switch to a string
  #
  public redef as_string String =>
    match switch.this
      a A => $a
      b B => $b


  # equality implementation
  #
  # result is only true if both x and y or
  # of choice type A and x.A = y.A
  #
  public redef fixed type.equality(x, y switch A B) bool
  =>
    if A : property.equatable
      x ? xa A =>
          y ? ya A => xa = ya
            | _  B => false
        | _  B => false
    else
      compile_time_panic

last changed: 2026-04-02