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

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

# choice -- feature used for choice types
#
# choice types provide algebraic sum types of all the generic arguments
# provided to choice.  A instance of a choice type is a tagged union of
# the types provided as actual generic type parameters.  This concept is
# also called variant, sum type or coproduct in other contexts.
#
# Syntactic sugar of the Fuzion language permits an alternative notation
# for choice types with actual generics as follows
#
#   A | B | C | ...
#
# which is equivalent to
#
#   choice<A, B, C, ...>
#
# The parser will directly convert the first notation into a choice type
# with actual generics.
#
# A field of choice type can be assigned a value of the same choice type
# or of any of the actual generic type arguments provided to the choice
# feature.
#
# Two choice types choice<A,B> and choice<B,A> that differ only in the order
# of their actual generic arguments are treated as different types.
#
# Named choice types can be constructed through inheritance, i.e.,
#
#   C : choice<A,B> is {}
#
# creates a choice type of A and B with the name C.  Two named choice types
# D and E that inherit from choice with the same actual generic arguments in
# the same order are nevertheless different types and their values are not
# assignable to one another.
#
# Named choice types may declare or inherit additional inner features as long
# as these features are not fields.  Also, declared inner features must not
# build a closure that accesses outer features.  Additional parents must be
# unit types, i.e., they must not declare fields nor access features of any
# of their outer features.
#
# Note that all types provided must be distinct, it is not possible to
# repeat the same type as in choice<i32,i32> or float | float.  If a sum
# type of two or more equal types is desired, these types must first be
# wrapped into a new type as illustrated in the following example:
#
# Say we want to store a temperature that is given as a 32 bit integer
# in degrees centigrade or degrees Fahrenheit.  So we define two wrapper
# features
#
#   centigrade(degrees i32) is {}
#   fahrenheit(degrees i32) is {}
#
# Now we define the choice type using the wrapped i32 types, which are
# distinct:
#
#   temp centigrade | fahrenheit := ...
#
# When assigning values to temp, we need to wrap the values accordingly:
#
#   set temp := centigrade 37
#   set temp := fahrenheit 99
#
# When matching the choice type, we use the wrapper types and access the
# argument field 'degrees' to access the i32 stored inside
#
#   match temp
#     c centigrade => say "it's " + c.degrees + "°C"
#     f fahrenheit => say "it's " + f.degrees + "°F"
#
# NYI: Once Fuzion's match statement supports destructuring as well, we should
# be able to extract the degrees directly as in
#
#   match temp
#     centigrade d => say "it's " + d + "°C"
#     fahrenheit d => say "it's " + d + "°F"
#
# A choice type with no actual generic arguments is isomorphic to 'void', i.e, it
# is a type that has an empty set of possible values.
#
choice(CHOICE_ELEMENT_TYPE type...) is

#  a<X> X
#    pre
#      choice.this ? X => true, *=> false;