Cicada ---> Online Help Docs ---> Cicada scripting ---> Classes and Inheritance

Inheritance

Cicada also supports a sort of inheritance. The inheritance operator is a colon ‘:’ separating the parent object from the code that specializes it. For example, to derive a class from myClass we could write:


    myDerivedClass :: myClass : {
       newString := "Hello, I am new to this class."
    }
   

myDerivedClass has all of the members of myClass, plus the new string member.

In this last example, we specialized a predefined parent object with inlined code within braces, using a single inheritance operator. But one doesn’t have to follow this pattern; we can combine class objects and inlined codes in any number and any combination.


    A :: { var1 :: int }
    B :: { } : { var2 :: string }
    C :: A : B
    D :: B : A
    E :: { var3 :: int, var4 :: string } : A : { var5 :: char }
    F :: C : { remove var1 }
   

So for example the type of C is effectively { var1 :: int } : { } : { var2 :: string }, whereas D is { } : { var2 :: string } : { var1 :: int }. The definition of F shows that it is possible for a derived object to have fewer members than its parent object.

Importantly, an object’s type is sensitive to the order of inheritance. C has a different type than D, so C :: D or C = @D will cause a type-mismatch error.

Cicada allows existing objects to be redefined as a different type only if the new type is derived from its original type. We can always specialize a member’s type by adding more inheritance operators at the end of the type specification. All of the following commands will work in order except the last one.


    C :: A : B              | we already did this, but fine
    C :: C                  | fine -- C equals A : B
    C :: C : B              | OK -- now C will be A : B : B
    C :: A : B : B : {}     | OK
    C :: A : B : B : {}     | error!
   

The last line failed only because any two inlined types are presumed different -- Cicada is not in the business of comparing what’s inside those braces to see if they match up.

Although types can be specialized, they can never be generalized. So typing F :: C will cause a type-mismatch error.

The same type-matching rules apply to aliases.


    D :: B : A             | was already defined this way
    G :: B : A : { }
    D = @G                  | legal
    (D =@ *) :: B : A       | legal
    G = @D                  | NOT legal!
   

Aliasing doesn’t change a member’s type, which explains why we could reassign D to a new variable of its original type.

It turns out that the inheritance operator can derive new types for any composite Cicada object: variables, sets, even functions. Inheritance applied to sets is best thought of as set concatenation.


    a :: { Alice, Bob }
    b :: { Charlie, David }
    c :: a : b
   

So c contains Alice, Bob, Charlie, David, in that order.

Inheritance of functions basically tacks new code at the end of the old (parent) function. Each sub-code keeps its own original search path (the example of Figure 3 shows a situation where these may be different). Function-inheritance makes most sense when the function does not return a value (i.e. it’s a subroutine), because any return statement will prevent the new code from running. The resulting function contains members from both parent functions.


    absval :: {
       sign :: int
       code
       
       sign = 1
       if args[1] < 0 then sign = -1
       args[1] = that*sign
    }
   
    sqrt :: {
       code
       return args^0.5
    }
   
    modulus_sqrt :: absval : sqrt
   

Here’s another way of using the inheritance operator to accomplish the same thing:


    sqrt :: {
       f :: { ; return args[1] }
       code
   
       return f(args[1])^0.5
    }
   
    modulus_sqrt :: sqrt : {
       remove f
       f :: { ; return abs(args[1]) }
    }
   

So the inheritance operator can conjoin different types of objects: functions, sets, classes, basically any composite object. To see how this works, think of any non-function as the constructor part of a function (for example, imagine putting a code marker at the very end). Inheritance in Cicada is really a concatenation of code, whether that be constructor code (the commands before the first code marker), the first coding block, or any subsequent code blocks. In Cicada, type is code. This explains why objects can be specialized but not generalized: the specialization code tells Cicada how to convent a parent into a child object, but not the reverse.


Prev: Classes    Next: Customizing the Cicada language


Last update: November 12, 2025