Cicada ---> Online Help Docs ---> Cicada scripting ---> Variables

Aliases

C has pointers; Cicada has aliases. An alias is a member that shares its data with some other member: they lead to the same variable. In Cicada a member and its alias are exactly on he same terms: even the interpreter doesn’t know which was the original member.

Here is how aliases are defined:


    a := 2      | will default to an int
    b :=@ a     | alias #1
    c :=@ b     | alias #2
   

b’ is now an alias to ‘a’, and ‘c’ is now an alias to ‘b’ and therefore also to ‘a’. If we were to now print(a), print(b) or print(c), we would get back the number 2. If we were to set any of the three variables to a different value:


    c = 3
   

then printing any of a, b or c would then cause the new number 3 to be printed.

Any variable can become an alias for any other variable of the same type (or a derived/inherited type), by means of the equate-at operator ‘=@’.


    a :: b :: c :: int
    { a, b, c } = { 1, 2, 3 }
    a =@ b               | 'a' now points to the variable storing '2'
    b =@ c               | 'a' STILL points to the variable storing '2'
    c =@ b =@ a
   

The tricky bit is the fourth line: since member ‘a’ has been aliased to member ‘b’, does the command b =@ c now drag member a along with it? The answer is no: aliasing binds one member to another member’s variable, not to the other member itself. If we follow through all the acrobatics, we find that members a, b, and c all end up referring to same the variable storing the number 2, as shown in Figure 2. (The other two variables are now inaccessible and will eventually be cleared from memory.)




Figure 2: Aliasing of members (letters) to variables (boxes)

Cicada clearly makes an important distinction between members and variables. Until now we have been rather sloppy on this point, so we shall be more careful from now on. A member is a named object in Cicada: the name of a variable, or a field in a composite variable. The variable itself is the data that the member refers to. In Cicada these two objects are entirely separate, and there is no reason to require a one-to-one correspondence between them.

Just as the data-copying operator ‘=’ or ‘<-’ has a data-comparison counterpart ‘==’, so the member-reference-copying operator ‘=@’ is mirrored in a reference-comparison operator ‘==@’ which tests to see whether two members point to the same object. (If the left side spans a range of array elements then the right side must also span exactly those same elements in order for the test to return true). Finally, the are-references-not-equal operator ‘/=@’ is just the logical negation of ‘==@’.

If we so prefer, we can write whitespace just before the ‘@’ of any of the aliasing operators.


    if a == @b then c := @b
    if a /= @b then a = @b
   

The extra space makes clearer the analogy with the data-copying operators: both a = @b and a = b cause member ‘a’ to equal member ‘b’, though by different means. By the way an @ symbol by itself is meaningless; it is only the last character of these aliasing operators.


Jamming

Arrays can also be involved in aliasing. There is a potential complication, but on the surface it is straightforward. For example, we ordinary (non-array) members can alias single array elements.


    array_1 :: [5] double
    array_2 :: [10] double
    oneEl :: double
   
    oneEl = @array_1[4]
    oneEl = @array_2[top]
   

Likewise complete arrays can alias other arrays, or parts of larger arrays. (Cicada doesn’t let us re-alias just some indices of an array since that would fragment its memory.). So we can write


    array_1[*] = @array_2[<4, 8>]
   

as long as array_1 had 5 elements to begin with (aliasing can’t resize an array); however we cannot write


    array_1[<3, 5>] = @array_2[<4, 6>]
   

The potential complication is that arrays having multiple members pointing to them can become ‘jammed’, meaning that they cannot be resized. The reason is that resizing one of its members would also force a resize of the other member which may be in an unrelated part of code, and this is not allowed. Here is an example.


    array_1 :: [3][10] int
    array_2 := @array_1[2][<4, 7>]  | jams 4 indices of array_1
   
    array_1[*][^12]       | legal - indices 11-12 aren't aliased by array_2
    array_2[^12]          | no, this would cause problems
    remove array_1[*][5]  | not legal -- would remove 2nd column of array_2
    remove array_1[1]     | legal
   
    remove array_1
    array_2[+3]           | legal only because we removed the jamb
   

Explicit aliases always jam arrays. On the other hand, unnamed references to objects (such as elements of sets and function arguments) never jam arrays.


    al := @my_array[<4, 6>]   | jams elements 4-6
    my_array[<4, 6>]          | does not jam
   

Tokens are ‘unjammable’, both in the sense that they cannot jam, and that they will become ‘unjammed’---i.e. permanently deactivated---if their referent is resized through another member. An unjammed token becomes unusable until it is redefined, usually when the command defining the token is rerun.


Prev: This and that    Next: The void


Last update: May 8, 2024