capri, a script language

Home | Documentation | Releases | Sources | Contact

Tasks/Functions

A task is equivalent to a function. It consists of the following parts

task createAnimal depends prepareAnimals { }
function createAnimal depends prepareAnimals { }

Parameters

Parameters can be declared using a comma-seperated list of identifiers and optionally a default value for each parameter:

task milkCow(cow) { }
task createCows(number = 1) { }

The default value for a parameter can be any expression. This expression will be evaluated using the declaration context of the task.

Dependencies

A task may have a list of dependencies, which can either be expressions or simply the name of a task. Before the task is called, all dependencies are evaluated in the order they are defined. Only if all dependencies return "true", the task is called.

task a {}
task b depends a {}
task c depends a(), e {}
task d depends b() == false {}
task e depends c {}

In the above example, when calling

Statement

The body statement can be any statement.

Task declaration & context

A task can be declared anywhere and assigned to a variable like any other type of value.

task someTask() {
  IO.println("I am a task in global space.");
}

project Farm {
  
  task createCows(number) {
    IO.println("I am a projects task.");
  }
  
  task prepareCowMilker() {
    def cowMilker = task {
      IO.println("This task is anonymous.");
    };
    return cowMilker;
  }
}

When a task is declared, the "declaration context" for this task is set. If the task is declared within another task, the project context of the task is used; otherwise the global context is used. This is necessary because the inner contexts of a task during its execution are deleted once the task finishs.

Dynamic task creation & passing values

If you declare a task within another task, you can not simply use the values of the declaring context within the inner tasks context (because the inner tasks declaration context is the parent context of the task where it's declared in).

If you need to pass values to a task when declaring it, you can do so by setting default values for parameters. Assuming that the cow-milker task above needs an additional parameter to function:

/**
 * This does not work, because the variable "number" is
 * declared in the parent tasks context, but the inner task
 * can not see it (as it's declaration context will be the
 * parent context of the parent task).
 */
task prepareCowMilker() {
  number = 20;
  def cowMilker = task() {
    IO.println("I am milking {number} cows!");
  };
  return cowMilker;
}

/**
 * This works around the above problem, using the default
 * values to pass a value from the declaration context into
 * the task context.
 */
task prepareCowMilker() {
  num = 20;
  def cowMilker = task(number = num) {
    IO.println("I am milking {number} cows!");
  };
  return cowMilker;
}