Shlaer-Mellor and Executable UML Portal

(Top Tabs)

Action Language

Last Updated: 30 May 2009

Introduction

The Action Language for OOA10 is used to define all operation semantics including:

  1. Mathematically dependent attributes are called derived attributes in Executable UML.
  2. Mathematically dependent relationships are called derived associations in Executable UML.
  3. Actions are called procedures in Executable UML.
  4. Processes are called actions in Executable UML.
To help understand some of the above terminology, wormholes and control reception points are categorized below:

The current Action Language syntax grammar defined using Pattern Language syntax and lexical rules is:

ActionLanguage0.01.pattern (drop the ".html" suffix for the actual pattern)

Design

The design of the Action Language for OOA10 is important for people to understand so that they can accept it more readily. There are lots of programming languages out there (my favourite being Java™ although I still love Lisp) with lots of great features that you won't find here and there are good reasons for that.

The overriding reason that the Action Language must be simple is that it needs to be readily translatable into many other programming languages without the benefit of a team of compiler specialists. Shlaer-Mellor OOA/RD (and Executable UML/MDA) requires that an application containing Action Language code be mapped to a software architecture and then translated to deployment platform code. The software architecture and choice of deployment programming language should be made by the application development team not a tool vendor. It is way too easy for tool vendors to add lots of features to an Action Language in an effort to sell their CASE tool more easily (and more expensively!). However, it is not in the users' interest to fall for this. The users may end up writing many thousands of lines of Action Language code but those users will probably still have to debug the deployed code. If the Action Language is feature rich then the deployed code will be that much more complicated.

The second reason that the Action Language should be kept simple is that it will need to be readily understandable by everyone on the team, not just the programmers, since it will be used to formally specify constraints and logic within the application domain. Analysts and even sophisticated end users may want to review some of this business logic rather than rely solely on verbal descriptions (or Use Case models).

The third reason is that an Action Language should look distinctly different from a programming language so that analysts and programmers are constantly reminded that they are not creating the deployment platform code at this stage. The translator will be able to perform many optimizations when producing the deployed code well beyond what is possible with an ordinary compiler since the translator will have much more information available to it.

Unfortunately, there is no standard Action Language already defined. All of the existing Shlaer-Mellor OOA/RD (and Executable UML/MDA) tool vendors have created their own proprietary Action Languages. Even UML doesn't have a standard Action Language yet, although there is an effort under way to propose one. Most of these Action Languages have been placed in the public domain in an effort to spread their adoption by new tool vendors. The two most popular Action Languages are Object Action Language (OAL) from Mentor Graphic's BridgePoint® product and Action Specification Language (ASL) from Kennedy Carter's iUML product.

Rather than start from scratch creating a completely new Action Language for OOA10, a decision was made to start from one of the existing Action Languages. OAL [BPAL97] [OAL02] [OAL08] was chosen rather than ASL [ASL03] since OAL is very simple and readily understandable by non-programmers. However, OAL does not include all of the features that are needed in OOA10 and it has some rough edges which need to be rounded off. OOA Tool may also end up supporting multiple Action Languages in the future, especially if the OMG endorses an acceptable Action Language as part of the UML standard. However, OOA10 will only specify a single Action Language as part of it's specification. Even though OOA Tool will probably support multiple Action Languages in the future, they will all have to map to the Action Language subsystem of the OOA of OOA since metamodel population data defined by this subsystem is what's used to translate Action Language code to deployment platform code.

There are a number of other Action Languages worth mentioning:

Not only is the OOA10 Action Language based on OAL, it also aims to maintain some level of backwards compatibility. Thus, it is worth looking in more detail at a syntax grammar of OAL. The OAL reference manual provides a syntax grammar in an appendix but it isn't easy to follow. A more readable syntax grammar was produced from scratch as part of a BridgePoint 4.2 analysis (see BridgePoint 4.2 Model for more details):

Syntax and Lexical Rules for Object Action Language
Some assumptions and slight simplifications had to be made when producing this Pattern Language syntax grammar since BridgePoint itself wasn't available and the syntax as explained in the documentation is very quirky. It has also been structured so that it can be more easily compared with the OOA10 Action Language syntax grammar. The differences between OOA10 and OAL are summarised later after all Action Language statements and expressions have been discussed in detail.

Control Structures

If Block

The main conditional control structure is the if block:

    IF '(' booleanExpression ')'
        statementBlock
    { ELIF '(' booleanExpression ')'
        statementBlock }*
    [ ELSE
        statementBlock ]
    END IF ';'
    
Parentheses around control structure conditions are not optional in OOA10.

Switch Block

A conditional control structure for use with enumerated values is also provided:

    SWITCH '(' enumeratedExpression ')'
    { CASE legalValue { ',' legalValue }* ':'
        statementBlock }+
    END SWITCH ';'
    
There is no default case here since all cases must be explicitly provided. A major source of bugs in my experience is incomplete switch statements and broken default cases. Another source of bugs is missing break statements. However, break statements are not used to exit switch statements in OOA10 and control doesn't flow from one case to the next. Instead, each case is associated with all of the legal values that will be handled in the case's statement block. A given legal value can't be associated with more than one case.

For Each Block

The main iterative control structure (in most Action Language code) is the for each block:

    FOR EACH variable IN ( variableOrInputParameter | '(' expression ')' )
        statementBlock
    END FOR ';'
    
There is no traditional for block since there is no array element indexing at present which is often used in conjunction with traditional for blocks. However, OAL08 does introduce a syntax for array element indexing but does not define any associated semantics. A break statement can be used to exit a for each block. A continue statement can be used to skip the current iteration.

In OAL, the iterations of a for each block may in theory be executed in parallel. However, in practice, OAL does not define adequate semantics to enable the iterations to be executed in parallel. The iterations of a for each block are always executed sequentially in OOA10. If concurrent iterations are required then a process model should be used instead since process modelling does provide adequate semantics to enable parallel iterations.

The loop variable is implicitly declared just before the for each block if not already declared. This means that the loop variable remains in scope after the block ends. The implicit declaration will declare the loop variable as having the same type as the set expression. The set expression doesn't need to be an object instance expression and doesn't need to have a multiplicity of many. The implicit declaration will always have a multiplicity of one and will only be conditional if the set expression is conditional. The loop variable is assigned a value on entry into each iteration. If no iterations are executed because the set expression is empty then no value will be assigned.

While Block

A more traditional while block is also provided:

    WHILE '(' booleanExpression ')'
        statementBlock
    END WHILE [ numericExpression ] ';'
    
A break statement can be used to exit a while block. A continue statement can be used to skip the current iteration.

Infinite loops involving multiple state model states are acceptable since a single state machine can't hog all of a system's resources. However, all operations are assumed to complete within a finite amount of time allowing a balanced distribution of resources across state machines. As a consequence, all while blocks must terminate in OOA10. An infinite loop error should be reported if it can be determined statically that a while block will never terminate. However, it is not always possible to determine whether a loop will terminate.

In most situations, an analyst can easily determine an iterations limit that will never be exceeded assuming the while block has been coded correctly. OOA10 allows this limit to be specified after the end while keywords, for example:

    declare n as Integer;
    declare fibonacci_n as empty or one Integer;
    if (n < 0)
        fibonacci_n = ?;
    elif (n == 0)
        fibonacci_n = 0;
    else
        fibonacci_n_minus_1 = 1;
        fibonacci_n = 1;
        i = 2;
        while (i < n)
            fibonacci_n_minus_2 = fibonacci_n_minus_1;
            fibonacci_n_minus_1 = fibonacci_n;
            fibonacci_n = fibonacci_n_minus_1 + fibonacci_n_minus_2;
            i = i + 1;
        end while n - 2;
    end if;
    
If the increment i statement in the example above is missed out then an iteration limit error should be reported when the code above is executed (assuming n > 2). However, iteration limit checking is like Java assert checking, i.e. it may be turned off in a deployed system. Thus, it is very important that all iteration limit errors be discovered and fixed prior to deployment.

The numeric expression defining the iteration limit is either evaluated after the while condition is first evaluated or not at all. It is never evaluated more than once. It is also never evaluated if the while condition evaluates to false immediately indicating no iterations are required. The iteration limit which is always rounded up may be zero or negative indicating no iterations should occur. It doesn't matter how approximate the iteration limit is as long as it is never less than the number of expected iterations. However, it can sometimes be useful to specify the exact number of iterations if the calculation is not too complicated since it may help validate (or not!) the algorithm being implemented.

An optional Default Iterations Limit attribute is associated with each project ensuring that iteration limits are not required on all while blocks. This default limit can be set to a high value so that iteration limit errors are only reported as a last resort. However, to reduce the chance of frozen simulations, proper use of iteration limits is recommended in OOA10.

Break Statement

for each blocks and while blocks can be exited prematurely using a break statement:

    { BREAK }+ ';'
    
Rather than add support for loop labels and labelled breaks, OOA10 allows nested break statements, for example:
    select many objects from instances of Object;
    for each object in objects
        select many attributes related by object->Attribute[defines];
        for each attribute in attributes
            if (attribute.Name == "No Name")
                // Found an attribute with no name...
                break break;
            end if;
        end for;
    end for;
    
When using nested break statements in this way, one must be very careful not to add additional semicolons. Doing so will result in an unreachable statement error after the first semicolon.

Continue Statement

for each blocks and while blocks can also have the current iteration skipped using a continue statement:

    { BREAK }* CONTINUE ';'
    
A continuation causes a jump to the beginning of the block as if the current iteration had completed normally. Rather than add support for loop labels and labelled continues, OOA10 allows nested continue statements which work in a similar way to nested break statements. However, a nested continue statement doesn't perform multiple continuations, it performs one or more breaks and then performs a single continuation.

Objects

Create Object Statement

Object instances can be explicitly created using the create object statement:

    CREATE OBJECT ( INSTANCE [ variableOrSelf ] OF objectSpecification
                  | INSTANCES [ variableOrSelf '=' ] objectSpecification
                              { ',' [ variableOrSelf '=' ] objectSpecification }* ) ';'
    
An object instance is also implicitly created after a creation state has been entered if the self object instance isn't explicitly created in the action associated with the creation state. The self keyword must be used explicitly in this case so that we can determine which object instance to associate with the newly created state machine. The self keyword should not be used as a create target anywhere else.

OAL requires all object instances to be explicitly created using the create object instance statement. However, OOA10 only requires leaf object instances to be explicitly created unless Manual Subtype-Supertype Relationships attribute is set on a particular project. This attribute is only provided for backwards compatibility and its use isn't recommended. Furthermore, all leaf object instances which form part of a single component instance must be created in a single create object instances statement. The instances keyword highlights the fact that multiple object instances may be created even if only one object instance is specified. The create object instance statement can still be used to create a single leaf object instance as long as it doesn't participate in any subtype-supertype relationships. As a consequences, subtype-supertype relationships are always implicitly created.

Where object specification is defined as:

    objectReference [ '(' [ attribute ':' expression
                              { ',' attribute ':' expression }*
                              [ ',' CURRENT_STATE ':' enumeratedExpression ]
                          | CURRENT_STATE ':' enumeratedExpression ] ')' ]
    

Delete Object Statement

Object instances can be explicitly deleted using the delete object statement:

    DELETE OBJECT ( INSTANCE | INSTANCES ) objectInstanceExpression ';'
    
An object instance is also implicitly deleted after a deletion state has been entered if the self object instance isn't explicitly deleted in the action associated with the deletion state. The self keyword doesn't need to be used explicitly in this case.

Migrate Statement

    MIGRATE OBJECT INSTANCES objectInstanceExpression TO
        [ variable '=' ] objectSpecification
        { ',' [ variable '=' ] objectSpecification }* ';'
    

Select From Statement

    SELECT ( ANY | MANY ) variable
        FROM ( INSTANCES OF objectReference | objectInstanceExpression )
        [ whereClause ] [ orderedByClause ] ';'
    

Where where clause is defined as:

    WHERE booleanExpression
    

Relationships

Relate Statement

    RELATE objectInstanceExpression TO objectInstanceExpression
        ACROSS relationshipSpecification [ USING objectInstanceExpression ] ';'
    

Where relationship specification is defined as:

    relationshipID [ '.' verbPhrase ] | verbPhrase
    

Unrelate Statement

    UNRELATE objectInstanceExpression FROM objectInstanceExpression
        ACROSS relationshipSpecification [ USING objectInstanceExpression ] ';'
    

Select Related By Statement

    SELECT ( ONE | ANY | MANY ) variable RELATED BY instanceChain
        [ whereClause ] [ orderedByClause ] ';'
    

Where instance chain is defined as:

    objectInstanceExpression { "->" objectReference [ '[' relationshipSpecification ']' ] }+
    

Where ordered by clause is defined as:

    [ REVERSE ] ORDERED BY ( [ REVERSE ] attribute { ',' [ REVERSE ] attribute }*
                           | relationshipSpecification )
    

Events

Generate Statement

Create Event Statement

Delete Event Statement

Operations

Invoke Statement

Return Statement

    RETURN [ expression | parameter ':' expression { ',' parameter ':' expression }* ] ';'
    

Variables

Assign Statement

    [ ASSIGN ] ( assignTarget expression | invokeTarget invokeExpression ) ';'
    

Declare Statement

All local variables in OAL are implicitly declared when first assigned. However, OOA10 also allows variables to be explicited declared using the new Declare statement:

    DECLARE variable AS [ [ EMPTY OR ] ( ONE | MANY ) ] dataType [ '=' expression ] ';'
    

Expressions

Differences Between OOA10 and OAL

Change Log

Version 0.01 Initial tracked version.
Requires OOA Tool 1.0 BETA Build 014 (or later).
Version 1.0 Requires OOA Tool 1.0 Standard (not released yet).

(Bottom Tabs)

Copyright © 2008-2010 by Kavanagh Consultancy Limited. All rights reserved.