Previous: Imperative Statements, Up: Interfaces [Contents][Index]
A function can be used to name and reuse a sequence of imperative statements. As of version 2.20, a function is not required to be scoped to an interface or component behavior, but may be defined in the same scope as interfaces and components, see also See Dezyne Files.
function ::= type identifier "(" parameter-list ")"
"{" imperative-statement* "}"
| type identifier "(" parameter-list ")" ";"
For example:
void foo ()
{
bye;
cruel;
world;
}
bool bar (bool b, int i)
{
if (b)
world;
idle = i == 12;
return idle;
}
Functions are allowed to be called recursively. This includes mutual
recursive functions (function f calling function g and
vice versa). However only as long as every function involved in the
recursion is tail recursive; which means that a recursive call is
the last statement in the function.
Previous versions of the language restricted functions to the scope of behaviors. Starting with version 2.20 functions may be declared independent from interface and component behaviors. This obviously results in the ability to allow functions to be reused across behaviors and thereby prevent duplication of data related functions. Functions not confined to the scope of an interface or component may or may not be defined in the Dezyne language. In the latter case, during verification, the entire range of possible return values is verified by selecting each value non-deterministically.
Instead of using a port to query whether a pin is valid:
interface ipin
{
in bool valid (PIN pin);
behavior
{
on valid: reply (false);
on valid: reply (true);
}
}
A user may declare a foreign function:
bool pin_valid (PIN pin);
The foreign function declaration of pin_valid in Dezyne allows a
user to (re)use an implementation in the target programming language
with the same name. The difference being that any Dezyne component can
invoke the foreign function, relying on the linker in for instance
C++, without the need to instantiate the corresponding port and
having to assign the function to the port event slot during integration
for every component that must check the validity.
Now the question remains when should you opt for the first case or the second. This is straightforward, when there is additional state beyond the state of the data being passed to the call and there are other calls that must also inspect the additional state, you should choose a port over foreign functions to maintain this additional state.
A expression functions can be used to name a single expression of type bool.
expression-function ::= bool identifier "(" ")" "=" expression ";"
The expression of the expression functions can contain calls to other expression functions but regular function calls or actions are not allowed. Note that expression functions can be used in a declarative context, like guards and invariants, while this is not allowed for regular functions.
Expression functions are available as of Dezyne 2.19.0.
Previous: Imperative Statements, Up: Interfaces [Contents][Index]