IndexNextUpPreviousUrbi SDK 3.0.0

Chapter 9
Functional Programming

urbiscript support functional programming through first class functions and lambda expressions.

 9.1 First class functions
 9.2 Lambda functions
 9.3 Lazy arguments

9.1 First class functions

urbiscript has first class functions, i.e., functions are regular values, just like integers or strings. They can be stored in variables, passed as arguments to other functions, and so forth. For instance, you don’t need to write function object.f(){/* ... */} to insert a function in an object, you can simply use setSlot.

 
var o = Object.clone()|; 
// Here we can use f as any regular value. 
o.setSlotValue("m1"function () { echo("Hello") })|; 
// This is strictly equivalent/ 
var o.m2 = function () { echo("Hello") }|; 
o.m1(); 
[00000000] *** Hello 
o.m2(); 
[00000000] *** Hello  

This enables to write powerful pieces of code, like functions that take function as argument. For instance, consider the all function: given a list and a function, it applies the function to each element of the list, and returns whether all calls returned true. This enables to check very simply if all elements in a list verify a predicate.

 
function all(list, predicate) 

  for (var elt : list) 
    if (!predicate(elt)) 
      return false; 
  return true; 
}|; 
// Check if all elements in a list are positive. 
function positive(x) { x >= 0 }|; 
all([1, 2, 3], getSlotValue("positive")); 
[00000000] true 
all([1, 2, -3], getSlotValue("positive")); 
[00000000] false  

It turns out that all already exists: instead of all(listpredicate), use list.all(predicate), see RangeIterable.all.

9.2 Lambda functions

Another nice feature is the ability to write lambda functions, which are anonymous functions. You can create a functional value as an expression, without naming it, with the syntax shown below.

 
// Create an anonymous function 
function (x) {x + 1}|; 
// This enable to easily pass function 
// to our "all" function: 
[1, 2, 3].all(function (x) { x > 0}); 
[00000000] true  

In fact, the function construct we saw earlier is only a shorthand for a variable assignment.

 
// This ... 
function obj.f (/*...*/) {/*...*/}; 
// ... is actually a shorthand for: 
const var obj.f = function (/*...*/) {/* ... */};  

9.3 Lazy arguments

Most popular programming languages use strict arguments evaluation: arguments are evaluated before functions are called. Other languages use lazy evaluation: argument are evaluated by the function only when needed. In urbiscript, evaluation is strict by default, but you can ask a function not to evaluate its arguments, and do it by hand. This works by not specifying formal arguments. The function is provided with a call object that enables you to evaluate arguments.

 
// Note the lack of formal arguments specification 
function first 

  // Evaluate only the first argument. 
  call.evalArgAt(0); 
}|; 
first(echo("first"), echo("second")); 
[00000000] *** first 
function reverse 

  call.evalArgAt(1); 
  call.evalArgAt(0); 
}|; 
reverse(echo("first"), echo("second")); 
[00000000] *** second 
[00000000] *** first  

A good example are logic operators. Although C++ is a strict language, it uses a few logic operators. For instance, the logical and (&&) does not evaluate its right operand if the left operand is false (the result will be false anyway).

urbiscript logic operator mimic this behavior. The listing below shows how one can implement such a behavior.

 
function myAnd 

  if (call.evalArgAt(0)) 
    call.evalArgAt(1) 
  else 
    false; 
}|; 
 
function f() 

  echo("f executed"); 
  return true; 
}|; 
 
myAnd(false, f()); 
[00000000] false 
 
myAnd(true, f()); 
[00000000] *** f executed 
[00000000] true