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

Other define and equate operators

The difference between a member’s type and the type of its target variable motivates two further define operators.

The variable-define operator ‘@::’ is identical to ordinary define (::), except that it only sets the target variable’s type, while leaving the member’s type unchanged. That means that if it is used to define a brand new member, that member’s type will be void. For example, here we use this operator to define and then redefine a member with different types of storage, and then alias it to another variable of a different type.


    theVar @:: int
    ...
    theVar = @nothing   | need to unlink before creating a new variable
    theVar @:: string
    ...
    theBool :: bool
    theVar = @theBool
   

Notice that the second @:: operator was forced to make a new variable because theVar had been unlinked (aliased to the void) on the previous line. Had we left out the unlinking command, Cicada would have tried to redefine the existing int variable as a string, causing a type-mismatch error.

The member-define operator ‘*::’ is the counterpart to variable-define: it only acts upon the member, without affecting any variable that member may target. Its symbol reflects the fact that, if one uses member-define to define a new member, it will indeed create a member of the desired type but it will not bother to create a variable for it: the member will point into the void. So the following code will cause an error:


    myNum *:: int
    myNum = 5     | will cause an error
   

which could have been avoided had we written myNum :: int or myNum @:: int between the two lines, in order to construct the integer variable behind the member. It has to be an integer variable in order to be compatible with member myNum’s type.

There are actually 256 operators in the define family, most of which cannot be scripted directly unless we modify the language. See Chapter 4.

Finally, there is another assignment operator called ‘forced-equate’, and given the symbol ‘=!’ or ‘<-!’. While equate copies data between variables whose data structures match or are compatible (e.g. { int, string } to { double, string }), forced equate copies between variables having the same memory storage size. (Having a string in the destination variable makes the storage requirement somewhat elastic.) A forced equate simply takes the data contained in its right-hand argument and stuffs those N bytes in the same order into the left-hand variable, with no restrictions on how the storage space is parceled out within the destination variable.

When forcing an equate from an inlined numeric constant, remember that Cicada interprets constants as either as signed long integers or floating-point doubles, according to the convention described in the earlier section on expressions. So on the author’s old machine where long integers are 4 bytes and doubles are 8 bytes, a =! -4 and a =! 2e5 will copy 4 bytes while a =! 4. and a =! 2e10 will each copy 8 bytes.

Here are some examples showing the difference between these two operators:


    var1 :: { int, bool }
    var2 :: { double, bool }
    var3 :: { int, string }
   
    var1 = var2   | OK
    var1 = var3   | type-mismatch error
   
    var1 =! var2  | unequal data size error
    var1 =! var3  | unequal data size error unless string has 1 character
    var3 =! var1  | OK, surprisingly!
   

The last line works because forced-equate resizes var3’s string as needed to soak up any extra bytes from var1.


Prev: The void    Next: Loops and if blocks


Last update: May 8, 2024