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

Composite variables

The second type of variable in Cicada is a composite variable, equivalent to a structure variable in C. Composite variables are collections of members defined inside of curly braces, just like a struct variable in C. Member definitions can go on their own lines, but make sure the opening brace is on the first line.


    StreetAddress :: {
       number :: int
       street :: string
    }
   

If we don’t care about the member names we can leave them out.


    StreetAddress :: { int, string }
   

StreetAddress is a proper variable with its own storage, but for convenience Cicada allows us to also treat it as a new data type.


    PetersPlace :: StreetAddress
   

In general any Cicada variable A can be used to define other variables B and C, which just copy A’s type definition (although not A’s data).

We access members of a composite variable the same way in Cicada as we do in C: using a period. For example (using the original definition with member names):


    PetersPlace.number = 357
    PetersPlace.street = "Bumbleberry Drive"
   

Composite variables may be nested inside one another, either using previously-defined types or by nesting curly braces. Here is an example showing both methods.


    FullAddress :: {
       first_line :: StreetAddress
       second_line :: {
           city :: state :: string
           zip :: int
       }
    }
   

In this case, we need to use a ‘.’ twice to access any of the primitive fields.


    FullAddress.first_line.number = 357
   

Notice that members of composite variables can also serve as data types.


    GeneralWhereabouts :: FullAddress.second_line
    GeneralWhereabouts.city = "Detroit"
   

One peculiarity of composite variables is that their internal structures can be rearranged after they have been defined. For example:


    PaulineAddress :: FullAddress
   
    remove PaulineAddress.first_line.street   | it's a PO box
    PaulineAddress.country :: string          | in another country
   

By the end PaulineAddress will have a three members including one named country, and the street member of first_line will be missing. One thing to be aware of is that if we ever use a modified variable like PaulineAddress to define another variable:


    PaulineOldAddress :: PaulineAddress
   

the new variable is always defined using the original definition. So PaulineOldAddress will not have a member named country and it will have street inside of first_line. This can lead to problems with the define-equate operator:


    > PaulinesDogAddress := PaulineAddress
   
    Error: type mismatch
   

The problem was that the define half of := constructed PaulinesDogAddress based on the original type definition of PaulineAddress, while the equate half of := copies data from the fields that are actually present between the two variables. Oops.

Assignment and equality-testing work with whole composite variables just like they do with primitive variables:


    Tom :: Bob :: StreetAddress
    ...
    Tom = Bob
    if Tom == Bob then (     | yes, they will be equal
       print("They're sharing a room.\n")
    )
   

We were allowed to assign and compare Tom and Bob because they have the same { number, string } structure.

Numeric operations and comparisons do not work with composite variables, even if all their members are numeric. Expressions like Tom+Bob and Tom > Bob will always cause an error.


Prev: Primitive variables and constants    Next: Array variables


Last update: May 8, 2024