Using Nasal functions
| The FlightGear forum has a subforum related to: Nasal Scripting |
| Nasal scripting |
|---|
| Nasal internals |
|---|
A Nasal function is a reusable block of code associated with a symbolic name.
Simple Examples
Functions are typically called by appending parentheses to their name. Functions without return statements implicitly return nil.
var hello = func() {
print("Hello!");
};
hello(); # Traditional invocationDefining Function Arguments
Anonymous Arguments
If parameters are omitted in the function signature, passed arguments are implicitly accessible via the local arg vector:
var log_message = func {
print(arg[0]);
};
log_message("Test");Named Arguments & Default Values
You can define explicit parameter names. Default values must be constants and placed at the end of the argument list. Extra arguments spill over into the arg vector, or a custom vector using trailing ellipsis (...).
var log_message = func(line, msg = "error", extra...) {
# 'extra' holds any additional positional arguments as a vector
};Invocation Methods
Positional Arguments
Arguments are mapped to the signature sequentially:
var greet = func(name, greeting = "Hello") { print(greeting, " ", name); }
greet("FlightGear"); # Uses default greetingNamed/Hash Arguments
Passing a hash literal instead of a list bypasses ordering restraints and sets up the function's namespace directly:
var lookat = func(heading = 0, pitch = 0, fov = 20) {}
lookat(fov: 55, heading: 180); # order independent
# lookat(fov=55, heading=180); # this is wrongArgument Passing Semantics
- Scalars (strings, numbers) are passed by value (copied).
- Containers (hashes, vectors) are passed by reference (shared memory).
var modify = func(scalar, vector) {
scalar += 1; # Outside variable unchanged
vector[0] = 42; # Outside variable modified
};Implicit Returns & Nesting
Nasal functions implicitly return the value of their last expression. Parentheses and braces can be omitted for simple one-liners.
var add = func(p1, p2) p1 + p2; # Implicit return, syntax simplifiedFunction Overloading
Nasal does not natively support standard function or operator overloading. Emulate this manually by checking argument types with typeof() or inspecting the arg vector count:
var multiply2 = func(params) {
if (typeof(params) == "scalar") return params * arg[0];
if (typeof(params) == "vector") return params[0] * params[1];
};Function Closures
Every time a function is evaluated, it generates a new object bound to its lexical scope (outer namespaces).
The Lexical Scope Trap
Functions reference their outer variables, they do not copy them. This can lead to bugs in loops:
var result = [];
for (var i = 0; i < 10; i += 1) {
append(result, func print(i)); # Traps reference to 'i'
}
# Calling any function in 'result' now prints '10', because i evaluation happens at execution time.To fix this, force evaluation using an intermediate generator function or use bind():
var generator = func(i) return func print(i);
for (var i = 0; i < 10; i += 1) {
append(result, generator(i)); # Creates distinct local scope copies
}Advanced Invocation via call()
|
|
For fine-grained control—such as passing a me reference object, altering the local namespace hash, or catching runtime exceptions safely—use the built-in call() API:
call(function, vector_of_arguments, object, namespace, error_vector);If a runtime error occurs, metadata is safely appended to the `error_vector` instead of crashing the script execution context.