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
# 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 := fuzion.sys.misc.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.
#
mpanic(msg String) => panic msg
# 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 the same as the currently installed effect of type
# `mutate.this`
#
private is_currently_installed => my_id = mutate.this.env.id
# check that this effect is installed and replace it.
#
private check_and_replace
is
if !is_currently_installed
mpanic "*** 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 (
public 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 =>
new T get
# returns `as_string` of the current value
#
public redef as_string => get.as_string
# create a mutable array.
#
module:public array (
# element type
public T type,
# length of the array to create
public length i32,
# contents of the array
module data fuzion.sys.internal_array T,
_ unit
) : Mutable_Array T, mutable_element
pre
safety: (length ≥ 0) && (length ≤ data.length)
is
# 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 => 0..length-1
# 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
=>
data[i]
# set element at given index i to given value o
#
public set [ ] (i i32, o T) unit
pre
safety: 0 ≤ i < length
=>
check_and_replace
data[i] := o
# add an element at the end of this array
#
public add (o T) unit
=>
check_and_replace
d := if (data.length > length) data
else
new_data := fuzion.sys.internal_array_init T (max 8 data.length*2)
for i in indices do
new_data[i] := data[i]
new_data
d[length] := o
set data := d
set length := length+1
# create immutable array from this
#
public redef as_array =>
array T length (i -> data[i])
# create a list from this array
#
public redef as_list =>
# since array is mutable,
# we first copy the elements
# to an immutable array.
as_array.as_list
# initialize one-dimensional mutable array
#
public type.new
(LM type : mutate,
# length of the array to create
length i32,
# initial value for elements
init T
) Mutable_Array T
=>
data := fuzion.sys.internal_array_init T length
for x in data.indices do
data[x] := init
LM.env.array T length data unit
# initialize an empty mutable array of type T
#
public type.new (LM type : mutate) Mutable_Array T =>
LM.env.array T 0 (fuzion.sys.internal_array_init T 0) unit
# 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 T v
# an interface defining a mutable array
#
# NYI: Remove Sequence parent. Since Sequence is supposed to be immutable,
# we should maybe not pretend to be a Sequence.
#
public Mutable_Array(public T type) ref : Sequence T is
# add an element at the end of the sequence
public add(t T) unit => abstract
# set element at index i to o
public set [ ] (i i32, o T) unit => abstract
# the indices of the array
public indices interval i32 => abstract
# the length of the array
public length i32 => abstract
# is this Sequence known to be array backed? If so, this means that operations
# like index[] are fast.
#
public redef is_array_backed => true
# count the number of elements in this Sequence.
#
# Since we know the exact length, this is redefined to achive O(1) performance instead
# of O(n) for counting the elements.
#
public redef count => length
last changed: 2024-03-07