This section expects that you already know how to run urbi. If not, please first see Listing 2.
This section introduces the most basic notions to write urbiscript code. Some aspects are presented only minimally. The goal of this section is to bootstrap yourself with the urbiscript language, to be able to study more in-depth examples afterward.
Commenting your code is crucial, so let’s start by learning how to do this in urbiscript. Comments are ignored by the interpreter, and can be left as documentation, reminder, …urbiscript supports C and C++ style comments:
1; // This is a C++ style comment.
[00000000] 1
2 + /* This is a C-style comment. */ 2;
[00000000] 4
"foo" /* You /* can /* nest */ */ comments. */ "bar";
[00000000] "foobar"
Listing 2 introduced some of the conventions used in this document: frames such as the previous one denote “urbiscript sessions”, i.e., dialogs between Urbi and you. The output is prefixed by a number between square brackets: this is the date (in milliseconds since the server was launched) at which that line was sent by the server. This is useful at occasions, since Urbi is meant to run many parallel commands. Since these timestamps are irrelevant in documentation, they will often be filled with zeroes. More details about the typesetting of this document (and the other kinds of frames) can be found in Listing 28.
Several special kinds of “values” can be entered directly with a specific syntax. They are called literals, or sometimes manifest values. We just met a first kind of literals: integers. There are several others, such as:
These examples highlight some points:
You can call functions with the classical, mathematical notation.
Math.cos(0); // Compute cosine
[00000000] 1
Math.max(1, 3); // Get the maximum of the arguments.
[00000000] 3
Math.max(1, 3, 4, 2);
[00000000] 4
Again, the result of the evaluation are printed out. You can see here that function in urbiscript can be variadic, that is, take different number of arguments, such as the max function. Let’s now try the echo function, that prints out its argument.
The server prints out Hello world!, as expected. Note that this output is still prepended with the time stamp. Since echo returns void, no evaluation result is printed.
Variables can be introduced with the var keyword, given a name and an initial value. They can be assigned new values with the = operator.
Note that, just as in C++, assignments return the (right-hand side) value, so you can write code like “x = y = 0”. The rule for valid identifiers is also the same as in C++: they may contain alphanumeric characters and underscores, but they may not start with a digit.
You may omit the initialization value, in which case it defaults to void.
var y;
y;
// Remember, the interpreter remains silent because void is printed out
// as nothing. You can convince yourself that y is actually void with
// the following methods.
y.asString;
[00000000] "void"
y.isVoid;
[00000000] true
Scopes are introduced with curly brackets ({}). They can contain any number of statements. Variables declared in a scope only exist within this scope.
{
var x = "test";
echo(x);
};
[00000000] *** test
// x is no longer defined here
x;
[00000073:error] !!! lookup failed: x
Note that the interpreter waits for the whole scope to be input to evaluate it. Also note the mandatory terminating semicolon after the closing curly bracket.
Methods are called on objects with the dot (.) notation as in C++. Method calls can be chained. Methods with no arguments don’t require the parentheses.
0.cos();
[00000000] 1
"a-b-c".split("-");
[00000000] ["a", "b", "c"]
"foo".length();
[00000000] 3
// Method call can be chained
"".length().cos();
[00000000] 1
In obj.method, we say that obj is the target, and that we are sending him the method message.
You know how to call routines, let’s learn how to write some. Functions can be declared thanks to the function keyword, followed by the comma separated, parentheses surrounded list of formal arguments, and the body between curly brackets.
// Define myFunction
function myFunction()
{
echo("Hello world");
echo("from my function!");
};
[00000000] function () {
echo("Hello world");
echo("from my function!");
}
// Invoke it
myFunction();
[00000000] *** Hello world
[00000000] *** from my function!
Note the strange output after you defined the function. urbiscript seems to be printing the function you just typed in again. This is because a function definition evaluates to the freshly created function.
Functions are first class citizen: they are values, just as 0 or "foobar". The evaluation of a function definition yields the new function, and as always, the interpreter prints out the evaluation result, thus showing you the function again:
// Work in a scope.
{
// Define f
function f()
{
echo("f")
};
// This does not invoke f, it returns its value.
f;
};
[00000000] function () { echo("f") }
{
// Define f
function f()
{
echo("Hello World");
};
// This actually calls f
f();
};
[00000000] *** Hello World
Here you can see that f is actually a simple value. You can just evaluate it to see its value, that is, its body. By adding the parentheses, you can actually call the function. This is a difference with methods calling, where empty parentheses are optional: method are always evaluated, you cannot retrieve their functional value — of course, you can with a different construct, but that’s not the point here.
Since this output is often irrelevant, most of the time it is hidden in this documentation using the |; trick. When a statement is “missing”, an empty statement ({}) is inserted. So code|; is actually equivalent to code | {};, which means “run code, then run {} and return its value”. Since the value of {} is void, which is not displayed, this is a means to discard the result of a computation, and avoid that something is printed. Contrast the two following function definitions.
function sum(a, b, c)
{
return a + b + c;
};
[00003553] function (var a, var b, var c) { return a.’+’(b).’+’(c) }
function sum2(a, b, c)
{
return a + b + c;
}|;
sum(20, 2, 20);
[00003556] 42
The return keyword breaks the control flow of a function (similarly to the way break interrupts a loop) and returns the control flow to the caller. It accepts an optional argument, the value to return to the caller.
In urbiscript, if no return statement is executed, the value of the last expression is returned. Actually, refrained from using return when you don’t need it, it is both less readable (once you get used to this programming style), and less efficient (Listing 15.1.2).
You’re now up and running with basic urbiscript code, and we can dive in details into advanced urbiscript code.