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 mutate
#
# 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 : effect is
# does this effect support abort?
public redef abortable => false
# 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 := fzE_unique_id
# panic operation to be used in case of a severe problem. This is redefined within the
# base lib to make sure fundamental uses of local mutability do not cause dependency
# on the panic effect.
#
module mpanic(msg String) => panic msg
# common type for mutable data
#
module: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 the same as the currently instated effect of type
# `mutate.this`
#
is_currently_instated =>
match mutate.this.type.get_if_instated
x mutate.this => my_id = x.id
nil => false
# check that this effect is instated and replace it.
#
module check_and_replace
=>
if !is_currently_instated
mpanic "*** invalid mutate for {mutate.this.type}"
mutate.this.env.replace
# is this element open, i.e., can it be mutated?
#
public open => my_id != u64 0
# stop any further mutations of this element
#
public close =>
set my_id := 0
# create a new mutable value with the given initial value and update the
# 'mutate' effect in the current environment
#
public new (
public T type,
# initial value, will be updated by 'put' or 'infix <-'.
mutable_value T
) : mutable_element,
auto_unwrap T mutate
is
# read the current value of this mutable value.
#
# If this is open, check that the mutate effect this was created with is still
# instated 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
# instated 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 calculating the new value from the old value
f T->T
)
=>
put (f get)
# creates a copy of the mutable field
#
public copy new T =>
new get
# unwrap this mutable value
#
public redef unwrap ! mutate => get
# returns `as_string` of the current value
#
public redef as_string => get.as_string
# install default instance of mutate
#
module type.install_default =>
mutate.default
# short-hand for accessing mut effect in current environment
#
public mut =>
mutate.install_default
mutate.env
# create a new mutable value of type T with initial value v
#
public mut(T type, v T) => mut.new v
last changed: 2025-01-23