Omega Functions & Methods

Omega allows users to define functions as regular objects and to pass them as arguments to functions. This provides a powerful yet simple way to paramterize certain computations, akin to the apply() of Lisp and other languages. Essentially, functions are stand-alone methods that are not associated with any class. They are not compiled and so are easier to modify, test, modify,...

Default Argument Values

Default values for arguments can be provided in a function definition. This means that the user does not have to specify a value for that argument. The matching of the names
 function foo(x = 1, y = new util.Vector(10)) {

 }

Closures

As Robert Gentlemen & Ross Ihaka have written and Luke Tierney has explained, flexible name spaces and scoping are an important aspect of statistical computing. Omegahat supports "static" variables within a function body which has that effect of preserving the value of that variable across calls. This is similar to static variables in C and Java and leads to fields in classes. User Classes

As an interesting example of extending the Function is to implement tail recursion. By this we mean a function whose last instruction is to call itself. Hence we have recursion in the tail of the function. Recognizing such functions means we need not create a new evaluation frame for the recursive call, since when we return from it, we will also return from the parent call - a feature of the tail. This has efficiency implications and avoiding stack overflow.

Omegahat analyzes functions when they are defined and determines the appropriate class - Closure, Tail Recursive function, Tail Recursive closure, etc.

Variable Number of Arguments

Unlike Java, Omegahat supports specifying an argument as ... in the same way as S and R do. This means that arbitrary values can be passed in place of this argument and accessed collectively or individually
[1] foo = function(...) { get("...").size(); $1;}
function foo(...) -> java.lang.Object
get("...").size();
$1;

[7] foo(1,2,3)
2

Lazy Evaluation

Users of S will be familiar with lazy evaluation and the fact that all arguments are evaluated only when they are derefernced (or used). In Omegahat, individual arguments of a function can be specified as either lazy or eager, with the default being eager. Eager arguments are evaluated when the function is called. Lazy arguments are evaluated when needed. This allows for improved efficiency since arguments that are not used are not evaluated.

To avoid specifying each argument as lazy, one can set the default argument mode for a function by preceeding it with a lazy qualifier.

 lazy function foo(x, y) {
   ..
 }
Then individual arguments can be specified as eager
  lazy function foo(x, eager y) {
  }
just as one can specify lazy qualifiers when the default mode is eager.

The eager and lazy qualifiers preceed any type declarations for the parameter.

 function foo(lazy util.Vector x)

Compilation

In the near future, we will offer the ability to compile an Omegahat function into Java byte code (and perhaps Java source code). This will allow the user to take advantage of the simplicity of defining and refining interpreted functions and then commit the "finished" version to avail of the speed of a compiled version. In most cases, the author will be required to provide type information in the function definition or at least hints. Alternatively, we will identify types based on the current values of the "free" variables.

The type information will be specifiable externally from the function (as an additional argument to the compiling method) so as to avoid redefining the function. In this way, we can think of the function as a template.

In addition to functions, we will be able to compile user-level classes and methods as well as global methods/functions.


Duncan Temple Lang <duncan@research.bell-labs.com>
Last modified: Sat Aug 7 11:32:22 EDT 1999