Last Updated: 30 May 2009
The Action Language for OOA10 is used to define all operation semantics including:
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)
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 LanguageSome 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.
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.
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.
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.
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.
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.
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.
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 ] ')' ]
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 OBJECT INSTANCES objectInstanceExpression TO [ variable '=' ] objectSpecification { ',' [ variable '=' ] objectSpecification }* ';'
SELECT ( ANY | MANY ) variable FROM ( INSTANCES OF objectReference | objectInstanceExpression ) [ whereClause ] [ orderedByClause ] ';'
Where where clause is defined as:
WHERE booleanExpression
RELATE objectInstanceExpression TO objectInstanceExpression ACROSS relationshipSpecification [ USING objectInstanceExpression ] ';'
Where relationship specification is defined as:
relationshipID [ '.' verbPhrase ] | verbPhrase
UNRELATE objectInstanceExpression FROM objectInstanceExpression ACROSS relationshipSpecification [ USING objectInstanceExpression ] ';'
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 )
RETURN [ expression | parameter ':' expression { ',' parameter ':' expression }* ] ';'
[ ASSIGN ] ( assignTarget expression | invokeTarget invokeExpression ) ';'
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 ] ';'
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). |