swirl Guide to OmniMark 5   OmniMark home
docs home 
IndexConceptsTasksSyntaxLibrariesOMX VariablesErrors
 
    Related Syntax  
Functions

Like most languages, OmniMark supports functions. Unlike many languages, an OmniMark program is not simply a hierarchy of functions. Rules are the principal structural element of OmniMark programs. Functions are supplementary structures. Functions cannot contain rules (though they can invoke them through submit, do xml-parse, or do sgml-parse). You can use functions to encapsulate code you use commonly within different rule bodies. You can also use functions as pattern matching functions or within patterns to dynamically define a pattern to be matched.

Functions isolate sections of code, but don't isolate you from the current environment, in particular the current output scope. "Output" in a function goes to the current output scope. If a function has a return value, that value goes to the calling action. If a function changes the destinations of the current output scope (with output-to), this carries over to the calling environment.

A function that returns a value is defined as follows:

  define integer function add
     (value integer x,
      value integer y)
     as
     return x + y

The return type of the function is declared following the define keyword. It may be any OmniMark variable type or any OMX component type. The value is returned using the return keyword. return exits the function.

Here is how the "add" function can be called:

  process
     output "d" % add(2,3)

Functions can generate output. The following function outputs the value it generates rather than returning it to the calling action. Note that it has no return type in the definition and no return is required:

  define function output-sum
     (value integer x,
      value integer y
     )as
     output "d" % (x + y)

This function is called as if it were a regular OmniMark action:

  process
     output-sum(2, 3)

You can also write functions that both return a value and do output:

  define integer function add
     (value integer x,
      value integer y
     )as
     output "I will add %d(x) and %d(y)%n"
     return x + y

  process
     local integer z
     set z to add(2,3)
     output "%d(z)%n"

While it is certainly possible to program like this, we recommend that you avoid writing functions that both do output and return a value. Not only do they make it hard to follow your code, but they can have unexpected results. In particular, if the return value is directed to current output, you may not get the function's return values and output in the order you expected.

Finally, you can write functions that neither return a value nor create output:

  define function clear-flags
      (modifiable switch the-flags
      ) as
      repeat over the-flags
        set the-flags to false
     again

This function clears all the switches on a switch shelf that is passed to it as a modifiable argument.

Functions and the rules that call them

Whatever you can do in the rule that calls a function you can do in the function itself. For example, a function can use the %c operator, or the "%v" or "%q" format items when called from a rule that supports them. The most useful application of this feature is the ability to write a function that does generic processing on a class of markup element types.

Side effects

The principal job of a function that returns a value is to calculate and return that value. However, a function may have side effects on the global state of the program. While writing functions with side effects is appropriate in some situations, you should exercise caution when using this technique as it can lead to programs that are difficult to debug and hard to read and maintain.

Function side effects can be particularly problematic with functions used in patterns and in the guards of rules. To allow for optimization of pattern matching routines, OmniMark does not define whether a pattern or the guard on a pattern is executed first (a pattern is itself a kind of guard on a statement, so this is sensible). You should never write a program that depends on the order in which a pattern and a guard on that pattern are executed.

In the case of patterns that fail, OmniMark does not guarantee that all parts of the pattern will be tried, or that the same parts will be tried in all circumstances. This allows OmniMark to optimize pattern matching. You should never write a program that depends on the side effects of a function called in a pattern that fails.

      Related Syntax
   define function
 
----

Top [ INDEX ] [ CONCEPTS ] [ TASKS ] [ SYNTAX ] [ LIBRARIES ] [ OMX ] [ OMX ] [ ERRORS ]

Generated: August 11, 2000 at 3:06:21 pm
If you have any comments about this section of the documentation, send email to docerrors@omnimark.com

Copyright © OmniMark Technologies Corporation, 1988-2000.