Caste Declarations

The concept of caste is analogous to the concept of class in object-oriented languages. Similar to class, a caste is a template of agents, and also a classifier of agents. However, caste differs from class in both structure and dynamic behaviour.

Structure of Caste and Agent

The following syntax definition in EBNF define the structure of castes.

CasteDeclaration ::=

[ Imports ] [ Uses ]

⟨CASTE⟩ CasteName=Identifier "(" [ParamDeclaration] ")" [⟨EXTEND⟩ CasteName] "{"

{ ObserveDeclaration ";" }

{ TypeDef | ConstDef }

{ VarDeclaration ";" }

{ ActionDeclaration }

InitDeclaration

RoutineDeclaration

"}"

⟨EOF⟩

Import and Uses

The Imports clause lists the names of definition packages used in the declaration of the caste. The Uses clause lists the caste names of those castes that this caste declaration depends on. Data types and constant definitions can be made within a caste declaration as local definitions and their scope is within the caste.

Uses ::= ⟨USES⟩CasteNameList ";""

CasteNameList ::= CasteName { "," CasteName }

Imports ::=⟨IMPORT⟩ DefPackNameList ";"

DefPackNameList ::=DefPackName { "," DefPackName }

Caste Parameters

The optional parameter list in the head of caste declaration defines the param- eters used for initialising agents when they are created.

ParamDeclaration::= Name_and_Type { "," Name_and_Type }

Name_and_Type ::= CasteParameter=Identifier ":" TypeName

Each identifier in the parameter list defines a caste parameter whose scope is within the caste. Its type is given in the TypeExp. Its value is determined when an agent of the caste is created by the corresponding expression as the actual parameter. The value of a caste parameter cannot be modified.

Environment Declarations

The syntax is:

ObserveDeclaration ::= ⟨OBSERVE⟩ CasteName { "," CasteName } ";"

The environment declarations in a caste declaration defines a set of other agents whose actions can be observed by the agent of this caste and the values of whose state variables can be obtained. An observe-clause declares that the agent observes the agents of the castes listed in the declaration. In other words, it subscribes the events generated by the agents of the castes. When an agent in an observed caste takes a visible action, this agent can capture the event and may trigger actions in the agent itself, such as specified by a when-statement or a till-statement.

State Variable Declarations

State variable declarations are used to define the variables that represent the state of the agent. The value of a state variable can be viewed by other agents if it is declared as visible by the keyword state, but it cannot be modified by any other agents.

Each state variable declaration defines one variable of a particular type.

State variables are global in the sense that it is accessible in the init and body statements throughout the whole lifecycle of the agent.

var status:string;

state var eMoji: string;

For example, in the above, the variable status is not visible by other agents. But, the value of the variable eMoji can be observed by other agents.

Action Declarations

An action declaration declares an actions that the agent can perform. The syntax for declaring the actions are as follows.

ActionDeclaration ::=

[ ⟨INTENAL⟩] ⟨ACTION⟩ ActionName=Identifier "(" [ ParamDeclaration ] ")"

"{" Statement "}"

An action can have any number of parameters, which are listed with their types. Each action has a statement as its body. When an action it taken by the agent, the body is executed. The following is an example of action declaration. When the execution of the action body finishes, an event is generated and delivered to all agents that observes this agent, if the action is not an internal action.

Var messageLog : String;

...

messageLog := "";

...

action say (word: String) {

messageLog := messageLog + word + ";"

}

Initialisation

The initialisation clause defines how agents of the caste are initialised. The syntax is given below.

InitDeclaration ::= ⟨INIT⟩"{" Statement "}"

The initialisation statement that is executed once when the agent is created.

Body

The body clause defines the body of the agent, i.e. the code for agents of the caste to execute. It consists of a statement and optionally some local variable declarations, and local action declaration.

RoutineDeclaration ::= ⟨BODY⟩ "{" Statement "}"

The body statement of the caste are repeatedly executed by the agents of the caste until the agent is destroyed or quits from the caste. The state variables declared within the body are called local variables. Similarly, the actions declared with the body are local actions. The scope of the local state variables and local actions is within the body of the caste. Performing a local action will not generate any externally visible events.

For example, the following is a "Hello world!" program in CAOPLE.

caste Peer(){

action say(word: string) { }

init {

say("Hello world!");

}

body { }

}

In this example, an agent of Peer caste is capable of performing the action say. When an agent of this caste is created, it will execute the initialisation statement, i.e. perform the action say("Hello world!"). It will then execute the body statement. In this case, it is empty; thus, the agent will do nothing after say "Hello world!".

Inheritance

The Extend-clause gives the caste from which it inherits.

If a caste inherits another caste, then it logically contains all the environment, state variables, actions of the inherited caste and the body code in addition to its own.

If a variable is declared with a name that is already in the inherited caste, the new declaration will over-write the existing inherited variable declaration. Similar, if an action is declared with a name already in the inherited caste as an action name, the new declaration over-writes the inherited action. The identifiers used in the caste declaration and the castes from which it inherits must all be disjoint unless the new declaration is an over-writing.

The inheritance relations between castes must not be cyclic. For example, consider the following caste declaration.

caste GreetingPeer() inherits Peer;

observe Peer;

init {

super();

}

body {

when exist x in Peer: say("Hello world!") {

say("Welcome to the world!")

}

}

}

Note that, when a caste A inherits caste B, the initialisation of the caste B is performed when the super-statement is executed.

A GreetingPeer agent will say "Hello world!" as Peer agents do because of the execution of the super() statement in the init-statement of caste GreetingPeer. In addition, whenever a Peer agent says "Hello world!", it will respond by saying "Welcome to the world!". Note that, a GreetingPeer agent is also a Peer agent, since GreetingPeer is a subcaste of Peer. Thus, GreetingPeer agent’s behaviour is effectively equivalent to the following.

caste Peer;

observe Peer;

action say(word:string){};

init {

say("Hello world!");

}

body{

when exist x in Peer: say("Hello world!") {

say("Welcome to the world!")

}

}

}