There is one last variable ‘type’, which is no type at all. There are two ways of writing this:
var1 :: nothing
var2 :: *
nothing and * are synonyms for the void. If var1 is defined as void then we will get a void-member error if we try to access its data. In fact, one of the few things we can do with a void member is to test whether it is void or not, using the reference-comparison operator ==@.
if var1 == @nothing then &
print("out of order..\n")
One way to make use of a void member is to redefine it.
var1 :: nothing
var1 :: [1000] string
We could have redefined var1 as anything: a primitive or composite variable, function, etc. But now that it has a non-void type, var1 cannot be redefined again except to the same type or a derived type (see inheritance).
What is the use of having void-typed variables, if we can’t use them while void? The main reason is that members without no type are universal aliases (because all other data types are daughters of the void). Just make sure to alias using the =@ operator, not the :=@ operator as the latter will redefine its type.
any_var :: *
x :: int
y := "some string"
z :: { double, int }
any_var = @x
any_var = @y
any_var = @nothing
any_var = @z
The fact that the void is the universal parent type also explains why void members can be redefined to any other type. Cicada always permits an existing member’s type to be specialized---restricted to a subtype of its original type---but never changed back to a parent or sibling type. Similar rules apply to aliasing---aliases can be made to variables having inherited types, but not parent types---except that any member is allowed to become unlinked by aliasing to the void.
There are actually two uses of the word ‘void’ in this document that are important to keep logically separate. A void member is one that has no storage space. But a void-typed member is one with essentially no type restriction on what it can point to. A definition like a :: * does two things: it defines a member ‘a’ having no type, and it therefore neglects to give ‘a’ any storage space.
Cicada also distinguishes between member types and variable types. For example, after any_var was aliased to x, did any_var have a null type or was it an int? Well, that depends on whether you are asking about the member’s type (which was void), or the type of the variable it points to (an integer). Both members and variables have types, and in general they may be different. A member’s type specification determines which variables it is allowed to point to, and if the two types are different then the member type must be a parent of the variable type.
Last update: November 12, 2025