The Cyan Programming Language

This text introduces some of the Cyan features through examples.

Before reading this page, remember that the Cyan compiler is being built. It will take years before the language is fully implemented.

The language has many innovations. The main ones, in order of importance, are:

1. grammar methods 6. context functionss
2. an object-oriented exception handling system 7. user-defined literal objects
3. context objects 8. generic prototypes
4. statically-typed anonymous functions 9. multi-methods
5. codegs 10. linking past-future

Besided that, there are many ways of mixing dynamic and static typing (dynamic message sends, dynOnce, dynAlways). And Cyan makes it easy to build Domain Specific Languages.

The links below introduce Cyan through examples. Enjoy it.

Here it is:

package main

object Program
    public fun run {
        Out println: "Hello World"
    }
end

A prototype is a literal object with instance variables and methods. It is the equivalent of "class" in class-based languages such as Smalltalk, Java, C#, C++, Ruby, and Groovy. The difference is that a prototype can be readily used. You can send a message directly to it, pass it as parameter, and do whatever can be done with any other object. In the 'Hello World' program, there is a Program object:

 

package main

object Program
    public fun run {
        Out println: "Hello World"
    }
end

 

Then it is possible to send a message to Program as in

Program run;

Methods start with keyword fun followed by the name. Method 'run' is public which means it can be called by anyone. Symbol { starts the method and } ends it. After each statement there is a ';' which is optional before }. We intend to make the ";" always optional.

Packages are groups of prototypes, interfaces, and so on. Cyan packages are very similar to the same concept of Java (and many other languages). To declare that a source file belongs to a certain package, use keyword package followed by the package name (starting with a lower case letter by convention). Several source files compose a package. And each source file can have a single public prototype or interface and zero or more private prototypes and interfaces (declared with keyword private, see the example below). By default, a prototype is public as Program in this example.

package main

private object Empty
end

object Program
    public fun run {
        Out println: "Prototype Program of package main"
    }
end

After the package declaration, use keyword import followed by one or more package names separated by commas. All of the identifiers of the package are imported.

package other
import main

object Test
    public fun test {
            // I can use Program here since
            // it was defined in package main
        Program run
    }
end

Use var followed by the variable type and name. All variables are references to objects. That is, the declaration of a variable of type String(for example) does not allocate memory for the string.

   // declare n as having type Int
var Int n;
   // declare s and t as having type String
var String s, t;
s = "I am a string";
t = s;
   // now s and t reference the same object

Not yet. It will be as soon as possible. It is just a matter of adjusting the compiler that is being built to consider the ; optional.

Assume that s is a variable of type String which has a method size. Expression s size is the sending of message size to the object referred to by s. The message is separated to the receiver by one or more white spaces. This would be "s.size()" in Java and "s->size()" in C++.

var String s;
s = "Cyan";
var Int n;
n = s size;
		

Package cyan.lang is automatically imported by every Cyan source code. It defines a prototype In used for input and Out used for output in the standard devices. Methods readString, readInt etc of In read a String, Int etc from the standard input. Method println: of Out does the output.

package main
object Program
    public fun run {
           // s is a String variable
        var  String s;
        s = In readString;
           // write s
        Out println: s;
        var Int n = In readInt;
        Out println: (n*n)
    }
end
	

Variable n is declared as having type Int because the type of the literal 0 is Int. Variable s is declared with type String.

var n = 0;
var s = "I am a string";
	

An integral number can be written with any number of underscores for clarity. However, it is illegal to start a number with an underscore (it would be an identifier) and use two consecutive underscores.

   // underscores are ignored
var Float budget;
budget = 1_000_000.0;
var Int howLongSec;
howLongSec = 2_349_349;
	

Prototype Person declares a private instance variable name of type String. An instance variable is sometimes called "attribute", "field", or "data member" (C++).

object Person
       // no way of initializing name yet
    private String name
end
	

This code declares a printObj method without parameters or return value. It uses the instance variable name. The method is public. The method declaration should be preceded by keyword "fun".

object Person
       // no way of initializing name yet
    private String name
    public fun printObj {
            // + concatenates strings
        Out println: ("the name of person is " + name);
    }
end
	

self is a reference to the object that received the message (same as "self" of Smalltalk and this of C++, C#, and Java). Instance variables can be prefixed by "self.":

object Person
       // no way of initializing name yet
    private String name
    public fun printObj {
            // + concatenates strings
        Out println: ("the name of person is " + self.name);
    }
end
	

Methods are declared with keyword fun followed by an identifier (with an ":") and preceded by keyword "public" or "private". The return value type of a method should be put after -> as in method getName below. The return value of the method can be given either after ^ (but there are restrictions) or keyword return. Methods that take one or more parameters should necessarily be followed by ":" as "setName:". Methods that do not take parameters can be followed by : or not (usually not).

object Person
    private String name
       // getName returns name
    public fun getName -> String { ^name }
       // setName: takes a String parameter
    public fun setName: (String name) {
        self.name = name
    }

    public fun printObj {
            // + concatenates strings
        Out println: ("the name of person is " + self.name);
    }
end
	

The program execution starts in a method called run (without parameters or return value) or

    run: Array<String>

of a prototype specified at compile-time through the compiler or IDE option. Type Array<String> is an array of strings. The arguments to run are those passed to the program when it is called. In this text (all of it) we usually call Program the prototype in which the program execution starts. But the name can be anyone. The program that follows prints all arguments passed to it when it is called.

package main

object Program
    public fun run: (Array<String> args) {
        args foreach: } (: String elem :)
            Out println: elem
        }
    }
end
	

All objects have a method clone that returns a shallow copy of the object. This is usually the only way of creating new objects in other prototype-based languages. In the example below, the execution will start at method run of Program. This method will clone prototype Test; that is, a new object identical to Test will be created (the values of the instance variables will be the same) in statement "Test clone".

package main

private object Test
    private String name = "First test"
    public fun test {
       Out println: name
    }
end

object Program
    public fun run {
        var Test t;
           // t will refer to a Test object
        t = Test clone;
            // print "First test" since the clone
            // is equal to the original object
        t test;
    }
end
	

C++ and Java constructors are called init or init: in Cyan. When a prototype P declares a method init or init:, the compiler adds to P a new or new: method to P with the same parameters as the init or init: method. This new or new: method allocates memory for a P object and sends to it message init or init: with the new or new: arguments (if any).

If the prototype does not declare an init or init: method, the compiler will add a new method without parameters to the prototype. This method can only be called through the prototype.

object Person
    private String name
    public fun init: (String name) {
        self.name = name
    }
    public fun printObj {
            // + concatenates strings
        Out println: "the name of person is " + name;
    }
end

object Program
    public fun run {
        var Person p;
        p = Person new: "Gauss";
        p printObj
    }
end

In this example, the compiler adds to Person a method

    public fun new: (String name) {
        self.name = name
    }

because Person declares an "init: String" method.

A method may have two or more selectors. Each selector is composed by an identifier and a : (glued) and a list of parameters. Unlike Smalltalk, each selector may have more than one parameter.

object Circle
    public fun x: (Int x1) y: (Int y1) radius: (Int r) {
        self.x = x1;
        self.y = y1;
        self.radius = r
    }
    public fun draw {
       // draw a circle
       // elided
    }
    private Int x, y, radius
end
	

The first method has three selectors, x:, y:, and radius: and it can be called as

var Circle c;
c = Circle new;
c x: 100 y: 50 radius: 30;
c draw;

The name of the first method is x:y:radius. It is called a keyword method or method with multiple selectors.

An instance variable may be declared public in Cyan. The compiler will automatically create a getter and a setter to this variable, which can only be accessed through theses methods. A public instance variable name is declared in the example. The compiler will rename name to _name, declare it as private, and create two public methods: name -> String and name: (String newName).

object Person
    public String name
    public fun printObj {
            // + concatenates strings
        Out println: "the name of person is " + name;
    }
end
	

Then this prototype will be transformed into

object Person
    public name -> String { ^_name }
    public name: (String newName) { _name = newName }
    private String _name
    public fun printObj {
            // + concatenates strings
        Out println: "the name of person is " + name;
    }
end
	

Now we can set and get the name of the person:

Person name: "Gauss";
Out println: (Person name);
	

An instance variable can be initialized from an expression in its declaration. The expression is evaluated and assigned to the variable every time a new object from the prototype is created.

object Person
    public String name = "anonymous"
end
	

A shared variable is, as expected, shared among all objects of the same prototype. It is not cloned in a cloned operation.

object Time
    public Int day, month, year
    shared private Int currentYear = 2012
    public fun getCurrentYear -> Int { ^currentYear }
end
	

Method initOnce is called just once when the prototype is loaded into memory. It is usually used to initialize the shared variables of the prototype.

public object Lexer
    ...
    private fun initOnce {
        keywordsTable add: "public";
        keywordsTable add: "private";
        keywordsTable add: "object";
        ...
    }
    private shared Set keywordsTable
	

Literal strings accept the same escape characters as Java:

var s = "Tab: \t new line: \n";

Using @" the escape characters are not considered:

var directory = @"c:\tab\newline\foward";
	

There is a pre-defined generic prototype Array. Method foreach: iterates through the array elements.

var Array<Int> v;
v = Array<Int> new: 4;
v[0] = 1;
v[1] = 1;
v[2] = 2;
v[3] = 6;
var sum = 0;
v foreach: {
   (: Int item :)
   sum = sum + item
};
   // prints 10
Out println: sum

Method foreach: receives a function with a parameter of the array type (Int in this example). This function is called by foreach: passing each array element as a parameter.

Literal Arrays are delimited by {# and #}.

var daysMonth = {# 31, 28, 30, 31, 30, 31, 31, 30, 31, 30, 31 #};
var january = 0;
Out println: "January has " + daysMonth[january] + " days";
var vowels = {# 'a', 'e', 'i', 'o', 'u' #};
  // print the vowels
vowels print;
var Array<Char> e_to_o;
    // array slicing
e_to_o = vowels[1..3];
  // print e, i, o
e_to_o print;
...
	

Keyword const is used to declare a constant.

object Date
     public const daysWeek = 7
     public const daysMonth = {# 31, 28, 30, 31, 30, 31, 31, 30, 31, 30, 31 #}
     public Int day, month, year
end

Since the constants of Date are public one can write

Out println: Date.daysWeek;
	

Cyan supports the following basic types: Byte Short Int Long Float Double Char Boolean. Literals of all of these types are full objects. The range of them is exactly the same as the range of the corresponding Java type. Literals of Byte Short Int Long Float, and Double should end with B, S, I, L, F, D or Byte, Short, Int, Long, Float, Double. Int is the default for number literals without a dot. With a dot, the default is Float. There is no automatic conversion between the basic types.

var Char ch;
var aByte  = 7B;
var aShort = 29Short;
var aLong  = 1234567L;
var bLong  = 37Long;
var anInt  = 223Int;
anInt = 223;
var aFloat Float;
aFloat = 1.0;
var aDouble Double = 1.0D;
  // error: no automatic conversion
anInt = 1.0;
  // error: no automatic conversion
aFloat = 1;
aFloat = Float cast: 1;
	

The basic types can be compared with the operators <, <=, >, >=, !=, == which are regular methods.

var Int n;
n = 0;
var Char ch = 'c';
var Boolean bool = false;
bool = bool < true;
bool = n <= 0;
bool = ch >= 'e';
	
var age = In readInt;
if age <= 2 {
    Out println: "a baby!"
}
else {
    Out println: "not a baby anymore"
};
if age > 19 {
    Out println: "an adult"
};
   // else is optional
	

Decisions may be made using methods ifTrue:ifFalse:, ifFalse:ifTrue:, ifTrue:, or ifFalse: of prototype Boolean:

var age = In readInt;
( age <= 2 ) ifTrue: {
    Out println: "a baby!"
    }
ifFalse: {
    Out println: "not a baby anymore"
};
( age <= 19 ) ifFalse: {
    Out println: "an adult"
};
	
if age < 3 {
    s = "baby"
}
else if age <= 12 {
    s = "child"
}
else if age <= 19 {
    s = "teenager"
}
else {
    s = "adult"
};
	

Prototype Boolean has methods t:f: and f:t: that return an expression. It is a short form of the if statement.

oddOrEven = (n%2 == 0) t: "even" f: "odd";
   // or
oddOrEven = (n%2 != 0) f: "even" t: "odd";
	

Note that the expressions after t: and f: are always evaluated, which is very different from the operator ?: of languages C/C++/Java.

Use ++ and -- before a variable to increment or decrement it from 1. The type of the variable should be any of the integral types or Char.

var i = 0;
    // prints 0
Out println: i;
++i;
    // prints 1
Out println: i;
--i;
    // prints 0
Out println: i;

Note that neither ++ or -- are message sends. Since i is a local variable, ++i is replace by the compiler by

(i = i + 1)
	
var i = 0;
while ( i < 5 ) {
    Out println: i;
    ++i
};
	

Message whileTrue: is sent to a function that returns a boolean value. The function is evaluated till the receiver returns false.

var i = 0;
{^ i < 5 } whileTrue: {
    Out println: i;
    ++i
};
	

There is also the form whileFalse:

var i = 0;
{^ i >= 5 } whileFalse: {
    Out println: i;
    ++i
};
	
var i = 0;
   // the function is called forever.
   // only a return statement can stop it
{
  ++i;
  Out println: i
} loop;
	

Prototype Boolean support the logical operators &&, ||, and ! for "and", "or", and "not". Besides that, there is a version of && and || that accepts a function as parameter, used for short circuit evaluation.

var Int i = 0;
var v = {# 2, 4, 6 #};
if !(i >= v size) && i >= 0 {
    v[i] print
};
i = In readInt;
if i < v size && v[i] == 0 {
    // will never execute this
};

In the above code, the test "v[i] == 0" is made even if i < v size returns false because && is a message send (the arguments passed as parameters to a message send are always evaluated). To prevent that, the last expression should be put in a function:

...
i = In readInt;
if i < v size && {^ v[i] == 0 } {
    // will never execute this
};

The top-level prototype, Any, defines a method assert: that takes a boolean expression as parameter. If this expression is evaluated to false the program is terminated. Since this method is inherited by anyone, we can use it anywhere.

var i = 0;
assert: (i < 10);
assert: (Math.pi > 3.0 && Math.pi < 4.0);
	

Cyan supports anonymous functions which are called simply "functions". A function is a literal object composed by statements between { and }:

var function = { Out println: "I am a function" };
   // call the function:
function eval;

It will be printed "I am a function". This function is a regular object with an eval method that does not take parameters or return a value. It is as if it were declared as

object Function01
    public fun eval {
        Out println: "I am a function"
    }
end

A function is an anonymous literal function. As a function can take parameters and return a value.

The return value of a function should appear after ^. The declaration of the return value can be absent.

var function = { ^0 };
   // the function returns 0
assert: (function eval == 0);

The function return value type, Int, may not be declared as in this example. Or it can:

var function = { (: -> Int :) ^0 };
   // the function returns 0
assert: (function eval == 0);

This function object has a method

    public fun eval -> Int

The parameters of a function should be put between (: ... :) as in the example:

var function = { (: Int n -> Int :) ^n*n };
   // the function returns n*n
assert: (function eval: (2 == 4));

The eval: method of this function takes an Int as parameter and returns an Int:

    public fun eval: (Int p) -> Int
	

Local variables may be used inside a function:

var Int n = 0;
var function = { ++n };
assert: (n == 0);
function eval;
assert: (n == 1);
	

Instance variable total is used inside a function passed as parameter to selector ifTrue:.

object Account
    public fun withdraw: (Float amount) {
        (amount < total) ifTrue: {
            total = total - amount
        }
    }
        // total of money in the account
    private Float total
        // account identification, usually a number
    private String id
    ...
end
	

Every function that does not take parameters or return a value implements interface Function<Nil> (or UFunction<Nil>) that declares a single eval method.

var Int n = 0;
var Function<Nil> b;
b = { ++n };
b eval;
	

A function that takes an Int parameter and returns a String inherits from prototype FunctionR<Int><String> or UFunctionR<Int><String>. Of course, both of these prototypes declare a method eval: Int -> String. An example of function declaration and assignment is:

var FunctionR<Int><String> b;
b = { (: Int n -> String :)  ^Int cast: n };
assert: ((b eval: 5) == "5");

A function that takes parameters T1, T2, ... Tn and returns a value of type R inherits from prototype

    Function<T1, T2, ..., Tn><R>

if it accesses local variables or has a return statement. Otherwise it inherits from

    UFunction<T1, T2, ..., Tn><R>

That is, Function<...><R> and UFunction<...><R> can be used as types of functions.

A copy variable is a variable used inside a function preceded by %. A copy variable is local to the function but its initial value comes from the variable of the same name of the scope of the function. Changes in a copy variable are not reflected in the external variable of the same name.

var n = 0;
var b = {
    %n = %n + 1;
    Out println: %n;
    assert: (%n == 1)
};
assert: (n == 0);
   // prints 1
b eval;
assert: (n == 0);
	

Statement return can be given inside a function. When this statement is executed at runtime, the method in which the function is defined returns.

object Test
    public fun test {
        Out println: "before callFunction";
        callFunction: { return };
        Out println: "after callFunction";
    }
    public fun callFunction: (Function<Nil> b) {
        Out println: "before calling the function";
        b eval;
        Out println: "this is never printed";
    }
    public fun run {
        test;
        Out println: "the end"
    }
end

Assuming method run is called, this program prints

before callFunction
before calling the function
the end

When b eval is executed inside callFunction, statement return of the function { return } causes a jump to

    Out println: "the end"

in method run. This happens because function { return } is defined inside method test. Therefore the return is a return from test. It does not matter whether the method is called. It does matter whether the method is defined.

IntSet is a prototype that keeps a set of integers and defines a method foreach: that applies the function that is parameter to each integer of the set.

object IntSet
    public fun add: (Int elem) { ... }
    public fun foreach: Function<Int, Nil> b {
        var i = 0;
        while i < intArray size  {
            b eval: intArray[i];
            ++i
        }
    }
    ...
    private Array<Int> intArray
    private Int size
end

This method can be called as

var mySet = IntSet new;
mySet add: 0;
mySet add: 1;
mySet add: 2;
    // print all elements
mySet foreach: { (: Int n :)  Out println: n };
var sum = 0;
    // sum all elements
mySet foreach: { (: Int n :) sum = sum + n };
...
	

Functions that do not access local variables (or access them using %) and that do not have a return statement can be stored in instance variables.

object Button
        // when the button is pressed,
        // execute the action
    public fun pressed {
        action eval
    }
    public fun whenPressed: (Function<Nil> action) }
        self.action = action
    }
    public  Image image
    private Function<Nil> action
end

This prototype could be used as

var yesButton = Button new;
var noButton  = Button new;
yesButton whenPressed: { Radio on  };
noButton  whenPressed: { Radio off };
...
	

Functions in Cyan are statically typed. That means there will never be an error caused by an access to a variable that no longer exists:

object Test
    public fun run {
        var a1 = 1;
        var Function<Nil> b1;
        if a1 == 1 {
            var a2 = 2;
            b1 = { Out println: a2 };
        };
        b1 eval
    }
end

Here statement "b1 eval" tries to access variable a2 that is no longer in the stack. A runtime error would occur if Cyan allowed this code. But it does not. An assignment "b = function" is only allowed if the variables accessed inside the function will live as much as the variable b. Therefore statement

      b1 = { Out println: a2 };

is illegal in Cyan for b1 will live longer than a2.

It is also illegal to assign a function that accesses local variables to an instance variable:

object StatList
    public fun inc {
        var n = 0;
        stat = { ++n };
    }
    public fun run {
        inc;
        stat eval
    }
    private Function<Nil> stat
end

When run is called, there would be a runtime error in

    stat eval

because there would be an attempt to use local variable n that no longer exists.

Functions that have a return statement cannot live past the method in which they were defined:

object Test
    public fun run {
        prepareError;
        makeError;
    }
    public fun prepareError {
        function = { return  };
        return;
    }
    public fun makeError {
        function eval;
    }
    private Function<Nil> function
end

In makeError, the function stored in the instance variable receives message eval and statement return is executed. This is a return from method prepareError that is no longer in the stack. There would be a runtime error. But it does not because the compiler does not allow the statement

        function = { return  };
	

The Cyan manual has a complete list of restrictions of functions in Section Functions. There is a kind of functions that will never cause any runtime error and can be freely used: the functions that only access local variables using % and that do not have any return statements. Functions of this kind are called "unrestricted functions". The other ones are the "restricted functions".

The type of an unrestricted function that takes parameters of types T1, T2, ... Tn and returns a value of type R is

    UFunction<T1, T2, ..., Tn, R>

The type of an restricted block that takes parameters of types T1, T2, ... Tn and returns a value of type R is

    Function<T1, T2, ..., Tn, R>

An unrestricted function that does not take parameters and returns a value of type R has type

    UFunction<R>

A restricted block that does not take parameters and returns a value of type R has type

    Block<R>

Method acc: returns a function that sums its parameter with the original parameter to acc:. Since parameters are read-only in Cyan, it is as if they were preceded by % in the function.

    public fun acc: (Int n) -> UFunction<Int, Int>{
        return { (: Int m :) ^n + m }
    }
	

Unrestricted functions can be stored in hashtables, arrays etc.

var Hashtable<String, UFunction<Nil>> carCommands;
carCommands key: "left"  value: { Car left };
carCommands key: "right" value: { Car right };
carCommands key: "off"   value: { Car off };
carCommands key: "on"    value: { Car on };
carCommands key: "move"  value: { Car move: 10 };

carCommands["on"] eval;
carCommands["move"] eval;
carCommands["left"] eval;
carCommands["move"] eval;
carCommands["right"] eval;
carCommands["off"] eval;

In this code,

    carCommands["off"]

is the same as

    (carCommands key: "off")
which returns the value stored in the hashtable associated to "off".

Methods are unrestricted functions that close over the instance variables of the prototype. They are unrestricted functions and are accessed using ".{signature}.". The signature of a method is composed by its selectors, parameter types, and return value type. We will show some examples using prototype Box.

object Box
     public fun get -> Int = { return value }
     public fun set: (Int other) { value = other }
     private Int value = 0
end

Method get of Box is Box getMethod: "get -> Int" as in

var getMethod = Box getMethod: "get -> Int";
. The type of getMethod is UFunction<Int>. See the example below.
var UFunction<Int> getMethod;
var UFunction<Int, Nil> setMethod;

getMethod = Box getMethod: "get -> Int";
setMethod = Box getMethod: "set: Int";
var box = Box new;
box set: 10;

setMethod eval: 5;
    // prints 5
Out println: (getMethod eval);
    // prints 0
Out println: (box get);

This syntax can be used to set a method of a prototype such as

var Int local;
var Box b = Box new;
b setMethod: "get -> Int", { ^0 };
b setMethod: "set: Int", { (: Int n :) Out println: n };
assert: (b get == 0);
    // method getDay of Date returns an Int
b setMethod: "get -> Int", (Date getMethod: "getDay -> Int");

A method of a prototype may be set too. The existing objects of that prototype are affected --- they will use the new method.

 

var Box before = Box new;
before set: 0;
Box setMethod: "get -> Int", { ^1 };
var Box after = Box new;
assert: (before get == 1);
assert: (after  get == 1);
	

There is a method that plays the rôle of the switch statement of language C. It is used as shown below.

var n = In readInt;
if n >= 0 && n <= 6 {        // according to the value of n,
       // one of the functions is called
    n switch:
      case: 0 do: {
          Out println: "zero"
      }
      case: 1 do: {
          Out println: "one"
      }
      case: 2, 3, 5 do: {
          Out println: "prime"
      }
      else: {
          Out println: "four or six"
      }
};
	

The else: part is optional. This switch: method is defined in prototype Any, the top-level prototype.

The function is called three times in this example. Message repeat: { ... } is send to object 3.

    // this code prints numbers 0 1 2
var i = 0;
3 repeat: {
    Out println: i;
    ++i
};
    // this code prints numbers 0 1 2
3 repeat: { (: Int i :)
    Out println: i
};
	
    // prints 0 1 2
i = 0;
1 to: 3 do: {
    Out println: i;
    ++i
};
    // prints 1 2 3
1 to: 3 do: { (: Int j :)
    Out println: j
};
	

The bit operators for "and", "or", "xor", and "not" are &, |, ~|, and ~.

var man = 1;
var brazilian = 2;
var programmer = 4;
var you = 0;
  // turn you into a man
you = you | man;
if you & man == 1 {
    Out println: "I am a man"
};
you = you | brazilian | programmer;
...
	

Method in: is implemented in the basic types Byte, Int, Long, and Char. It accepts as parameter any object that implements interface Iterable such as arrays.

interface Iterable<T>
    fun foreach: Function
end
...

var Int n = In readInt;
if n in: {# 0, 1, 2 #} {
    Out println: "Zero, one, or two"
};
var vowels = {# 'a', 'e', 'i', 'o', 'u' #};
var Char ch = In readChar;
if ch in: vowels {
    Out println: "typed a vowel"
};
	

Every prototype defines a method cast: Any that returns an object of the same type as the receiver. This method can only be used when the receiver is the prototype.

var Int n = 0;
n = Int cast: 3.5;
var Char ch;
   // convert to the ASCII correspondent
   // to the number, '0'
ch = Char cast: 48
   // compile-time error
   // should use "Int" as the receiver, not "n"
n = n cast: 3.5
car Student student;
student = Student cast: (homeWork getAuthor);

If the object cannot be converted, exception CastException is thrown.

There are intervals of the integral types and Char. There is a method in: of these types that accept an interval as parameter.

var Char ch;
ch = In readChar;
( ch in: 'a'..'z' ) ifTrue: {
    Out println: "#ch is a lower case letter"
};
var age = In readInt;
if age in: 0..2 { Out println: "baby" }
else if age in: 3..12 {
    Out println: "child"
}
else if age in: 13..19 {
    Out println: "teenager"
}
else {
    Out println: "adult"
}
	

Intervals also support a foreach: method and methods for repeat a function of code.

var Interval I;
I = 3..5;
    // this code prints numbers 0 1 2
0..2 foreach: { (: Int i :)
    Out println: i
};
    // this code prints numbers 3 4 5
I repeat: { (: Int i :)
    Out println: i
};
    // prints the alphabet
'a'..'z' foreach: {     (: Char ch :)
    Out println: ch
};

Unary message sends are associated from left to right. Then

    var name = club members first name;

is the same as:

    var name = ((club members) first) name;
	

Cyan supports inheritance of prototypes in the same way class-based languages such as C++, Java, Groovy, C#, etc support inheritance of classes. Keyword extends is used for inheritance as in the example below. Considers that Person and Worker are in different source files. Both are public. The source files, with the package declaration, are not shown.

object Person
    public fun init: (String name) { self.name = name }
    private String name
    ...
end

    // Worker inherits from Person
object Worker extends Person
    public fun init: (String name, String job) {             // this line is demanded
        super init: name;
        self.job = job;
    }
    private String job
    ...
end

Cyan supports only single inheritance but any number of mixins can be inherited and any number of interfaces can be implemented. Every prototype that does not inherit explicitly from another prototype inherits from Any (the equivalent of Object of Smalltalk and Java).

We call the inherited prototype "super-prototype" (or "sub-object") and the inheriting one "sub-prototype" (or "sub-object"). Then Person is the super-prototype of Worker.

In the sub-prototype, methods of the super-prototype can be called using keyword super as usual.

A method declared in a super-prototype may be redefined in a sub-prototype. However, its declaration in the sub-prototype should use keyword override before keyword fun.

object Animal
    public fun eat: (Food food) {         Out println: "animal eating food"
    }
end

object Mammal extends Animal
    public override fun eat: (Food food) {         Out println: "mammal eating food"
    }
end
	

Protected instance variables can be accessed by methods of sub-prototypes. To keep the representation of the variables hidden from the sub-prototypes, each protected instance variable is converted into two methods: one for getting and the other for setting the variable.

A protected instance variable name of type String is declared by putting keyword protected before the declaration. The compiler then creates protected methods name -> String and name: (String newName) (see public instance variables).

object Person
    public fun init: (String name) { self.name = name }
    protected String name
    ...
end

    // Worker inherits from Person
object Worker extends Person
    public fun init: (String name, String job) {             // this line is demanded
        super name: name;
        self.job = job;
    }
    public fun printObj {           // call super-prototype method "name"
       Out println: name + " " + job
    }
    private String job
    ...
end
	

Any is the super-prototype of every prototype (directly or indirectly). When a prototype does not explicitly define a super-prototype, it inherits from Any, which defines a lot of important methods (see the language manual for details). A variable of type Any can receive in an assignment an expression of any type.

var Any any;
any = 0;
any = String;
    // Any defines a print method
any print;
any = Person clone;
any = AnyInterface;
Out println: (any asString);
	

Use methods eq: and neq: for comparing references. The first one returns true if the receiver and the parameter refer to the same object. The second method returns false in this case. These methods have special behavior when the receiver is a basic value (Int, Char, etc). In this case, they compare the values of the objects, not the references. Methods eq: and neq: cannot be overriden in sub-prototypes.

object Program
    public fun run {         var other = Program new;
        var another = Program new:
        var yetAnother = other;

        assert: (other neq: another);
        assert: (other eq: yetAnother);
        assert: (self neq: other);

        var Int n = 0;
        var Int p = 0;
        assert: (n eq: p);
        assert: (n eq: 0);

    }
end

It is very important that, for basic types, eq: and neq: compare the values. That makes it impossible to distinguish between two variables that have the same value (as n and p in this example). Or a variable and a value (n and 0). As a consequence, in most situations the compiler can use value semantics for basic type variables. That is, the variable keeps the value, not a reference to an object that has the value. This is a simple and powerful trick.

Keyword interface can be used in place of object. It declares a Java-like interface. A prototype may "implement" an interface using the syntax "implements InterfaceName" after the prototype name or inheritance.

interface Saveable
    fun save
end

object Person implements Saveable
    public String name
    public Int age
    public fun save {        // save to a file
    }
end

Prototype Person should define a method save. Otherwise there is a compile-time error. Only method interfaces (without the body) can be declared in an interface.

An interface may extend another interface (and only another interface). A regular prototype can only extends another regular prototype and mixin objects.

interface Printable
    fun printObj
end

interface ColorPrintable extends Printable
    fun setColor: (Int newColor)
    fun colorPrint
end

Interfaces that do not inherit explicitly from any other interface inherit from AnyInterface (which cannot be inherited by regular prototypes).

Interfaces are regular Cyan prototypes with restrictions. They can be types of variables. If a variable v has type I, an interface, the compiler checks whether the messages sent to v are only those whose signatures are declared in I or Any.

interface Printable
    fun printObj
end
...
var Printable v;
v = Person clone;
    // ok
v printObj;
    // Ok, inherited from Any
if v eq: nil {
    Out println: "v is nil"
}
    // compile-time error: method getName
    // is not in the interface
if v getName == "noname" {
    Out println: "v is no body"
}
	

Use method isInterface inherited from Any.

var inter = Printable;
var person = Person clone;
assert: (inter isInterface);
assert: !(person isInterface);
	

A subtype is a sub-prototype, a sub-interface, or a prototype that implements an interface. That is, if B inherits from A, then B is subtype of A. Interface J that inherits from interface I is subtype of it. If a prototype A implements interface I then A is subtype of I. The subtype relation is transitive: if C is subtype of B and B subtype of A, then C is subtype of A.

Method isA: of Any returns true if the receiver is subtype of the real argument.

var Person person;
...
if person isA: Worker {
    Out println: (person name) + " is a worker";
    var Worker worker = Worker cast: person;
    ...
}
	
The parameter to isA: should be a prototype.

Method prototype of Any returns the prototype of the receiver. Method prototypeName returns the name of the prototype of the receiver.

var Any any;
var worker = Worker clone;
any = worker prototype;
    // prints "Worker"
Out println: (any prototypeName);
   // prints "Int"
Out println: (17 prototypeName);
	

Use method parent inherited from Any.

var Any any = Worker clone;
Out println: (any parent prototypeName);

Assuming Worker inherits from Person, "Person" will be printed. any parent prototypeName is the same as (any parent) prototypeName

Method printHierarchy: prints all the hierarchy of the parameter

    public fun printHierarchy: (Any obj) {         var any = obj;
        while ( any != Any ) {             Out println: (any prototypeName);
            any = any parent
        };
        Out println: "Any";
    }
	

All objects of basic types are objects.

var Any any;
var Int zero = 0;
any = zero;
any = 'A';
any = 3.141592;
any = true;

Method eq: of all basic types return a comparison between the two objects. Then it is not possible to distinguish two 0 objects in any way. This allows the compiler to optimize the code.

var Any any = 0;
var zero = 0;
assert: (zero eq: 0    &&
         any  eq: 0    &&
         any  eq: zero &&
         0    eq: 0 );

The compiler will only allocate dynamically objects of basic type in special conditions (when they really need to be treated as regular objects).

Method asString inherited from Any returns a string which represents the object. In the basic types, this method returns what is expected from them:

var thousand = 1000;
    // prints "1000"
Out println: (thousand asString);
    // prints "1000";
Out println: ((Int cast: "999") + 1);

In regular objects, asString returns a string with a list of instance variables and values of them --- the details are yet to be defined. Anyway, this method can be user defined.

Literal object nil represents an object whose type is subtype of every other type. It is the same concept of nil of Smalltalk. Unlike the null value of C++/Java, nil of Cyan is really an object.

Methods isNil and notNil defined at Any are used to discover whether a variable refer to nil or not.

var Any any = nil;
if any isNil {
    Out println: "any refers to nil"
};
var person = Person;
if person notNil {
    Out println: "person does not refer to nil"
};
	

Constructors in Cyan are methods named init or init: (when there are parameters). These methods are not part of the prototype interface (they cannot be called using an object of the prototype or even the prototype itself as a receiver). They can only be called in message sends to nil or super.

object Circle
    public fun init: (Int x, Int y, Int radius) {         self.x = x;
        self.y = y;
        self.radius = radius;
    }
    public fun draw {         // draw a circle
    }
    private Int x, y, radius
end

The compiler creates a method new for every method init declared in the prototype (idem for init:). These methods allocate memory for a new object, call the corresponding init or init: method, and return the created object. The new and new: methods can only be called by sending a message to the prototype (they cannot be called by sending a message to a variable).

var Circle c;
c = Circle new: 100, 50, 30;
   // compile-time error:
Circle init: 100, 50, 30;
   // compile-time error:
c new: 100, 50, 30;

If a prototype does not declare any init, init:, new, or new: methods, the compiler supplies an empty init method:

object Circle
    public fun draw {         // draw a circle
    }
    public Int x, y, radius
end
...
   // the compiler creates a new method
var c = Circle new;
	

A prototype may declare a new or new: method that has the prototype itself as the return type. But it cannot have the same parameter types as a method init or init: of the same prototype. There is a method called primitiveNew added by the compiler that creates an object of the prototype without initializing it. This method cannot be overridden in a prototype.

object Circle
    public fun new: (Int x, Int y, Int radius) -> Circle {         var Circle newCircle = primitiveNew;
        newCircle x: x;
        newCircle y: y;
        newCircle radius: radius;
        return newCircle;
    }
    public fun draw {         // draw a circle
    }
    public Int x, y, radius
end
...


var Circle c;
c = Circle new: 100, 50, 30;
	

Singleton objects are object that have only one instance. They are easily declared in Cyan:

object Earth
    public fun clone -> Earth { ^Earth }
    public fun new -> Earth   { ^Earth }
    public fun mass -> Float { ^earthMass }
    private Float earthMass = 6e+24;
    ...
end

In this example, only clone and new can create Earth objects (method primitiveNew is private). And both return the prototype.

A compile-time metaobject is an object that can change the behavior of a program, add information to it, or it can just inspect the source code, using the collected information in the source code itself. Metaobjects may appear in several places in a Cyan program such as before a prototype or interface declaration, a method declaration, a statement, etc. As an example, metaobject checkStyle (not a pre-defined metaobject) could be attached to prototype Person:

@checkStyle object Person
    public fun print {          Out println: "name: ", name, " (", age, ")"
    }
    public String name
    public Int age
end

checkStyle is a metaobject written in Java. The compiler loads a Java class CheckStyle from the disk and creates an object from it (the Java class starts with an upper case letter). Then it calls some methods of this object passing as parameter some information on the object Person. For example, it could call method change of the CheckStyle Java object passing as parameter the whole abstract syntax tree (AST) of Person. Then method change of CheckStyle could change the AST or issue errors or warnings based on it. The intended meaning of checkStyle is to check whether the identifiers of the prototype follow Cyan conventions: method names and variables should start with an lower case letter and prototype and interfaces names should start with an upper case letter. In this metaobject, the AST is not changed at all.

The interactions of metaobjects with the Cyan compiler should be defined by a Meta-Object Protocol (MOP). The MOP would define how and which parts of the compiler are available to the metaobjects, which can be written by common users. The MOP has not yet being designed. It will be in a few years.

A metaobject called "meta" can appear in the Cyan code in several ways. Two of them are:

    @meta
    @meta<< ... >>

After the metaobject name there may appear a sequence of symbols, which is << in this example (it could be many other symbol sequences). The argument to the metaobject call ends with a sequence that mirrors the start sequence. So << is ended by >> and (<+ would be ended by +>). Almost any sequence is valid and different metaobject calls may use the same symbol sequence. The text in between is passed as argument to a call to a specific method of this metaobject (say, parse). Which method is called is defined by the MOP. Note that it is an abuse of language to say "a call to a metaobject"

A metaobject may have parameters, which are put between ( and ) as in

    @meta(parameters)<< ... >>

There is a special kind of compile-time metaobject called Codeg (code + egg) that makes the integration between the compiler and the IDE used with Cyan. Each codeg works like a plug-in to the IDE but with the added power of being a metaobject of the language. There are many technical details of the workings of a codeg. Few of them will be given here.

Codegs are similar to some features of the Codea code editor for iPad. They were designed around 1998 for the language Green with the name micro-CASES (although not incorporated officially into the language).

Codegs have been fully implemented using the IDE Eclipse by adding a plug-in to it. Therefore currently codegs work only in Eclipse. After installing the Codeg plug-in and defining a project as being a "Cyan project", source files ending with ".cyan" will receive special treatment. Let us shown an example using codeg "color" (for didactic reasons, the codeg described here may differ from the real implementation). When the user type

     @@color(red)
the Eclipse editor loads a Java class to memory that treats the codeg "color". This text "@@color(red)" will be shown in a color different from the rest of the code (the color will be blue regardless of the codeg). By putting the mouse pointer above "@@color(red)", a standard menu will appear which allows the editing of this codeg 'call'. This menu is standard just by convention. The codeg designer is free to choose another one if she so wishes.

By clicking in an "edit" button in the menu, another window will appear with a disk of colors. A color may now be chosen with the mouse. After that, the user should click in the "Ok" button. All codeg windows will disappear and the source code editing may continue. Now when the mouse pointer is over the text "@@color(red)" the standard menu will appear with an edit button and a bar showing the chosen color (it is expected that "red" was chosen).

This is what happened at editing time. When the compiler finds the codeg call "@@color(red)" it will load the codeg class (written in Java), create an object from it, initialize this object with data collected at editing time (collected using the menu), and calls method getCode of this object. This method takes a parameter of class CodeGenerationContext that gives information on the compilation itself. In future versions of the compiler, the AST of the current source code will be available from the CodeGenerationContext object. Currently this class only provides two methods: getLanguage and getCodegsList. The first method returns the target language of the codeg, which may be Java or Cyan. In due time, there will be only the options AST and Cyan. Method getCodegsList returns a list of codegs of the same source code. This allows communications among the codegs of the same file.

Method getCode returns an object of class CodeGeneration. This class has three methods that return the generated code:

    String getLocalCode()
    String[] getImports()
    String getGlobalCode()
The string returned by getLocalCode replaces the codeg call, "@@color(red)". It should be compiled by the compiler and may contain errors although it is expected that it does not. This code may need packages that were not imported by the source file in which the codeg call is. The packages used in the code returned by getLocalCode should be returned by method getImports. Finally, getGlobalCode returns code that should be added just after the import section of the source code in which this code is. So, suppose we have a code like
package main

object Program
    public fun run {
        Out println: @@color(red)
    }
end
Consider that method getCode of codeg color (which is a Java class called ColorCodeg) returns an object of CodeGeneration whose methods return the following:
    String getLocalCode()   returns "RGBColor new: 255, 0, 0"
    String[] getImports()   returns "RGB"
    String getGlobalCode()  returns "/* global code */"
Then the compiler will add these strings to the source code in such a way that the program above will become
package main
import RGB

/* global code */

object Program
    public fun run {         Out println: (RGBColor new: 255, 0, 0)
    }
end
It is expected that prototype RGBColor is in package RGB.

Use the @init metaobject. It will add two methods to the prototype.

object Circle
    @init(x, y, radius)
    ...
    public fun draw {         // draw a circle
    }
    private Int x, y, radius
end

The metaobject will add the following methods to Circle:

    public fun x: (Int newX) y: (Int newY) radius: (Int newRadius) {         self.x = newX;
        self.y = newY;
        self.radius = newRadius;
    }
    public fun new: (Int newX, Int newY, Int newRadius) {         var Circle p = primitiveNew;
           // initialize the variables
    }
	

The call

    Proto new: a1, a1, ... an
can be abbreviated to
    Proto(a1, a1, ... an)

Then we can write:

var circle = Circle new: 100, 50, 30;
   // the call to new above is the same as
circle = Circle(100, 50, 30);
var p = Person("Gauss", 30);

That can be very convenient when creating complex hierarchies of objects such as trees or Abstract Syntax Trees (for a compiler):

object Tree
end

object BinTree extends Tree
    @init(left, value, right)
    public Tree left, right
    public Int value
end

object No extends Tree
    @init(value)
    public Int value
end
...

var tree = BinTree( No(-1), 0, BinTree(No(1), 2, No(3)) );
	

An abstract object does not have any new methods even if it declares init methods. Abstract methods do not have bodies and can only be declared in abstract objects. A sub-prototype of an abstract object may be declared abstract or not. However, if it does not define the inherited abstract methods, it must be declared as abstract too.

public abstract object Shape
    public abstract fun draw
end
	

Final prototypes are declared with keyword final and they cannot be inherited. A final method cannot be overriden in sub-prototypes. Public instance variables can be declared as final. That means the methods for getting and setting the variable are final.

public object Person
    public final fun name -> String { ^ _name }
    public final fun name: (String newName) { _name = newName }
    ...
end

...

public final object String
   ...
end

All of the basic types and String are final prototypes.

Cyan symbols start with # and come in two flavors. The first one starts by a # followed, without spaces, by letters, digits, underscores, and :. It should start with a letter or digit. The second flavor is a string preceded by a #, as #"a symbol". These are valid symbols in Cyan (one per line):

#name
#name:
#"this is a valid symbol; ok? ! &)"
#at:put:
#1
#711
#"1 + 2"
#"Hello world"

There may be methods with the same name but with different number of parameters and parameter types (method overloading). For example, one can declare

object MyBlackBoard
    public fun draw: (Square f)    { ... }
    public fun draw: (Triangle f)  { ... }
    public fun draw: (Circle f)    { ... }
    public fun draw: (Shape f)     { ... }
    private String name
end

There are four draw methods that are considered different by the compiler. In a message send

     MyBlackBoard draw: fig
the runtime system searchs for a draw method in prototype MyBlackBoard in the textual order in which the methods were declared. It first checks whether fig references a prototype which is a sub-prototype from Square (that is, whether the prototype extends Square, assuming Square is a prototype and not an interface). If it is not, the search continues in the second method,
    draw: Triangle f
and so on. If an adequate method is not found in this prototype, the search would continue in the super-prototype.

A method in a sub-prototype may have the same name as a method in the super-prototype, making them compose a multi-method. Keyword override should precede the redefinition of the method in the sub-prototype. The name of a method is composed solely by its selector names. In the example that follows, method eat: is overridden in sub-prototype Cow. A Cow or Animal is assigned to variable animal depending on the user input. Idem for objects Food and Grass with variable food.

object Animal
    public fun eat: (Food food) {         Out println: "eating food"
    }
end

object Cow extends Animal
    public override fun eat: (Grass food) {         Out println: "eating grass"
    }
end
...

var Animal animal;
animal = (In readInt > 0) t: Animal f: Cow;
Food food;
food = (In readInt > 0) t: Food f: Grass;
animal eat: food;

At runtime, animal may refer to Animal or Cow and food may refer to either Food or Grass. The search for an adequate method in message send

animal eat: food

start at the prototype of the object and continues at the super-prototype. The first method that fits is used. The possible combinations of receiver and parameter are given below.

Receiver parameter method called
Animal Food eat: Food
Animal Cow eat: Food
Cow Food eat: Food
Cow Grass eat: Grass

Note that multi-methods only exist when the method names are equal.

A sequence of symbols can be a method name:

    public fun **+ (Int other) -> Int { ... }

You cannot combine symbols and letters (or numbers) and some combinations are not valid (such as [( ). All methods that start with ! are considered unary. All the other should be binary methods. Methods that are operators may return or not a value.

It is possible to define the special operator []. This operator is special because it is associated to two different methods. One is called when the operator is used in the left-hand side of an assignment (as the target of the assignment). The other is called when the operator is in an expression.

object Table
     public fun [] at: (Int index) -> String {          return anArray[index]
     }
     public fun [] at: (Int index)  put: (String value) {          anArray[index] = value
     }
     private Array<String> anArray
end
...

var t = Table new;
t[0] = "One";
t[1] = "Two";
    // prints "One Two"
Out println: t[0], " ", t[1];
	

Cyan supports mixin prototypes, a concept similar to mixin classes of languages Ruby, Groovy, and Scala. A mixin prototype is defined with keyword mixin followed by a type (prototype or interface):

mixin(Window) object Border
    public fun draw {  /* draw the window */
        drawBorder;
        super.draw
    }
    public fun drawBorder {        // draw a border of color "color"
       ...
    }

    public fun setBorderColor: Int color { self.color = color }
    private Int color
    ...
end

Mixin Border can be inherited by Window and its sub-prototypes. Methods of Window can be called inside mixin Border using super.

object Window mixin Border
    public fun draw { /* method body */ }
    ...
end

Unlike regular inheritance, the methods of Border have precedence over the methods of Window. The compiler creates the hierarchy:

Any
    Window'  (with the body of Window)
        Window (with the body of Border)

So a message send

    Window draw;

will call method draw of Border. This method, using super, calls method draw of Window.

Currently a mixin object cannot be the type of a variable, parameter, or return value. Maybe this restriction will be lifted in the future. An object can inherit from a single super-prototype but it can be mixed with any number of mixin prototypes through the keyword {\tt mixin}. Mixin inheritance does not have the problems associated to multiple inheritance. There will never be a collision of methods cause by multiple mixin inheritance because the mixin objects inherited are put in a linear hierarchy.

Use a mixin prototype:

mixin object Math
    public const pi = 3.1415926535897;
    public fun sin: (Float x) -> Float { ... }
    public fun cos: (Float x) -> Float { ... }
    public fun tan: (Float x) -> Float { ... }
    ...
end

This mixin can be inherited by any prototype since it does not specify any object after keyword mixin:

object Program mixin Math
    public fun run {         ...
        var area = pi*radius*radius;
        var side = b*(cos: angle);
    }
end
	

A mixin can be attached to an object at runtime. The mixin methods take precedence over the object methods and these can be called inside the mixin methods using keyword super. Method attachMixin inherited from Any (the super prototype of anyone) is used to attach a mixin prototype to an object.

mixin(Any) object PrintToPrinter
    public override fun print {         super print;
            // print to a printer
        Printer print: (self asString)
    }
end

This mixin can be attached to any object, including prototype Person:

object Person
    public String name
    public String age
    public override fun asString -> String {         ^"name: #name age: #age"
    }
end

The attachment of the mixin to Person is made by calling method attachMixin:

...
var p = Person new;
p name: "Carol";
p age: 1;
    // prints in the standart output
p print;
    // attach mixin to object p
p attachMixin: PrintToPrinter;
    // prints both in the standart output and in the printer
p print;
Person name: "fulano";
Person age:  127;
    // print only in the standard output
Person print;
	

By calling method attachMixin, the runtime system replaces method print of Person by method print of PrintToPrinter. Only the receiver of message attachMixin is affected.

A dynamic message send is made by putting symbol ? before each selector of the message:

var Person p;
...
p ?name: "Peter"  ?age: 31;

The compiler will not check whether Person has a method with selectors name and age. That will be delayed till runtime. If the result of a dynamic message send is used somewhere else, the compiler will consider that there is no type error:

    // no compile-time error here
if box ?get {         // no compile-time error here either
    aSet add: (hash ?key: "John");
}
	

The compiler does not know the return type of get of box (or even if it returns a value). But it does not signal any errors.

Literal value noObject represents the sole value in Cyan that is not an object. Conceptually any method that returns Void returns noObject. This "no object" is necessary because of dynamic message sends:

n = box ?get;

If the method get called at runtime has Void as return value type, the value returned will be noObject. This non-object brings uniformity to the language: every method returns something, even those declared with Void as return value type.

Metaobject @dynOnce used before the declaration of a prototype makes it temporarily dynamically typed. The prototype may declare its variables, parameters, and methods without supplying types.

@dynOnce object Person
    public name
    public age
    public fun addAge: n {            // unnecessary but didactic code
        var sum;
        sum = age + n;
        age = sum
    }
    public fun print {         Out println: name + " (#{age} years old)"
    }
end

Suppose that in the first run of the program, the following code is executed.

var Person p;
p name: "Turing";
p age: 100;
p print;

Then at the end of program execution, the compiler adds some of the missing types in the declaration of Person:

@dynOnce object Person
    public String name
    public Int age
    public fun addAge: n {            // unnecessary but didactic code
        var sum;
        sum = age + n;
        age = sum
    }
    public fun print {         Out println: name + " (#{age} years old)"
    }
end

However, addAge: was not used in this run of the program and its parameter n does not have a type yet. In the next run, suppose statement

    Person addAge: 1

is executed. Then all the missing types of Person have been established. Again the compiler changes the source code of Person to

object Person
    public String name
    public Int age
    public fun addAge: (Int n) {            // unnecessary but didactic code
        var Int sum;
        sum = age + n;
        age = sum
    }
    public fun print {         Out println: name + " (#{age} years old)"
    }
end

Since all variables and return value types are known, the call to metaobject @dynOnce is removed from the source code.

There are some questions related to the mixture of static and dynamic typing in Cyan that were not solved. Consult the language manual for details.

Metaobject @dynAlways makes a prototype dynamically typed.

@dynAlways object Person
    public name
    public age
    ...
end

No type information should be given in this prototype, including the type of instance variables, parameters, local variables, and return value of methods.

The syntax of Cyan was designed in such a way that the missing types do not cause any ambiguities.

Cyan supports the ` operator which link the runtime value of a String variable to the compile-time meaning of this value. \begin{cyan} var selector String; selector = (In readInt > 0) t: "prototypeName" : "asString"; // a runtime test is inserted to check if the result // is really a String var result String = 0 `selector; Out println: result; \end{cyan} Here 0 `selector is the sending of the message given by the runtime value of selector to object 0. If selector is "prototypeName", the result will be "Int". If selector is "asString", the result will be "0".

When the compiler finds #{expr} or #id inside a string it generates code to convert the expression and identifier to a string and concatenate it to the original one:

var colors = {# "blue", "red", "green" #};
var i = 0;
   // print  "0 is blue"
Out println: "#i is #{colors[i]}";
   // print  "1 is red"
Out println: "#{i+1} is #{colors[i+1]}";
var s = "#{colors[i+2]}";
assert: (s == "green");

The compiler will replace "v is #{expr}" by ("v is " + ((expr) asString))

The generic prototypes of Cyan are declared using < and >. The type parameters should be preceded by :.

object Box<T>
    public T value
end
...
var intBox = Box<Int> new;
intBox value: 0;
assert: (intBox value == 0);

For each parameter the compiler creates a different prototype by copying and pasting the text of the prototype. So Box and Box are completely different prototypes.

When the compiler finds an instantiation of the generic prototype Box such as Box<Int>, it replaces T by Int in the text of Box and compiles the resulting prototype. Then compile-time errors may occur.

A type P may be given after the type parameter to restrict it to be a subtype of P:

    // here P is Person
object Box<T Person>
    public T value
end

Now Box can only have parameters that are subtypes of Person or Person itself.

...
    // compile-time error
var intBox  = Box<Int> new;

However, even when a subtype of the parameter is supplied as a real argument, there may be a compile-time error:

object Box<T Person>
    public fun init {         value: (T new: "anonymous");
    }
    public T value
end
...
var Box<worker> workerBox;

When the compiler tries to create a Box prototype, it discovers that Worker does not have a new: method that takes a string as parameter (even though Worker is a sub-prototype of Person).

There may be a prototype A that takes a variable number of parameters. However, there should be different declarations for the prototype when it takes 1, 2, ... n parameters.

A public prototype A with n parameters should be declared in a source file called "A(n).cyan". Prototypes with different parameters are considered different. Then if there is a non-generic prototype Box and you want to make it generic you can just create a "Box(1).cyan" source file with the content

object Box<T>
    public T value
end

All of the previous code that used just Box will continue to work with the old prototype.

Besides that, one can make specializations of a generic prototype:

object Box<Int>
    public Int value
    public fun whoIam {         Out println: "I am a Int Box"
    }
end

object Box<Person>
    public Person value
    public fun identity -> String {         return value name
    }
end


object Box<T>
    public T value
end

When the compiler finds a generic prototype instantiation Box<T>, it looks in file "Box(1).cyan" for an adequate match for T from top to bottom. For example, if T is Int, the first Box prototype is used. Note that this prototype have a method whoIam that the other two Box prototypes do not have. Idem for prototype Box<Person> and method identity.

A parameter of a generic prototype may be used where the compiler expect a method name, variable name, parameter name, or any kind of identifier in Cyan.

object Box<F, T>
       // F is a parameter and an identifier!
    public fun F: (T value) {         self.value = value
    }
    public fun F -> T {         return value
    }
    private T value
end

Now we can use Box as

var Box<amount, Float> myMoney;
myMoney amount: 534.4;
Out println: "I have #{myMoney amount} dollars";

Parameter amount to Box was used as an identifier inside this prototype.

A literal tuple is declared as [. ... .] with pairs field:value as in:

var t = [. name: "Lívia", age: 4, hairColor: "Blond" .];
Out println: "name: #{t name} age: #{t age}  hair color: #{t hairColor}";
t age: 5;
t hairColor: "Black";
...

The type of t is NTuple<name, String, age, Int, hairColor, String>.

An unnamed literal tuple is a list of values between [. ... .].

var t = [. "Lívia", 4, "Blond" .];
Out println: "name: #{t f1} age: #{t f2}  hair color: #{t f3}";

The fields of the tuple have names f1, f2, and so on. The type of t is NTuple<String, Int, String>.

Prototype DTuple is a dynamic tuple. Fields are added by sending messages "id: value" to the dynamic tuple. Once a field is added, it can be retrieved using method id.

var t = DTuple new;
   // adds a field "name" to the tuple
t ?name: "Carolina";
   // prints "Carolina"
Out println: (t ?name);
   // if uncommented the line below would produce a runtime error
//Out println: (t age);
   // adds a field "age" to the tuple
t ?age: 1;
   // prints 1
Out println: (t ?age);
	

Generic prototype Union is an unnamed union. An union keeps a single value whose type is given as parameter to the generic prototype Union. So an union Union<Int, String> can keep a single value of type Int or String. The Int value is stored and retrieved using f1: and f1. The second one, using f2: and f2.

var u = Union<Int, String> new;
u f1: 0;
assert: (u f1 == 0);
u f2: "zero";
assert: (u f2 == "zero");
    // runtime error in the next line
var n = u f1;

In the last line there is a runtime error since the value stored is a string and the code tries to retrieve an Int.

Unions may have meaningful field names:

var NUnion<wattsHour, Float, calorie, Float, joule, Float> u;
u wattsHour: 120;
Out println: (w wattsHour);
   // runtime error if the line below is uncommented
//Out println: (w joule);
w joule: 777;
Out println: (w joule);
	

Cyan offers several features that help to implement internal Domain Specific Languages (DSL's):

Besides that, functions are also very helpful in designing an internal DSL. Grammar methods make it easy to implement DSL's. An internal DSL can be implemented in Cyan using grammar methods in a fraction of the time it would take in other languages. The reasons for this efficiency are:

  • the lexical analysis of the DSL is implemented using grammar methods is the same as that of Cyan;
  • the syntactical analysis of the DSL is given by a regular expression, the signature of the grammar method, and that is easy to create;
  • the program of the DSL is a grammar message send. The Abstract Syntax Tree (AST) of such a program is automatically built by the compiler. The tree is composed by tuples, unions, arrays, and prototypes that appear in the definition of the grammar method. The single method parameter refer to the top-level object of the tree;
  • code generation for the DSL is made by interpreting the AST referenced by the single grammar method parameter. Code generation using AST´s is usually nicely organized with code for different structures or commands being generated by clearly separated parts of the compiler;
  • it is relatively easy to replace the type of the single parameter of a grammar method by a very meaningful type of the AST. So, instead of using
        Array<Tuple<Int, Int>>
    
    one could use
        Graph
    
    in which Graph is a prototype with appropriate methods.

Cyan allows multiple assignments if the right-hand side have a type tuple:

var Livia = [. "Lívia", 4 .];
var String name;
var Int age;

   // multiple assignment
name, age = Livia;
name, age = [. name:"Carolina", age:1 .];

The same applies to return value of methods:

object Person
    ...
    public fun getInfo -> Tuple<String, Int> {         return [. name, age .]
    }
    private String name
    private Int age
end
...
var Myself = Person new;
name, age = Myself getInfo;
	

Context objects are a generalization of both functions and inner or nested prototypes (which are not supported by Cyan). Besides that, they implement a kind of safe language C-like pointers. We will introduce context objects with an example. A function used as parameter to method foreach: of an array will be transformed into a context object.

The elements of an array can be summed up using a function:

var v = {# 0, 1, 2, 3 #};
   // sum the vector elements
var s = 0;
v foreach: { (: Int x :) s += x };

This function cannot be reused: it is a literal object. However, this function can be transformed into a context object that can be reused:

object Sum(Int &sum) extends Function<Int, Nil>
   public fun eval: (Int x) {
       sum += x
   }
end

This context object takes a sum parameter which keeps the sum of the elements. The real argument should be a local variable. It can be used as

var v = {# 0, 1, 2, 3 #};
var s = 0;
   // binds sum of Sum to local variable s
Sum bind: s;
v foreach: Sum;
assert: (s == 6);

Method bind: of Sum binds the context object parameter to the local variable s. After that, any changes in one is reflected in the other. It is as if parameter sum were a C-like pointer to local variable s.

This same code can be implemented using the short form of object creation (using parentheses):

var v = {# 0, 1, 2, 3 #};
var s = 0;
v foreach: Sum(s);
assert: (s == 6);

Here Sum(s) creates a new object from Sum passing the address of s as parameter. Only context object can declare a type that is the "address" of another type.

A parameter of a context object that can be associated to an instance variable should be declared using * as in:

object Sum(Int *sum) implements Function<Int, Nil>
   public fun eval: (Int x) {
       sum += x
   }
end

object Test
    public fun totalSum: Array<Int> array {
        array foreach: Sum(total)
    }
    public fun getTotal -> Int { ^total }
    private Int total
end

The context object Sum created by expression Sum(total) associates the context object parameter sum to total.

A parameter of a context object whose type is preceded by % is a copy parameter, which obeys the same semantics as the copy variables of functions.

object GrowBox(Int value)
    public fun add: (Int x) {
        value = value + x
    }
    public fun getValue -> Int {
        return value
    }
end

object Test
    public fun run {
        var Int sum = 0;
        var gb = GrowBox(sum);
        gb add: 10;
        assert: (sum == 0);
        assert: (gb getValue == 10)
    }
end

A copy parameter is associated to the value of the real argument. Changes in the parameter do not affect the real argument as in regular parameter passing. Any expression may be real argument. In the above code, 0 is the real argument. Local variable sum is not affected by the sum made in method add:.

In the following example, instance variable _color of prototype Car is shared between the car and the car doors. Changes in the color using methods of the doors are reflected in the car color. And vice-versa.

object CarDoor(public Int *color)
    ...
end

object Car
    public fun init {         leftDoor  = CarDoor(_color);
        rightDoor = CarDoor(_color);
    }
    public fun color: (Int newColor) { _color = newColor }
    public fun color -> Int { ^ _color }
    private Int _color
    public CarDoor leftDoor, rightDoor
end

...
Car color: 255;
   // prints "color = 255"
Out println: "color = {(Car leftDoor) color}";

(Car rightDoor) color: 0;
   // prints "color = 0"
Out println: "color = {Car color}";
	

Some languages such as C++ support passing of parameters by reference. In this case, changes in the parameter are reflected in the real argument, which should be a variable (it cannot be an expression). Cyan does not support directly this construct. However, it can be implemented using the context object Ref:

object Ref<T>(T &v)
    public fun value -> T { ^v }
    public fun value: (T newValue) { v = newValue }
end

Now if you want to pass a parameter by reference, use Ref:

private object CalcArea
       // it is as if parameter to selector area: were by reference
    public fun squareSide: (Float side) area: (Ref<Float> refSqrArea) {
           // by calling method value: we are changing the parameter
           // of the context object
        refSqrArea value: side*side
    }
end

public object Program
    public fun run {         var side = In readFloat;
        var Float sqrArea;

           /* encapsulate the reference parameter inside a
              context object. That is, use "Ref<Float>(sqrArea)"
              instead of just "sqrArea".
              Local variable "sqrArea" is changed inside
              method squareSide:area: of prototype CalcArea when message
              value: is sent to refSqrArea
           */
        CalcArea squareSide: side area: Ref<Float>(sqrArea);

        Out println: "Square side = #side";
        Out println: "area = #sqrArea"
    }
end

Of course, the "passing by reference" syntax in Cyan is not straightforward. However, it has two advantages:

  • it does not need a special syntax;
  • and, most importantly, it is type-safe. Context objects use the same rules as the static functions of Cyan. That means, for example, that an instance variable of prototype Calc cannot refer to a parameter of type Ref<Float>. That guarantees there will never be a reference to local variable of run of Program after this method is removed from the stack.

There will never be an error in Cyan equivalent to the following error in a C program, in which pointer mistake refers to a local variable that has been removed from the stack.

#include <stdio.h>

const float pi = 3.141592;

float *mistake;
void calc(float radius, float *area) {
    mistake = area;
    *area = pi*radius*radius;
}
void run() {
    float area;
    calc(1, &area);
}
float useStack() { float ten = 10; return area; }
int main() {
    run();
    useStack();
        // mistake refers to a variable that has been
        // removed from the stack
        // 10 is printed in some compilers
    printf("%f\n", *mistake);
    return 0;
}

A context function is a function whose messages to "self" are delegated to an object that can be set at runtime. A context function is a regular function whose first parameter is self. For example, the assignment

var printBox = { (: Box self :) Out println: get };

assigns to printBox a context function. Inside the function the type of self is Box:

object Box
     public fun get -> Int  { return value }
     public fun set: (Int other) { value = other }
     private Int value = 0
end

Therefore inside the function there can be a message send "get" to self. This function could have been declared as

var printBox = { (: Box self :) Out println: (self get) };

If printBox receives message eval there is a runtime error because the "self" in the function has not been bound yet. This can be made by sending message bindToFunction: to printBox, which returns an object of type UFunction<Nil> (since the context function does not take parameters, return a value, or uses local instance variables).

var aBox = Box new;
aBox set: 5;
var printBox = { (: Box self :) Out println: (self get) };
var UFunction<Nil> b = printBox bindToFunction: aBox;
   // prints 5
b eval;
Box set: 10
b = printBox bindToFunction: Box;
   // print 10
b eval;

Method bindToFunction: returns a real function that can receive message eval to call the function body.

Context functions are used to add methods to objects at runtime and to build domain specific languages.

Prototype Any, the super-prototype of everyone, defines a grammar method addMethod: ... that adds a method to an object at runtime. This method uses selector addMethod: (without parameters), one or more selectors selector: (with a Cyan symbol or string as parameter), an optional selector returnType: (with Any as parameter), and a selector body: with a context function as parameter.

The example that follows adds a method "print" to object referenced by myBox. The method body just prints the value retrieved from the object using "get".

var myBox = Box new;
myBox set: 10;
myBox addMethod:
    selector: #print
    body: { (: Box self :) Out println: "value = #{get}" };
myBox ?print;

The last statement is a dynamic message send. It will print

value = 10

It was necessary to use "myBox ?print" instead of "myBox print" because print is not declared in Box.

One can add a method to a prototype:

var otherBox = Box new;
otherBox set: 5;
Box addMethod:
    selector: #print
    body: { (: Box self :) Out println: get };

    // will print "5"
otherBox ?print;

Method print will be added to all instances of Box that have been created and that will created afterwards. However, if an instance of Box has added another print method, it is not affected.

Another method that takes a parameter and returns a value can be added to Box:

Box addMethod:
    selector: #returnSum
    param: Int
    returnValue: Int
    body: { (: Box self, Int p -> Int|  ^get + p };

Method "addMethod: ..." of Any has an attached metaobject checkAddMethod. This metaobject checks whether the number of selectors (one), the parameter type, and the return value type matches the context function. It does in this case. After the execution of this last example, method returnSum can be called using any instance of Box.

var myBox = Box new;
myBox set: 5;
assert: (myBox ?returnSum: 3) == 8;

Suppose we want to add a method with the following body to several different prototypes:

        var Int n = self get;
        Out println: (n + 1)

Each prototype should declare a get method that returns an Int. You can use a context function for that:

Box addMethod:
    selector: #addAndPrint
    body: { (: Box self :)
            var Int n = self get;
            Out println: (n + 1)
        };
ValueBox addMethod:
    selector: #printOneMore
    body: { (: ValueBox self :)
            var Int n = self get;
            Out println: (n + 1)
        };

Assuming that both Box and ValueBox define a method

   public fun get -> Int

there would not be any compile-time error in the above code. However, the context functions had to be duplicated. After all, they are literal objects and as such they cannot be reused. Fortunately selector body: of method addMethod: ... accepts an object of prototype ContextFunction. All we have to do is to create an appropriate sub-prototype of it.

The body of the context function above should be returned by method bindToFunction: of an object that inherits from ContextFunction<Box, Nil>.

object PrintBox
           extends ContextFunction<IGet, Nil>

    public fun bindToFunction: (IGet newSelf) -> UFunction<Nil> {
    return  {
                var Int n = newSelf get;
                Out println: (n + 1)
            }
    }
end

Interface IGet just defines a get method:

interface IGet
    fun get -> Int
end

Prototypes Box and ValueBox should implement this interface. Now it is easy to add a method whose body is the function returned by bindToFunction to these prototypes:

Box addMethod:
    selector: #addAndPrint
    body: PrintBox;
ValueBox addMethod:
    selector: #printOneMore
    body: PrintBox;

After the statements above are executed, one can call the added methods through a dynamic call:

var myBox = Box new;
myBox set: 0;
   // prints 1
myBox ?addAndPrint;
ValueBox set: 23;
   // prints 24
ValueBox ?printOneMore;

Object composition can be easily made if parentheses are used to create the objects and context objects are used to declare the prototypes.

object Tree
end

  // this is a context object with public
  // instance variables
object BinTree(public Tree left,
               public Int value,
               public Tree right) extends Tree
end

object No(public Int value) extends Tree
end
...

   // No(-1) is the creation of an object of No
var tree = BinTree( No(-1), 0, BinTree(No(1), 2, No(3)) );
Out println: ((tree left) value);

A method in Cyan may have one or more selectors, each one of them may take zero or more parameters. However, regular methods have a fixed number of selectors and parameters for each selector. So a method

    public fun at: (Int i) put: (String s) { ... }

is always called by a message send with one "at:" selector (with one Int parameter) followed by one "put:" selector with one String parameter. A grammar method may be called as a result of message sends with variable number of selectors and parameters. That is, several message sends with different "shapes" may call the same grammar method. But not every shape is allowed. The legal ones are those defined as a regular expression in the grammar method.

A grammar method has the form

    fun (regexpr) T v { ... }

in which regexpr is given as a regular expression that uses selectors, parameter types, and regular expression operators. There is only one parameter put after the regular expression. It is "v" in this example and has type "T".

The regular operators supported are:

R* zero or more repetitions of R
R+ one or more repetitions of R
R? zero or one R
R | S R or S

As an example of a grammar method, we present the grammar method of prototype IntSet that is called by messages containing one or more add: selectors:

object IntSet
    public fun (add: Int)+ Array<Int> v {         v foreach: {             (: Int elem :)
            addElem: elem
        }
    }
        // inserts one element at a time
    public fun addElem: (Int elem) {         ...
    }
    ...
end

Method add: can be used in several ways:

IntSet add: 0 add: 1 add: 2;
IntSet add: 5;

As another example, prototype Any defines a method

    public fun ( switch:
                 (case: (Any)+ do: Function<Nil>)+
                 (else: Function<Nil>)?
                ) Tuple<Any, Array<Tuple<Array<Any>, Function<Nil>>>, Union<Function<Nil>>> t {         // method body
    }

The + in (Any)+ means one or more repetitions of Any, the ? means that

    (else: Function<Nil>)?

is optional. So the following message sends are legal:

var n = In readInt;
var String s = "";
n switch:
    case: 0, 2, 4 do: { s = "even" }
    case: 1, 3, 5 do: { s = "odd"  };
n switch:
    case: 0 do: { s = "zero" }
    case: 1, 3 do: { s = "odd" }
    case: 2 do: { s = "prime" }
    else: { s = "other" };

The compiler groups all parameters passed in a grammar message send into one single object that is assigned to the single parameter of the grammar method. This object is created using tuples and arrays and it reflects the structure of the message send (according to the definition of the grammar method). For example, in the first message send of the last example the compiler creates the following object:

[. Any, // this "Any" is a dummy parameter to switch:
   {#
    [. {# 0, 2, 4 #}, { s = "even" } .],
    [. {# 1, 3, 5 #}, { s = "odd"  } .]
    #},
      // this Union is for the missing optional else:
    (Union<Function<Nil>> new)
.]

This object is then passed as parameter to the grammar method. Since there is no else: part, a Union<Function<Nil>> new object without any fields is used to compose this object.

Methods with variable number of parameters in Cyan are declared by putting the selectors and parameters between ( and ) (they are grammar methods). Then use (T)* to mean that zero or more parameters are accepted. Or (T)* to mean one or more parameters. Do not give the parameter names. After the most external parenthesis, declare an array that will keep the values passed as parameters.

object IntSet
    public fun (add: (Int)*) Array<Int> v {         v foreach: {             (: Int elem :)
            addElem: elem
        }
    }
        // inserts one element at a time
    public fun addElem: (Int elem) {         ...
    }
    ...
end

Method add: can be used in several ways:

IntSet add: 0, 1, 2, 3, 4;
IntSet add: 5;
    // it makes no sense but allowed
IntSet add:;

It is not necessary to give the type of the sole parameter of a grammar method:

object IntSet
    public fun (add: (Int)*) v { ... }
    ...
end

The compiler will deduce the type for v according to some rules given in the Cyan manual. In the same way, when the type is given it should obey these same rules.

Grammar methods can have selectors with alternative parameters declared using "|". For example, method eat: accepts either Meat or Vegetable:

object Animal
    public fun (eat: (Meat | Vegetable))  Union<Meat, Vegetable> t {        // eat the food
        if t contains: #f1 {             // meat
            var meat = t f1;
            Oven heat: meat;
            self eatMeat: meat
        }
        else {             var vegetable = t f2;
            vegetable addMayonnaise;
            self eatVegetable: vegetable
        }
    }
    ...
end

The sole parameter of this method, t, is given after the method signature. Its type represents a union of types Meat and Vegetable. See how Prototype NUnion is handled here.

A Domain Specific Language is a language specific to a domain. It has features that makes it easy to map the problem domain into the language statements and declarations. As examples of DSL we have SQL, HTML, shell scripts, and a language to control a remote controlled car. A DSL is the opposite of a general-purpose language such as C or LISP. Cyan supports several constructs that make it easy to build domain specific languages. The main of them is grammar methods, which is used in the example that follows.

Suppose we have a remote controlled car that accepts commands to turn to left, turn to right, move, and turn on and off. These commands can be given using a Domain Specific Language:

on
move 100
left
move 50
right
right
move 200
off

In Cyan, this DSL can be implemented using a grammar method:

object Car
   public fun on    { ... }
   public fun off   { ... }
   public fun left  { ... }
   public fun right { ... }
   public fun move: (Int dist) { ... }
   public (do:
           (on: | off: | left: | right: |
            move: Int)+
          ) Tuple<Any, Array<Union<Any, Any, Any, Any, Int>> > t  {        var anArray = t f2;
       anArray foreach: {            (: Union<Any, Any, Any, Any, Int> elem :)
           (elem whichOne) switch:
               case: #f1 do: { on }
               case: #f2 do: { off }
               case: #f3 do: { left }
               case: #f4 do: { right }
               case: #f5 do: { move: (elem f5) }
           }
       };
   }
   ...
end

Now the previous program can be expressed as a message send to Car:

Car do:
    on:
    move: 100
    left:
    move: 50
    right:
    right:
    move: 200
    off: ;
	

A named tuple or union can be used where an unnamed tuple or union is expected. In this way, we can declare a more meaninful type for the parameter of a grammar method. The previous example becomes:

object Car
   public fun on    { ... }
   public fun off   { ... }
   public fun left  { ... }
   public fun right { ... }
   public fun move: (Int dist) { ... }
   public (do:
           (on: | off: | left: | right: |
            move: Int)+
          ) NTuple<do, Any,
                 commandList, Array<NUnion<on,    Any,
                                          off,   Any,
                                          left,  Any,
                                          right, Any,
                                          move,  Int>> > t {        var anArray = t commandList;
          // an array of commands, each one represented by
          // an union.
       anArray foreach: {            (: NUnion<on, Any, off, Any, left, Any, right, Any,
                        move,  Int> elem :)
              /* method whichOne of union returns the Cyan symbol
                 representing the current field. From the
                 current field we can deduce the command that
                 the union represents */
           (elem whichOne) switch:
               case: #on    do: { on }
               case: #off   do: { off }
               case: #left  do: { left }
               case: #right do: { right }
               case: #move  do: { move: (elem move) }
           }
       };
   }
   ...
end

NUnion is a named union of elements. In this example, the element itself does not matter for the selectors on:, off:, left:, and right:. So the element type is Any and the value kept in the union is not used anywhere. What does matter is the field of the union that is used. That conveys the information of what command was used. If the field "on" was used, then the command was "on:". Field "move" has type Int and keeps the number given as parameter to the command move:.

Grammar methods offer a convenient way of implementing internal domain specific languages. They encompass lexical analysis, parsing, and the building of the Abstract Syntax Tree (AST). An AST is a set of objects that represent a program. An AST has a root that have references to other objects, these objects have references to other objects, and so on. In general code generation is made by sending a message "genCode" to the root object which usually generates some code and call method genCode of the objects it has references to.

In a grammar method GM that implements a DSL called L, a source code in L is a message send such as:

var g = MakeGraph numVertices: 5
                  edge: 1, 4
                  edge: 3, 1
                  edge: 1, 2
                  edge: 2, 4;

This message send is intended to build a graph with five vertices and four edges. Every message send that will call the grammar method GM is a source code in L. This source code (or message send) is transformed into an AST by the compiler. The objects of the AST are composed by tuples, arrays, unions, and types that appear in the definition of the grammar method GM. Suppose that the grammar method to be called by the above message send is

object MakeGraph
    public fun ( numVertices: Int (edge: Int, Int)* )
                 Tuple<Int, Array<NTuple<Int, Int>>> t
                 -> Graph {         // convert t to an object of Graph
        ...
    }
end

When the compiler finds the previous message send, it will build an object of Tuple to represent it. The fields of this tuple will be an integer and an array. The elements of this array are tuples of integers. This is the AST. The root of it is the Tuple object whose type is the type of the parameter t:

    Tuple<Int, Array<NTuple<Int, Int>>>

However, this AST is not very representative of the source code. It would be better represent the AST using prototypes Graph and Edge:

object Edge
    public Int from
    public Int to
end

object Graph
    public Int numVertices
    public Array<Edge> edgeArray
end
However, we cannot simply put type Graph as the type of parameter t of the grammar method of MakeGraph. The compiler would not know how to build the AST using Graph and Edge. But using annotations we can give a hint on how to relate the fields (public instance variables) of these two prototypes to the fields of the tuples and arrays that compose the type of parameter t.

Tuples and unions have fields named f1, f2, ... fn. By putting annotations to the public instance variables of a prototype, we can pretend it is a tuple or an union:

   // compatible with Tuple<Int, Int>
object Edge
    @annot( #f1 ) public Int from
    @annot( #f2 ) public Int to
end

   // compatible with Tuple<Int, Array<Edge>>  OR
   //  Tuple>Int, Array<NTuple<Int, Int>>>
object Graph
    @annot( #f1 ) public Int numVertices
    @annot( #f2 ) public Array<Edge> edgeArray
end

Now we can change MakeGraph to:

object MakeGraph
    public fun ( numVertices: Int (edge: Int, Int)* )  Graph t  -> Graph {         ^t
    }
end

A call

var g = MakeGraph numVertices: 5
                  edge: 1, 4
                  edge: 3, 1
                  edge: 1, 2
                  edge: 2, 4;

would produce and return an object of type Graph properly initialized. Note that the grammar method of MakeGraph just return the method argument. This is a simple trick to produce an AST from a message send.

Context functions can be used to make it easy to use an internal DSL. Let us use again prototype Car given in "implement a Domain Specific Language I".

object Car
   public fun on    { ... }
   public fun off   { ... }
   public fun left  { ... }
   public fun right { ... }
   public fun move: (Int dist) { ... }
   ...
end

A prototype may define a method sendToReceiver that takes a context function as parameter and evaluates the function using self as the context:

    public fun sendToReceiver: (ContextFunction<Car, Nil> b) {
        var Function<Nil> function = b bindToFunction: self;
        function eval;
    }

Using this method we can write

Car sendToReceiver: { (: Car self :)
        on;
        move: 100;
        left;
        move: 50;
        right;
        right;
        move: 200;
        off
    };

instead of writing

Car on;
Car move: 100;
Car left;
Car move: 50;
Car right;
Car right;
Car move: 200;
Car off;

Some day Cyan will not demand the ; at the end of a statement making the DSL's even more natural.

Language Groovy supports a very interesting construct called "builders" to build DSL´s or tree-like structures. For example, an object representing an html code can be build by

def html = new groovy.xml.MarkupBuilder()
html.html {
    head {
        title "Groovy Builders"
    }
    body {
        h1 "Groovy Builders are cool!"
    }
}

"{" and "}" delimit a anonymous function. html, head, and body, title, and h1 are all methods that take the function that follows them as parameter. Assume that these are methods of MarkupBuilder. This same code in Cyan can be made with context functions:

var b = MarkupBuilder new;
b html: { (: MarkupBuilder self :)
    head: {         title: "Groovy Builders"
    };
    body: {         h1: "Groovy Builders are cool!"
    }
};

Method html: would set self of the context function passed as parameter to its own self (which is b) before calling it. After that the message send "head: { ... }" to self is a message send to b. The result would be equal to the Groovy code.

The Cyan code is not as elegant as the Groovy code. But it has an advantage: it is statically-typed. The compiler would check whether the message sends inside the context functions are supported by prototype MarkupBuilder. By adding methods dynamically to objects, one can create tree-like structures in Cyan in which the tree names are not determined at compile-time. So it is possible to create XML-like structures using dynamic message sends made in the context of appropriate prototypes:

var xml = XMLBuilder new;
var text = xml build: { (: XMLBuilder self :)
    ?booklist: { (: XMLBuilder self :)
        ?author: "Isaac Newton"
        ?title: "Philosophiae Naturalis Principia Mathematica";
        ?publisher: "Royal Society"
    }
};

The call to methods publisher, booklist, title, and author would result in a runtime error. In this case, the runtime system calls method doesNotUnderstand inherited from Any by every object (similar to the method of the same name of Smalltalk). This method would be in charge of creating a XML AST (Abstract Syntax Tree) to represent the code. That representation could be a set of objects (the AST) or the XML code itself:


  
     Isaac Newton 
     Philosophiae Naturalis Principia Mathematica 
     Royal Society 
  

Default values are supported by special grammar methods:

object PrettyPrinter
    public fun (print: String (color: Int = Color.Black)?) t {         ...
    }
end

Now the color: selector is optional:

 

PrettyPrinter print: "I will be printed in black";
PrettyPrinter print: "I will be printed in red" color: Color.Red;
	

The exception handling system (EHS) of Cyan is completely object-oriented. The exceptions are objects (as in many languages), exceptions are thrown by sending messages (unlike any OO language we know of but Green), and exceptions are treated by methods that can be reused (unlike any other OO language).

All exception prototypes should inherit from CyException.

object ReadException extends CyException
end

Exception prototypes can declare instance variables. These can be used to communicate information from the place of error signalling to the place in which the error is treated.

object IllegalNumberException extends CyException
    public fun init: (Int number) {         self.number = number
    }
    public Int number
end
	

This prototype can be concisely written as
object IllegalNumberException(public Int number) extends CyException
end

An exception is thrown by sending message "throw: expr" to self. The type of expr should be a prototype that inherits directly or indirectly from CyException. Method "throw: CyException" is defined as a final method in the super-prototype Any.

if readError {
    throw: ReadException
}

Here ReadException should inherit from CyException.

An exception is caught using method catch: of every prototype that implements interfaces Function<Nil> or UFunction<Nil>. In its simplest form, a single exception is caught by a function as in this example.

var Int age ;
{
    age = In readInt;
    if age < 0 {         throw: NegAgeException(age)
    }
    Out println: "Age read is #{age}"
} catch: { (: NegAgeException e :)
      Out println: "Age #{e age} is negative"
};
   // point 1 (after message send "catch:")

When message throw: is sent to self at runtime, control is transferred to the function passed as parameter to catch:. Method eval: of this function is called passing as parameter the NegAgeException object. After that the execution continues at point

   // point 1 (after message send "catch:")

When message throw: is sent to self with an NegAgeException parameter, we say that exception NegAgeException was signalled or thrown. The function that is parameter to catch: treats the error thrown by the message send to self.

The code in Java equivalent to the above code in Cyan is

int age;
try {
    age = In.readInt();
    if age < 0 {         throw new NegAgeException(age)
    }
} catch ( NegAgeException e ) {
    System.out.println("Age " + e.getAge() + " is negative");
}

In the Cyan code, the parameter to catch: should have at least one eval: method, each of them accepting one parameter whose type is sub-prototype of CyException. In this case, NegAgeException should have been declared as

object NegAgeException extends CyException
       // '@init(age)' creates a constructor with
       // parameter age
    @init(age)
    public Int age
end
	

There may be more than one catch: selector, each one treating one exception:

var Int age;
{
    age = In readInt;
    if age < 0 {         throw: NegAgeException(age);
    }
    else if age > 127 {         throw: TooOldAgeException(age)
    }
} catch: { (: NegAgeException e :)
      Out println: "Age #{e age} is negative"
  }
  catch: { (: TooOldAgeException e :)
      Out println: "Age #{e age} is out of limits"
  };

If exception NegAgeException is thrown, control is transferred to the first function that is parameter to the first catch: selector. Assuming age receives value -1, it is printed

    Age -1 is negative

In the same way, if an age of 300 is read, control is transferred to the function of the second catch: selector. Of course there may be as many catch: selectors as needed because this is a grammar method:

 

    @checkCatchParameter
    public fun ((catch: Any)+  finally: Function<Nil>) t {         ...
    }

More about this method in the Cyan manual.

Catch objects are objects used in place of a function as parameter to a catch: selector. It can be responsible for catching several exceptions, one for each eval: method it defines.

As an example, the CatchFileException object is able to catch three different exceptions.

object CatchFileException
    public fun eval: (OpenException e)   { Out println: "Error opening file" }
    public fun eval: (ReadException e)   { Out println: "Error reading file" }
    public fun eval: (WriteException e)  { Out println: "Error writing to file" }
end

Prototype CatchFileException treats all errors associated to opening, reading, and writing to files (but not to closing a file).

This prototype can be used as in the example:

var Array<Char> charArray;
var f = MyFile new: "input.txt";
{
   f open;
   charArray = f readCharArray;
   if charArray size == 0 {        throw: ZeroException;
   }
} catch: CatchFileException
  finally: {
      f close
  }

When an exception is signaled in the function, the runtime system starts a search for an eval: method (a handler) in the nearest argument to catch:, which is CatchFileException.

Supposing that there was a read error, the correct eval: method should accept a ReadException object as parameter. The runtime system searches for the eval: method in CatchFileException using the same algorithm used for searching for a method after a message is send to an object. That is, the runtime system tries to send message eval: with a ReadException as argument to object CatchFileException. By the regular algorithm, the second textually declared method of CatchFileException, which is

         public fun eval: (ReadException e)   { Out println "Error reading file" }

is found and called. After that the function that is argument to selector finally: is called and the computation continues in the first statement after the outer function in the example.

Prototype CatchExit can be used to catch any exception and exiting with an error message:

object CatchExit<T>
    public fun eval: (T e) {
        Out println: "Fatal error";
        System exit
    }
end

It can be used as in this example:

var Array<Char> charArray;
var f = MyFile new: "input.txt";
{
   f open;
   charArray = f readCharArray;
   if charArray size == 0 {
       throw: ZeroException
   }
} catch: CatchExit<CyException>
  finally: {
      f close
  }

The eval: method of CatchExit has a CyException parameter. That means this prototype will catch all exceptions since every one of them is subtype of CyException.

This can be done with prototype CatchWarning:

object CatchWarning<T>
    public fun eval: (T e) {
        Out println: "Exception " + (T prototypeName) + " was thrown"
    }
end

Use it as in

var n = 0;
{
   n = (In readString) asInt
     // any read error is ignored
} catch: CatchWarning<ReadException>;

Of couse, one can mix CatchExit and CatchWarning (and any number of other catch objects):

{
  line = In readLine;
  if line size == 0 {
      throw: EmptyLineException()
  }
  else if line size > MaxLine {
      throw: LineTooBigException(line)
  };
  Out println "line = " + line
} catch: CatchExit<LineTooBigException>
  catch: CatchWarning<EmptyLineException>;

Generic prototype CatchIgnore takes one or more parameters and can be used to catch and ignore exceptions. CatchIgnore with two parameters is defined as

object CatchIgnore<T1, T2>
    public fun eval: T1 { }
    public fun eval: T2 { }
end

If we want to ignore two exceptions and treat a third one, we can write something like

 

{
  line = In readLine;
  if line size == 0 {
      throw: EmptyLineException
  }
  else if line size > MaxLine {
      throw: LineTooBigException(line)
  }
  else if line[0] == ' ' {
      throw: WhiteSpaceException
  };
  Out println "line = " + line
} catch: CatchIgnore<LineTooBigException, EmptyLineException>
  catch: { (: WhiteSpaceException e :)
      Out println: "line cannot start with white space";
      System exit
  };

Functions have a method hideException that just eats every exception thrown in them:

n = 0;
{
   n = (In readString) asInt
     // any read error is ignored
} hideException;

Of course, this method should be rarely used (it won't, I know that). The above example could have been written as

n = 0;
{
   n = (In readString) asInt
     // any read error is ignored
} catch: CatchAll;

CatchAll is a prototype that has a method

    public fun eval: (CyException e) { }

that catches all exceptions. This prototype is automatically included in every file. It belongs to package cyan.lang.

A common operation with exceptions is to catch an exception and convert it into another exception. Generic prototype ExceptionConverter makes it easy to implement this common pattern.

object ExceptionConverter<Source, Target>
    public fun eval: (Source e) {         throw: Target()
    }
end

This prototype is used as in this example:

...
{
  ...
} catch: ExceptionConverter<NegNumException, OutOfLimitsException>

When an exception NegNumException is thrown in the function, the catch prototype

    ExceptionConverter<NegNumException, OutOfLimitsException>

throwns exception OutOfLimitsException. ExceptionConverter can be defined for any even number of parameters.

Another common exception pattern is to catch exception E and throw exception F that keeps a reference to the original exception. This can be easily made with prototype ExceptionEncapsulator:

object ExceptionEncapsulator<Item, Container>
    public fun eval: (Item e) {          throw: Container(e)
    }
end

In the code

...
{
     // NegNumException may be thrown here
  ...
} catch: ExceptionEncapsulator<NegNumException, ArithmeticException>

any exceptions NegNumException thrown in the function are captured by prototype

    ExceptionEncapsulator<NegNumException, ArithmeticException>

which by its turn throws exception ArithmeticException.

Many exceptions may be caught using a single parameter to selector catch:, which should be an object of prototype CatchMany:

object CatchMany<T1, T2>(UFunction<Nil> b)
    public fun eval: (T1 e) {         b eval
    }
    public fun eval: (T2 e) {         b eval
    }
end

This generic prototype may take up to ten parameters. An example of its use is in

{
  line = In readLine;
  if line size == 0 {
      throw: EmptyLineException()
  }
  else if line size > MaxLine {
      throw: LineTooBigException(line)
  }
  else if line[0] == ' ' {
      throw: WhiteSpaceException()
  };
  Out println "line = " + line
} catch: CatchMany<EmptyLineException, LineTooBigException>(
            { Out println: "Limit error in line " + %line } )
  catch: CatchMany<WhiteSpaceException, ReadException>(
            { Out println: "Other error happened" });

Java now allows to catch many exceptions in a single catch in a more elegant way:

try {
   ...
} catch ( EmptyLineException | LineTooBigException e) { ... }
  catch ( WhiteSpaceException | ReadException e) { ... }

Alternative types can be declared in grammar methods:
    public fun (eval: WhiteSpaceException | ReadException) t { ... }
If this were allowed in functions, we could catch several exceptions with a single function:
{
   ...
} catch: { (: EmptyLineException | LineTooBigException e :)
           Out println: "Limit error in line " + line
  }
  catch: { (: WhiteSpaceException | ReadException e :)
           Out println: "Other error happened"
  };
Maybe that will be allowed soon.

In Cyan, it is possible to define literals such as

100meters   50yards     50kg  30lb
3000reais   500dollars   2000_euros
10this_is_unknown  0_real_1img

When the compiler finds a token that starts with a number but ends with a sequence of letters, numbers, and underscore, it searches for a metaobject capable of treating that token. This metaobject is defined using another metaobject, literalNumber:

@literalNumber<**
    endsWith: "bin", "Bin", "BIN"
    type: Int
    parser: BinaryNumberParser
**>

The body of this metaobject call should contain a sequence of pairs tag-value. One of the tags is endsWith that specifies a sequence of letters, digits, and underscore (starting with a letter or underscore) that ends this literal number (before the sequence there should appear at least a digit). In this example, there are several alternatives: bin, Bin, or BIN. The parser tag specifies the Java class responsible for treating literal numbers ended by strings given in the endsWith tag. Then a number

    101Bin

will be processed by the Java class BinaryNumberParser. Future versions of Cyan will use Cyan prototypes instead of Java classes. What happens is that, when the compiler finds a number ending by bin, Bin, or BIN, it loads the Java class BinaryNumberParser, creates an object from it, and calls a method of this object with two parameters (one of them is string "101Bin"). This method then returns 101 in binary in a way that the compiler understands (it may be just a string "5", by the way).

Anyone can create her or his literal objects. For example, one can create prototype List and define a literal object for it in such a way that a list can be given literally as in

var List myList = [* 1, 2, 3 *];
var another = [* 4, 5, 6 *];

Here the list appears between [* and *]. Any sequence of delimiters can be attached to a literal object of a certain prototype. But there is an one-to-one relationship between delimiters and prototype. It would not be possible, for example, to associate another pair of delimiters to List.

There are restrictions on what symbols can be in the start (and end) sequence of a delimiter ([* in this example). Sequences that can appear in the language, such as (: are not legal. See the Cyan manual for details.

Literal objects may also start with an identifier. In this case, the sequence that appears after the identifier can vary from call to call:

 

var Graph g1 = Graph<<+  (1, 2), (2, 3), (3, 1) +>>;
var Graph g2 = Graph(**  (1, 2), (2, 3), (3, 1) **);
var Hashtable dictionaryEnglishPortuguese = Dict( "one":"um", "two":"dois" );
var numberID = Dict<<** "one":"1", "two":"2" **>>;

Cyan has its own pre-defined literal objects for arrays and tuples:

var Array<Int> v = {# 1, 2, 3 #};
   // unnamed tuple
var Tuple<String, String> dancingCouple = [. "Ade", "Melissa" .];
   // named tuple
var t2 = [. university: "UFSCar" country: "Brazil" .];
	

See how to create your own literal object with delimiters

Suppose you want a new kind of comments that star with (* and end with *). They can be easily implemented as literal objects:

@literalObject<<*
    start: "(*"
    parse: ParseComment
*>>

When the compiler finds something like

   (*   anything *)

it calls a method of class ParseComment written in Java. This method, parseRetString, should return a single space character.

public class ParseComment implements RetString {
    public String parseRetString(String text, PCI compiler) {
        return " ";
    }
}
	

Then "(* anything *)" would be replaced by " ".

Literal objects may be defined in Cyan in several ways. There is no space here to explain all of them. We will show only a few ways of doing that. The simplest of them is just to write

@literalObject<<
    start: "<@"
    parse: ParseList
>>

When the compiler finds a code like

var myList = <@ "hi", 23, 3.14 @>;

after the declaration of the literal object (above), it uses the Java class ParseList to parse

 "hi", 23, 3.14

and return a string or an object of the Abstract Syntax Tree of the compiler. The string returned could contain

var tmp0001 = List new: 3;
tmp0001 add: "hi";
tmp0001 add: 23;
tmp0001 add: 3.14;

In this case, the compiler would replace

var myList = <@ "hi", 23, 3.14 @>;

by

var tmp0001 = List new: 3;
tmp0001 add: "hi";
tmp0001 add: 23;
tmp0001 add: 3.14;
var myList = tmp0001;
	

The regexpr tag of literalObject accepts a regular expression used to parse the literal object. The literal object should obey the grammar defined by this regular expression (or there is a compile-time error). The regular expression is composed by the regular expression operators, type names, and strings of symbols given between quotes. Each type means an expression of that type, just like in a grammar method.

@literalObject<<
    start: "<@"
    regexpr: ( String ":" Int )*
    type: ListStringInt
    parse: ParseListStringInt
>>

In this example, the regular expression given after regexpr: matches pairs of strings and integers separated by ":". The metaobject literalObject uses this regular expression to check the literal object before calling method parseRetString (or other equivalent to it) of ParseListStringInt. Therefore the checking is made twice by the metaobject literalObject and by the Java class.

The tag type gives the resulting type of the literal object, which is ListStringInt in this case. The literal defined above may be used as in

...
var portugueseList = <@ "um": 1 "dois" : 2 @>;
var englishList = <@
    "one": 1
    "two": 2
    @>;

As seen, a literal object may start with an identifier:

...
var Graph g1 = GraphBuilder<<+  (1, 2), (2, 3), (3, 1) +>>;
var Graph g2 = GraphBuilder(**  (1, 2), (2, 3), (3, 1) **);

The sequence of symbols that follows the identifier may vary from place to place. To define such a literal object, one should use metaobject literalObject with a tag "name:", which is the name that appears in the literal object definition:

@literalObject<<
    name: GraphBuilder
    parse: GraphParser
    type: Graph
>>

Using literal objects! you can insert another language inside Cyan code. See the example below with Prolog and SQL.

  // prints the result in the standard output
Prolog query: [? fat(5, X) ?]  database: [+
   fat(0, 1).
   fat(N, F) :- N1 is N - 1, fat(N1, H), F is H*N.
   +]
var v = [## select name, age from Person where age > 18  ##];
myTable = v eval;

Metaobject javacode can be used to insert Java code in Cyan code:

object Out
    public fun println: (String s) {         @javacode(**
            System.out.println(s);
        **)
    }
    ...
end

This metaobject will not be supported in a not-too-near future. For now, it is very useful in order to implement some prototypes of Cyan such as Out (responsible for basic output).

A multi-line string extends by several lines of code, which is not possible with strings delimited by " (quotes). Metaobject text is used to produce multi-line strings:

var expeditionarySong = @text<*
    Você sabe de onde eu venho?
    Venho do morro, do Engenho,
    Das selvas, dos cafezais,
    Da boa terra do coco,
    Da choupana onde um a pouco,
    Dois é bom, três é demais,
    Venho das praias sedosas,
    Das montanhas alterosas,
    Dos pampas, do seringal,
    Das margens crespas dos rios,
    Dos verdes mares bravios
    Da minha terra natal.
    ...
*>;

xmlCode = @text<**
<!--?xml version="1.0"?-->
<author>
  <authorname>
  Carol
  </authorname>
</author>
**>

The text that is argument to the metaobject text is passed as argument to a call to a specific method of this metaobject (say, parse) defined by the MOP. text is a pre-defined metaobject. A call to it is replaced by a literal array of Char's with all the characters between the delimiters. Note that to say "metaobject call" is an abuse of language. Metaobjects are objects and objects are not called. Methods are called. The compiler will in fact call some specific methods of the metaobject.

Metaobject text has an option "trim_spaces" to trim the spaces that appear before the column of @ in @text. As an example, variables t1 and t2 have the same content.

var t1 = @text(#
starts at
line 1
#);
var t2 = @text(trim_spaces)<<<*
      starts at
      line 1
      *>>>;
assert: (t1 == t2);
	

A feature is simple a key-value pair in which the key is a string and value can be any object. A feature may be associated to a prototype using metaobject feature:

@feature<* "author", "José" *>
@feature("compiler", #nowarning)
object Program
    public fun run {        ...
    }
end

In this example, the features associated to Program are:

 

("author", "José")
("compiler", #nowarning)

Features may be used by documentation tools ("author"), compilers (feature with key "compiler"), other tools, and the code itself. Of course, features may be associated to other language elements such as methods, constants, and so on. This will be better defined when the Metaobject Protocol for Cyan is defined.

There is a special kind of feature called "annotation" whose feature key is "annot". Metaobject "annot" attaches an annotation to a prototype, method, and so on:

@annot( #Author ) object Person
    public fun print {          Out println: "name: ", name, " (", age, ")"
    }
    @annot( #Authorname ) public String name
    public Int age
end

Annotations can be used in several useful tools. One of them can create automatically a XML file from an object. Method write: of a prototype XML may take an object writeThis as parameter and writes it to a file filename as XML code using the annotations as XML tags:

    write: (Any writeThis) tofilename: (String filename)

The annotated instance and shared variables are written in the XML file. The root element is the annotation of the prototype. Therefore the code

Person name: "Carol";
Person age: 1;
XML write: Person tofile: "Person.xml";
produces a file "Person.xml" with the contents:
<!--?xml version="1.0"?-->
<author>
  <authorname>
  Carol
  </authorname>
</author>

Method featureList defined in Any and inherited by every object retuns a list of features associated to the receiver.

@feature<* "author", "José" *>
@feature("compiler", #nowarning)
object Program
    public fun run {         featureList foreach: { (: NTuple<key, String, value, Any> elem :)
            Out println: "key is #{elem key}, value is #{elem value}"
    }
end

Then method run will print

key is author, value is José
key is compiler, value is nowarning
	

Method annotList defined in Any returns a list of annotation objects attached to the prototype.

@annot( #first ) @annot("second") object Test
    public fun run {         annotList foreach: {             (: String annot :)
            Out print: annot + " "
        }
    }
end

When run is called, it prints

    first second

Each Cyan source file is described by a XML file which keeps the source file in Cyan plus some other information, including history information of that source file. This information may be used to check versions of the source file, check whether something changed in the file, and so on.

Metaobject " onChangeWarn " may be attached to a prototype (including interfaces), a method declaration, or an instance variable declaration. This metaobject adds information to the XML file describing the current source code. This information will be used in future compilations of the source code even if the metaobject call is removed from the code. Using onChangeWarn one can ask the compiler to issue a warning whenever the signature of a method was changed, even after the programmer deleted the call to onChangeWarn:

object Test
    @onChangeWarn( #signature,
       "This signature should not be changed." +
       " Keep it as 'public fun test'")
    public fun test { ... }
end

If the signature was changed to

object Test
    public fun test: (Int n) { ... }
end

the compiler would issue the warning given in the second parameter of the call to onChangeWarn. All methods of the same name are grouped in the same set --- they all can be considered as the same multi-method. By changes in the signature we mean any changes in this set, which may be addition of method, deletion of method, changes in the parameter type of any method, changes in the return value type of all methods (it is illegal to change the return value type of just one method).

onChangeWarn takes two parameters. The first specifies the change, which may be:

  1. #signature for changes in the method signature;
  2. #name for changes in the name (used for prototypes only);
  3. #type for changes in the return type of a method, type of a variable;
  4. #qualifier for changes in the visibility qualifier (public, protected, private);
  5. #all for any changes whatsoever.

The second parameter to onChangeWarn gives the message that should be issued if the change specified in the first one was made. It should be a string. Other metaobjects that makes the linking past-future will be added to Cyan. Await.

This is a promise. There will be a metaobject doc to document prototypes, methods, and so on.

@doc<<
   This is a stack of integers
>>
object IntStack
    @doc{ push an element into the stack }
    public fun push: (Int elem) {         ...
    }

The details of code are yet to be defined.

Metaobject prototypeCallOnly should be attached only to a public method. It checks whether the method is called by sending a message to the prototype. Any other receiver causes a compile-time error.

object Person
    public String name
    @prototypeCallOnly public fun create -> Person { ^ Person new }
end
...
var Person p;
p = Person create; // ok
p = p create;      // compile-time error

The Cyan compiler adds some methods to every prototype. To a prototype P the compiler adds a method

    cast: Any -> P
    new -> P

The last method is added only if the prototype does not define any init methods. prototypeCallOnly is attached by the compiler to both methods (cast and new). This is necessary in order to guarantee type checking. There would be no meaning in calling cast through a variable because when we call it we want specifically the method declared in the prototype, not a method of a sub-prototype that can be called because of polymorphism (see the example).

var Person p, other, anotherPerson;
...
   // Worker is sub-prototype of Person
p = Worker;
   // p refer to a Worker from now on
other = p cast: anotherPerson;

In the last line, method cast: of Worker is called, which converts anotherPerson to Worker (since p refer to a Worker). If cast: of Person was user-defined, this is not the best thing to do. Polymorphism is undesired here. Method cast: of Person would be the correct method to be called.

The result of attaching metaobject prototypeCallOnly to a method is that the method is not included in the prototype type. It is as if the method were a static method of Java/C++/C# or a class-object method of language Green.

By reflection, one will be able to discover that an object of prototype P has indeed a method cast: Any -> P but this method cannot be called by sending a message to the object (unless it is the prototype).

Every object NTuple has a method

     copyTo: Any

that copies the tuple fields into fields of the same name of the parameter. For example, consider a book object:

 

object Book
    public String name
    public Array<String> authorList
    public String publisher
    public String year
    public fun print {         Out println: (authorList[0] + " et al. "
        Out println: name + ". Published by " + publisher + ". " + year;
    }
end

We can copy a named NTuple object to an object of Book:

 

...
var b = Book new;
var t = [. name: "Philosophiae Naturalis Principia Mathematica",
           authorList: {# "Isaac Newton" #},
           publisher: "Royal Society",
           year: 1687
        .];
t copyTo: b;

 

The last line copies the fields of the tuple into the object fields. That is, name of t is copied to name of b and so on. The Book object may have more fields than the tuple. But if it has less fields, an exception CopyFailureException is thrown. Note that copyTo: can be used to copy tuples to tuples:

 

var mary = NTuple<name, String, age, Int>
var maria = [. name: "Maria", age: 4, hairColor: "Blond" .];
maria copyTo: mary;
	

Use method exit or exit: Int of prototype System.

object Program
    public fun run:  Array<String> args {         if args == 0 {             Out println: ("This program should have at least " +
                          "one argument");
            System exit: 1
        }
        ...
    }
end