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

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

# mutate -- an effect that permits creation and mutation of mutable values.
#
# This effect is typically used to work with mutable values. You can create
# a mutable value as follows
#
#   v := mutate.env.new i32 42
#
# and then modify it using
#
#   v <- 666
#
# To read it, call 'get' as in
#
#   say "v is {v.get}"
#
# Convenience feature 'mut' and type inference allow the creation to be
# written as
#
#   v := mut 42
#
# NYI: syntax sugar to read mutable field using
#
#   w := v + 1
#
# instead of
#
#   w := v.get + 1
#
# is not supported yet.
#
public mutate : simple_effect is

  # short-hand to access effect type
  #
  # NYI: This does not work yet
  #
  # M := mutate.this.type

  # an id used for runtime checks to verify that mutation made with the same effect
  # the mutable value was created with
  #
  id := fuzion.sys.misc.unique_id

  # 0 is used to indicate this is closed
  #
  # NYI: remove this check as soon as id is set by an intrinsic guaranteed not to be 0.
  #
  if id = u64 0
    panic "*** mutate.id should never be 0"

  # common type for mutable data
  private:public mutable_element is
    # id used to verify that mutation made with the same effect
    # the mutable value was created with
    my_id := id

    # check that this effect is installed and replace it.
    #
    private check_and_replace is
      if my_id != mutate.this.env.id
        panic "*** invalid mutate for {mutate.this.type}"
      mutate.this.env.replace

    # is this element open, i.e., can it be mutated?
    #
    public open => id != u64 0

    # stop any further mutations of this element
    #
    public close is
      set id := 0


  # create a new mutable value with the given initial value and update the
  # 'mutate' effect in the current environment
  #
  public new (
    T type,

    # initial value, will be updated by 'put' or 'infix <-'.
    private mutable_value T
    ) : mutable_element
  is


    # read the current value of this mutable value.
    #
    # If this is open, check that the mutate effect this was created with is still
    # installed in the current environment.
    #
    public get ! mutate.this =>
      if open
        check_and_replace
      mutable_value


    # read the mutable value that is now immutable after it was closed for mutation.
    #
    public val
    pre
      safety: !open
    =>
      mutable_value


    # update mutable field with new value
    #
    # Check that the mutate effect this was created with is still
    # installed in the current environment.
    #
    public put (
      # the new value to be stored with 'h'
      to T)
      ! mutate.this
    pre
      safety: open
    =>
      check_and_replace
      set mutable_value := to


    # infix operator for put, OCaml/F#-style syntax
    #
    public infix <- (to T) => put to


    # update mutable field using a function of the old value
    #
    public update (
      # function calculcating the new value from the old value
      f T->T
      )
    =>
      put (f get)


    # creates a copy of the mutable field
    #
    public copy new T is
      new T get


    # returns `as_string` of the current value
    #
    public redef as_string => get.as_string


  # create a mutable array.
  #
  public array (# element type
         redef T type,

         # length of the array to create
         public length i32,

         # initial value for elements
         init T
        ) : Sequence T, mutable_element
  is
    private ma := (marray T).type.new length init

    # a sequence of all valid indices to access this array. Useful e.g., for
    # `for`-loops:
    #
    #   for i in arr.indices do
    #     say arr[i]
    #
    public indices => ma.indices

    # is this sequence known to be finite?  For infinite sequences, features like
    # count diverge.
    #
    public redef finite => true


    # get element at given index i
    #
    public redef index [ ] (i i32) T
      pre
        safety: 0 ≤ i < length
    is
      check_and_replace
      ma[i]

    # set element at given index i to given value o
    #
    public set [ ] (i i32, o T) unit
      pre
        safety: 0 ≤ i < length
    is
      check_and_replace
      ma[i] := o


    # create immutable array from this
    #
    public redef as_array => ma.as_array


    # create a list from this marray
    #
    public redef as_list => ma.as_list


    # map the array to a new array applying function f to all elements
    #
    public map(B type, f T -> B) => ma.map B f


    # fold the elements of this array using the given monoid.
    #
    # e.g., to sum the elements of an array of i32, use a.fold i32.sum
    #
    public redef fold (m Monoid T) => ma.fold 0 m.e m


  # install default instance of mutate
  #
  module type.install_default =>
    mutate.default


# short-hand for accessing mut effect in current environment
#
public mut =>
  mutate.type.install_default
  mutate.env


# create a new mutable value of type T with initial value v
#
public mut(T type, v T) => mut.new T v