Overview
Sometimes it is important to expose a variable or a portion of a data structure to a different piece of code that needs to mutate it, but doesn’t need to know where the data lives. On the surface, doing so might seem difficult. Consider the following example:
Dict is int->>str->>str = (1->($a->"hello", $b->"world")).
Dict 1 $a -> "goodbye".
In this example, one element is being mutated inside a subdictionary of a dictionary. To perform this operation inside a well-written function, we would like to pass some kind of a “pointer” to the field "hello"
into the function, rather than tell the function where to find the field. You can do so using the MUFL’s references, as illustrated in this example:
fn MutateIt (theRef:&(str+)) {
#theRef->"goodbye". // will mutate the value to which reference 'theRef' is pointing
}
Dict is int->>str->>str = (1->($a->"hello", $b->"world")).
MutateIt &(Dict 1 $a). // will pass reference to 'Dict 1 $a' into function 'MutateIt'
Here’s another example of using references:
A = 1.
B = &A. // construct a reference to 'A'
#B -> 2. // Mutate 'A' via reference
Map = ("A"->"A_halo", "B"->"B_world" ).
Ref = &(Map "A").
#Ref->"A_hello".
// Map is now ("A"->"A_hello", "B"->"B_world").
Only globally-scoped variables can generate a reference. Variables declared locally inside functions can be mutated, but one cannot create a reference to them.
References work symbolically. They are not actual pointers, but rather indicate a path the evaluator must take to get to the given value. Some programming language call this concept a “weak” reference because the existance of the reference does not guarantee there is a value it references.
This is illustrated in the following example:
A is any->>any = (,).
B = &(A 1 2 3 4). // This reference cannot be used yet because dictionary A does not have the given element path.
A 1 -> (2->(3->(4->5))). // We have now created an element for which B is a valid reference
#B->5.
_print (A 1 2 3 4). // will print '5'