Implicit Function Return Value Capture

This mouthful of a title is really a kind of "syntactic sugar" to simplify referencing the result of a previously called function without having to map a variable and explicitly assign the value to it. To invoke the feature, you simply prefix the called function with a dot, after which the returned value of that function will be available by referencing a variable with the same name as the function—including the dot. For example:

if .fn'foo(x) < 0 then                 ! dot-prefix call

    ? "fn'foo(x) error "; .fn'foo  ! use implicit capture value

endif

 

...

 

function fn'foo(value as f6:inputonly) as f6

    ...

    .fn = expression

endfunction

 

In the above example, we have a function fn'foo() that takes a numeric argument. For the purposes of our example, assume the return value is >= 0 for success, or < 0 for an error. In the call to the function (at the top of the example), the dot prefix—.fn'foo(x) instead of just fn'foo(x)—causes the return value to be capture in a variable named .fn'foo, matching the name of the called function, with the dot prefix. That variable is then available to be used subsequently.

Effectively, this is equivalent to:

map1 .fn'foo,f,6

.fn'foo = fn'foo(x)

if .fn'foo < 0 then

    ...

 

In other words, the compiler expands a reference to a function using the dot prefix into the combination of a variable definition (map statement) and an assignment from the function to the variable. The "fingertip savings" consists of the automatic mapping of the variable and the automatic assignment, plus, in a case like the above where the function reference is not a simple call but is part of an expression, it effectively embeds the assignment into the expression in a way that otherwise would have required multiple statements and a possible rearrangement of the logic.

Another way to look at it is that aside from simply reducing the amount of coding busy work, the automatically-created dot variable (.fn'foo in this example) provides a runtime savings by eliminating the need to call the function again in order to recall its value. So logically speaking, the original example would be equivalent to:

if .fn'foo(x) < 0 then                ! normal call

    ? "fn'foo(x) error "; .fn'foo(x)  ! second call

endif

 

Comments

If the dot variable already exists in the scope of the function call, then the existing variable is re-used. The normal scoping rules apply, including the various extern directives, just as they do with any other variable reference. Only if the variable is not defined within the visible scope is it created. The newly created variable has the same scope as any other variable mapped at the present location would.

Because of the scoping rules, it is possible for multiple instances of the automatically created dot variable to exist simultaneously, with independent values. For example, a program could call the .fn'foo(x) function (using the example above) from a global context (creating a global instance of the .fn'foo variable), and it could later call the .fn'foo(x) function from within another function, using a different value of x, resulting in a local instance of the .fn'foo variable with a correspondingly different value. This can obviously lead to confusion, so caution is advised when referencing one of these implicitly created dot variables, particularly when the reference to the variable is separated from the call that last assigned it.

The implicit function return value capture feature only applies to user-defined functions with names starting with fn' (or FN' or Fn'). It does not apply to built-in dot functions like .instrr().

The dot prefix is not part of the function name; instead it acts as a compiler directive. The function can be called with or without the dot prefix, but the implicit return value capture only occurs when called with the dot prefix.

The feature requires compiler edit 939, which is included with the 6.5.1695.0 release as well as separately, and it is entirely implemented within the compiler. There is no runtime dependency.