23.1 Barrier
Barrier is used to wait until another job raises a signal. This can be used to implement blocking calls
waiting until a resource is available.
A Barrier can be created with no argument. Calls to signal and wait done on this instance are
restricted to this instance.
Barrier.new;
[00000000] Barrier_0x25d2280
- signal(payload)
Wake up one of the job waiting for a signal. The payload is sent to the wait method.
Return the number of jobs woken up.
do (Barrier.new)
{
echo(wait) &
echo(wait) &
assert
{
signal(1) == 1;
signal(2) == 1;
}
}|;
[00000000] *** 1
[00000000] *** 2
- signalAll(payload)
Wake up all the jobs waiting for a signal. The payload is sent to all wait methods. Return the
number of jobs woken up.
do (Barrier.new)
{
echo(wait) &
echo(wait) &
assert
{
signalAll(1) == 2;
signalAll(2) == 0;
}
}|;
[00000000] *** 1
[00000000] *** 1
- wait
Block until a signal is received. The payload sent with the signal function is returned by the
wait method.
do (Barrier.new)
{
echo(wait) &
signal(1)
}|;
[00000000] *** 1
23.2 Binary
A Binary object, sometimes called a blob, is raw memory, decorated with a user defined
header.
Binaries are usually not made by users, but they are heavily used by the internal machinery when
exchanging Binary UValues. A binary features some content and some keywords, both simple
Strings.
Binary.new("my header", "my content");
[00000001] BIN 10 my header
my content
Beware that the third line above (‘my content’), was output by the system, although not preceded
by a timestamp.
23.3 Boolean
There is no object Boolean in urbiscript, but two specific objects true and false. They are the
result of all the comparison statements.
The objects true and false have the following prototype.
There are no constructors, use true and false. Since they are singletons, clone will return
themselves, not new copies.
true;
!false;
2 < 6 === true;
true.new === true;
6 < 2 === false;
As in many programming languages, conditions may be more than only true and false. Whether
some value is considered as true depends on the type of this. Actually, by default objects as
considered “true”, objects evaluating to “false” are the exception:
- false, nil
false.
- raise an error.
- false iff null (Float).
- Dictionary, List, String
false iff empty (Dictionary, List, String).
- otherwise
true.
The method Object.asBool is in charge of converting some arbitrary value into a Boolean.
assert(Global.asBool == true);
assert(nil.asBool == false);
void.asBool;
[00000421:error] !!! unexpected void
- ’!’
Logical negation. If this is false return true and vice-versa.
!true == false;
!false == true;
- asBool
Identity.
true.asBool == true;
false.asBool == false;
23.4 CallMessage
Capturing a method invocation: its target and arguments.
The following example implements a lazy function which takes an integer n, then arguments. The n-th
argument is evaluated twice using evalArgAt.
function callTwice
{
var n = call.evalArgAt(0);
call.evalArgAt(n);
call.evalArgAt(n)
} |;
// Call twice echo("foo").
callTwice(1, echo("foo"), echo("bar"));
[00000001] *** foo
[00000002] *** foo
// Call twice echo("bar").
callTwice(2, echo("foo"), echo("bar"));
[00000003] *** bar
[00000004] *** bar
Strict functions do support call.
function strict(x)
{
echo("Entering");
echo("Strict: " + x);
echo("Lazy: " + call.evalArgAt(0));
} |;
strict({echo("1"); 1});
[00000011] *** 1
[00000013] *** Entering
[00000012] *** Strict: 1
[00000013] *** 1
[00000014] *** Lazy: 1
- args
The list of not yet evaluated arguments.
function args { call.args }|
assert
{
args == [];
args() == [];
args({echo(111); 1}) == [Lazy.new(closure() {echo(111); 1})];
args(1, 2) == [Lazy.new(closure () {1}),
Lazy.new(closure () {2})];
};
- argsCount
The number of arguments. Do not evaluate them.
function argsCount { call.argsCount }|;
assert
{
argsCount == 0;
argsCount() == 0;
argsCount({echo(1); 1}) == 1;
argsCount({echo(1); 1}, {echo(2); 2}) == 2;
};
- code
The body of the called function as a Code.
function code { call.getSlot("code") }|
assert (code == getSlot("code"));
- eval
Evaluate this, and return the result.
var c1 = do (CallMessage.new)
{
var this.target = 1;
var this.message = "+";
var this.args = [Lazy.new(function () {2})];
}|
assert { c1.eval == 3 };
// A lazy function that returns the sum of this and the second argument,
// regardless of the first argument.
function Float.addSecond
{
this + call.evalArgAt(1);
}|
var c2 = do (CallMessage.new)
{
var this.target = 2;
var this.message = "addSecond";
var this.args = [Lazy.new(function (){ assert (false) }),
Lazy.new(function (){ echo (5); 5 })];
}|
assert { c2.eval == 7 };
[00000454] *** 5
- evalArgAt(n)
Evaluate the n-th argument, and return its value. n must evaluate to an non-negative integer.
Repeated invocations repeat the evaluation, see Section 23.4.1.1.
function sumTwice
{
var n = call.evalArgAt(0);
call.evalArgAt(n) + call.evalArgAt(n)
}|;
function one () { echo("one"); 1 }|;
sumTwice(1, one, one + one);
[00000008] *** one
[00000009] *** one
[00000010] 2
sumTwice(2, one, one + one);
[00000011] *** one
[00000012] *** one
[00000011] *** one
[00000012] *** one
[00000013] 4
sumTwice(3, one, one);
[00000014:error] !!! evalArgAt: invalid index: 3
[00000014:error] !!! called from: sumTwice
sumTwice(3.14, one, one);
[00000015:error] !!! evalArgAt: invalid index: 3.14
[00000015:error] !!! called from: sumTwice
- evalArgs
Call evalArgAt for each argument, return the list of values.
function twice
{
call.evalArgs + call.evalArgs
}|;
twice({echo(1); 1}, {echo(2); 2});
[00000011] *** 1
[00000012] *** 2
[00000011] *** 1
[00000012] *** 2
[00000013] [1, 2, 1, 2]
- message
The name under which the function was called.
function myself { call.message }|
assert(myself == "myself");
- sender
The object from which the invocation was made (the caller in other languages). Not to be
confused with target.
function Global.getSender { call.sender } |
function Global.callGetSender { getSender } |
assert
{
// Call from the current Lobby, with the Lobby as target.
getSender === lobby;
// Call from the current Lobby, with Global as the target.
Global.getSender === lobby;
// Ask Lobby to call getSender.
callGetSender === lobby;
// Ask Global to call getSender.
Global.callGetSender === Global;
};
- target
The object on which the invocation is made. In other words, the object that will be bound to
this during the evaluation. Not to be confused with sender.
function Global.getTarget { call.target } |
function Global.callGetTarget { getTarget } |
assert
{
// Call from the current Lobby, with the Lobby as target.
getTarget === lobby;
// Call from the current Lobby, with Global as the target.
Global.getTarget === Global;
// Ask Lobby to call getTarget.
callGetTarget === lobby;
// Ask Global to call getTarget.
Global.callGetTarget === Global;
};
23.5 Channel
Returning data, typically asynchronous, with a label so that the “caller” can find it in the
flow.
Channels are created like any other object. The constructor must be called with a string which will be
the label.
var ch1 = Channel.new("my_label");
[00000201] Channel_0x7985810
ch1 << 1;
[00000201:my_label] 1
var ch2 = ch1;
[00000201] Channel_0x7985810
ch2 << 1/2;
[00000201:my_label] 0.5
23.6 Code
Functions written in urbiscript.
The keywords function and closure build Code instances.
function(){}.protos[0] === &Code;
closure (){}.protos[0] === &Code;
- Whether this and that are the same source code (actually checks that both have the
same asString), and same closed values.
Closures and functions are different, even if the body is the same.
function () { 1 } == function () { 1 };
function () { 1 } != closure () { 1 };
closure () { 1 } != function () { 1 };
closure () { 1 } == closure () { 1 };
No form of equivalence is applied on the body, it must be the same.
function () { 1 + 1 } == function () { 1 + 1 };
function () { 1 + 2 } != function () { 2 + 1 };
Arguments do matter, even if in practice the functions are the same.
function (var ignored) {} != function () {};
function (var x) { x } != function (y) { y };
A lazy function cannot be equal to a strict one.
function () { 1 } != function { 1 };
If the functions capture different variables, they are different.
{
var x;
function Global.capture_x() { x };
function Global.capture_x_again () { x };
{
var x;
function Global.capture_another_x() { x };
}
}|;
assert
{
&capture_x == &capture_x_again;
&capture_x != &capture_another_x;
};
If the functions capture different targets, they are different.
class Foo
{
function makeFunction() { function () {} };
function makeClosure() { closure () {} };
}|;
class Bar
{
function makeFunction() { function () {} };
function makeClosure() { closure () {} };
}|;
assert
{
Foo.makeFunction() == Bar.makeFunction();
Foo.makeClosure() != Bar.makeClosure();
};
- apply(args)
Invoke the routine, with all the arguments. The target, this, will be set to args[0] and the
remaining arguments with be given as arguments.
function (x, y) { x+y }.apply([nil, 10, 20]) == 30;
function () { this }.apply([123]) == 123;
// There is Object.apply.
1.apply([this]) == 1;
function () {}.apply([]);
[00000001:error] !!! apply: argument list must begin with ‘this’
function () {}.apply([1, 2]);
[00000002:error] !!! apply: expected 0 argument, given 1
- asString
Conversion to String.
closure () { 1 }.asString == "closure () { 1 }";
function () { 1 }.asString == "function () { 1 }";
- bodyString
Conversion to String of the routine body.
closure () { 1 }.bodyString == "1";
function () { 1 }.bodyString == "1";
23.7 Comparable
Objects that can be compared for equality and inequality. See also Orderable.
This object, made to serve as prototype, provides a definition of != based on ==. Object provides a
default implementation of == that bounces on the physical equality ===.
class Foo : Comparable
{
var value = 0;
function init (v) { value = v; };
function ’==’ (that) { value == that.value; };
}|;
assert
{
Foo.new(1) == Foo.new(1);
Foo.new(1) != Foo.new(2);
};
- Whether ! (this != that).
class FortyTwo : Comparable
{
function ’!=’ (that) { 42 != that };
}|;
assert
{
FortyTwo != 51;
FortyTwo == 42;
};
- !=’(\var{that})Whether ! (this == that).
class FiftyOne : Comparable
{
function ’==’ (that) { 51 == that };
}|;
assert
{
FiftyOne == 51;
FiftyOne != 42;
};
23.8 Container
This object is meant to be used as a prototype for objects that support has and hasNot methods.
Any class using this prototype must redefine either has, hasNot or both.
- has(e)
!hasNot(e). The indented semantics is “true when the container has a key (or item)
matching e”. This is what e in c is mapped onto.
class NotCell : Container
{
var val;
function init(var v) { val = v };
function hasNot(var v) { val != v };
}|;
var c = NotCell.new(23)|;
assert
{
c.has(23); 23 in c;
c.hasNot(3); 3 not in c;
};
- hasNot(e)
!has(e). The indented semantics is “true when the container does not have a key (or item)
matching e”.
class Cell : Container
{
var val;
function init(var v) { val = v };
function has(var v) { val == v };
}|;
var d = Cell.new(23)|;
assert
{
d.has(23); 23 in d;
d.hasNot(3); 3 not in d;
};
23.9 Control
Control is designed as a namespace for control sequences. Some of these entities are used by the
Urbi engine to execute some urbiscript features; in other words, users are not expected to you use it,
much less change it.
23.10 Date
This class is meant to record dates in time, with microsecond resolution.
This feature is experimental. It might be changed in the future. Feedback on its use
would be appreciated.
Without argument, newly constructed Dates refer to the current date.
Date.new;
[00000001] 2010-08-17 14:40:52.549726
With a string argument d, refers to the date contained in d. The string should be formatted as
‘yyyy-mm-dd hh:mn:ss ’ (see asString). mn and ss are optional. If the block ‘hh:mn:ss ’ is absent, the
behavior is undefined.
Date.new("2003-10-10 20:10:50:637");
[00000001] 2003-10-10 20:10:50.637000
Date.new("2003-10-10 20:10:50");
[00000001] 2003-10-10 20:10:50.000000
Date.new("2003-Oct-10 20:10");
[00000002] 2003-10-10 20:10:00.000000
Date.new("2003-10-10 20");
[00000003] 2003-10-10 20:00:00.000000
Pay attention that the format is rather strict; for instance too many spaces between day and time
result in an error.
Date.new("2003-10-10 20:10:50");
[00001968:error] !!! new: cannot convert to date: 2003-10-10 20:10:50
Pay attention that the format is not strict enough either; for instance, below, the ‘.’ separator seem
to prefix microseconds, but actually merely denotes the minutes. Seconds must be spelled out in order
to introduce microseconds.
Date.new("2003-10-10 00.12");
[00000003] 2003-10-10 00:12:00.000000
Date.new("2003-10-10 00:00.12");
[00000003] 2003-10-10 00:00:12.000000
23.11 Dictionary
A dictionary is an associative array, also known as a hash in some programming languages. They
are arrays whose indexes are arbitrary objects.
The following session demonstrates the features of the Dictionary objects.
var d = ["one" => 1, "two" => 2];
[00000001] ["one" => 1, "two" => 2]
for (var p : d)
echo (p.first + " => " + p.second);
[00000003] *** one => 1
[00000002] *** two => 2
"three" in d;
[00000004] false
d["three"];
[00000005:error] !!! missing key: three
d["three"] = d["one"] + d["two"] | {};
"three" in d;
[00000006] true
d.getWithDefault("four", 4);
[00000007] 4
Arbitrary objects can be used as dictionary keys. To map to the same cell, two objects used as keys
must have equal hashes (retrieved with the Object.hash method) and be equal to each other (in the
Object.’==’ sense).
This means that two different objects may have the same hash: the equality operator
(Object.’==’) is checked in addition to the hash, to handle such collision. However a good hash
algorithm should avoid this case, since it hinders performances.
See Object.hash for more detail on how to override hash values. Most standard value-based
classes implement a reasonable hash function: see Float.hash, String.hash, List.hash,
…
The Dictionary constructor takes arguments by pair (key, value).
Dictionary.new("one", 1, "two", 2);
[00000000] ["one" => 1, "two" => 2]
Dictionary.new;
[00000000] [ => ]
There must be an even number of arguments.
Dictionary.new("1", 2, "3");
[00000001:error] !!! new: odd number of arguments
You are encouraged to use the specific syntax for Dictionary literals:
["one" => 1, "two" => 2];
[00000000] ["one" => 1, "two" => 2]
[=>];
[00000000] [ => ]
An extra comma can be added at the end of the list.
[
"one" => 1,
"two" => 2,
];
[00000000] ["one" => 1, "two" => 2]
It is guaranteed that the pairs to insert are evaluated left-to-write, key first, the value.
["a".fresh => "b".fresh, "c".fresh => "d".fresh]
== ["a_5" => "b_6", "c_7" => "d_8"];
- ’==’(that)
Whether this equals that. This suppose that elements contained inside the dictionary are
Comparable.
[ => ] == [ => ];
["a" => 1, "b" => 2] == ["b" => 2, "a" => 1];
- ’[]’(key)
Syntactic sugar for get(key).
assert (["one" => 1]["one"] == 1);
["one" => 1]["two"];
[00000012:error] !!! missing key: two
- ’[]=’(key, value)
Syntactic sugar for set(key, value), but returns value.
{
var d = ["one" =>"2"];
assert
{
(d["one"] = 1) == 1;
d["one"] == 1;
};
};
- asBool
Negation of empty.
[=>].asBool == false;
["key" => "value"].asBool == true;
- asList
The contents of the dictionary as a Pair list (key, value).
["one" => 1, "two" => 2].asList == [("one", 1), ("two", 2)];
Since Dictionary derives from RangeIterable, it is easy to iterate over a Dictionary using a
range-for (Section 22.7.5.2). No particular order is ensured.
{
var res = [];
for| (var entry: ["one" => 1, "two" => 2])
res << entry.second;
assert(res == [1, 2]);
};
- asString
A string representing the dictionary. There is no guarantee on the order of the output.
[=>].asString == "[ => ]";
["a" => 1, "b" => 2].asString == "[\"a\" => 1, \"b\" => 2]";
- elementAdded
An event emitted each time a new element is added to the Dictionary.
- elementChanged
An event emitted each time the value associated to a key of the Dictionary is changed.
- elementRemoved
An event emitted each time an element is removed from the Dictionary.
d = [ => ] |;
at(d.elementAdded?) echo ("added");
at(d.elementChanged?) echo ("changed");
at(d.elementRemoved?) echo ("removed");
d["key1"] = "value1";
[00000001] "value1"
[00000001] *** added
d["key2"] = "value2";
[00000001] "value2"
[00000001] *** added
d["key2"] = "value3";
[00000001] "value3"
[00000001] *** changed
d.erase("key2");
[00000002] ["key1" => "value1"]
[00000001] *** removed
d.clear;
[00000003] [ => ]
[00000001] *** removed
d.clear;
[00000003] [ => ]
- clear
Empty the dictionary.
["one" => 1].clear.empty;
- empty
Whether the dictionary is empty.
[=>].empty == true;
["key" => "value"].empty == false;
- erase(key)
Remove the mapping for key.
{
var d = ["one" => 1, "two" => 2];
assert
{
d.erase("two") === d;
d == ["one" => 1];
};
try
{
["one" => 1, "two" => 2].erase("three");
echo("never reached");
}
catch (var e if e.isA(Dictionary.KeyError))
{
assert(e.key == "three")
};
};
- get(key)
The value associated to key. A Dictionary.KeyError exception is thrown if the key is missing.
var d = ["one" => 1, "two" => 2]|;
assert(d.get("one") == 1);
["one" => 1, "two" => 2].get("three");
[00000010:error] !!! missing key: three
try
{
d.get("three");
echo("never reached");
}
catch (var e if e.isA(Dictionary.KeyError))
{
assert(e.key == "three")
};
- getWithDefault(key, defaultValue)
The value associated to key if it exists, defaultValue otherwise.
{
var d = ["one" => 1, "two" => 2];
assert
{
d.getWithDefault("one", -1) == 1;
d.getWithDefault("three", 3) == 3;
};
}|;
- has(key)
Whether the dictionary has a mapping for key.
{
var d = ["one" => 1];
assert
{
d.has("one");
!d.has("zero");
};
}|;
The infix operators in and not in use has (see Section 22.1.8.7).
"one" in ["one" => 1];
"two" not in ["one" => 1];
- init(key1, value1, ...)
Insert the mapping from key1 to value1 and so forth.
Dictionary.clone.init("one", 1, "two", 2);
[00000000] ["one" => 1, "two" => 2]
- keys
The list of all the keys. No particular order is ensured. Since List features the same function,
uniform iteration over a List or a Dictionary is possible.
{
var d = ["one" => 1, "two" => 2];
assert(d.keys == ["one", "two"]);
assert({
var res = [];
for (var k: d.keys)
res << d[k];
res
}
== [1, 2]);
};
- matchAgainst(handler, pattern)
Pattern matching on members. See Pattern.
{
// Match a subset of the dictionary.
["a" => var a] = ["a" => 1, "b" => 2];
// get the matched value.
assert(a == 1);
};
- set(key, value)
Map key to value and return this so that invocations to set can be chained. The possibly
existing previous mapping is overridden.
[=>].set("one", 2)
.set("two", 2)
.set("one", 1);
[00000000] ["one" => 1, "two" => 2]
- size
Number of element in the dictionary.
{
var d = [=>];
assert(d.size == 0);
d["a"] = 0;
assert(d.size == 1);
d["b"] = 1;
assert(d.size == 2);
d["a"] = 2;
assert(d.size == 2);
};
23.12 Directory
A Directory represents a directory of the file system.
A Directory can be constructed with one argument: the path of the directory using a String or a
Path. It can also be constructed by the method open of Path.
Directory.new(".");
[00000001] Directory(".")
Directory.new(Path.new("."));
[00000002] Directory(".")
- ’/’(str)
This feature is experimental. It might be changed in the future. Feedback on its
use would be appreciated.
The str String is concatenated with the directory path. If the resulting path is
either a directory or a file, ’/’ will returns either a Directory or a File object.
var dir1 = Directory.create("dir1")|;
var dir2 = Directory.create("dir1/dir2")|;
var file = File.create("dir1/file")|;
dir1 / "dir2";
[00000001] Directory("dir1/dir2")
dir1 / "file";
[00000002] File("dir1/file")
dir1.removeAll;
- ’<<’(entity)
This feature is experimental. It might be changed in the future. Feedback on its
use would be appreciated.
If entity is a Directory or a File, ’<<’ copies entity in the this directory. Return this to
allow chained operations.
dir1 = Directory.create("dir1")|;
dir2 = Directory.create("dir2")|;
file = File.create("file")|;
dir1 << file << dir2;
[00000001] Directory("dir1")
dir1.content;
[00000003] ["dir2", "file"]
dir2;
[00000004] Directory("dir2")
file;
[00000005] File("file")
dir1.removeAll;
dir2.removeAll;
file.remove;
- asList
The contents of the directory as a Path list. The various paths include the name of the directory
this.
- asString
A String containing the path of the directory.
Directory.new(".").asString == ".";
- asPath
A Path being the path of the directory.
- content
The contents of the directory as a String list. The strings include only the last component name;
they do not contain the directory name of this.
- copy(dirname)
Copy recursively all items of the this directory into the directory dirname after creating it.
dir1 = Directory.create("dir1")|;
dir2 = Directory.create("dir1/dir2")|;
file = File.create("dir1/file")|;
var directory1 = dir1.copy("directory1");
[00000001] Directory("directory1")
dir1;
[00000002] Directory("dir1")
directory1.content;
[00000003] ["dir2", "file"]
dir1.removeAll;
directory1.removeAll;
- copyInto(dirname)
This feature is experimental. It might be changed in the future. Feedback on its
use would be appreciated.
Copy this into dirname without creating it.
var dir = Directory.create("dir")|;
dir1 = Directory.create("dir1")|;
dir2 = Directory.create("dir1/dir2")|;
file = File.create("dir1/file")|;
dir1.copyInto(dir);
[00000001] Directory("dir/dir1")
dir1;
[00000002] Directory("dir1")
dir1.content;
[00000003] ["dir2", "file"]
dir.content;
[00000004] ["dir1"]
Directory.new("dir/dir1").content;
[00000005] ["dir2", "file"]
dir.removeAll;
dir1.removeAll;
- clear
Remove all children recursively but not the directory itself. After a call to clear, a call to empty
should return true.
dir1 = Directory.create("dir1")|;
dir2 = Directory.create("dir1/dir2")|;
var file1 = File.create("dir1/file1")|;
var file2 = File.create("dir1/dir2/file2")|;
dir1.content;
[00000001] ["dir2", "file1"]
dir2.content;
[00000002] ["file2"]
dir1.clear;
assert(dir1.empty);
dir1.remove;
- create(name)
Create the directory name where name is either a String or a Path. In addition to
system errors that can occur, errors are raised if directory or file name already exists.
dir = Directory.new("dir");
[00000001:error] !!! new: directory does not exist: "dir"
dir = Directory.create("dir");
[00000002] Directory("dir")
dir = Directory.create("dir");
[00000001:error] !!! create: directory exists: "dir"
dir.content;
[00000003] []
dir.remove;
- createAll(name)
Create the directory name where name is either a String or a Path. If name is a path (or
a String describing a path) no errors are raised if one directory doesn’t exist or
already exists. Instead createAll creates them all as in the Unix ‘make -p’ command.
Directory.create("dir1/dir2/dir3");
[00000001:error] !!! create: no such file or directory: "dir1/dir2/dir3"
dir1 = Directory.create("dir1");
[00000002] Directory("dir1")
Directory.createAll("dir1/dir2/dir3");
[00000002] Directory("dir1/dir2/dir3")
dir1.removeAll;
- empty
Whether the directory is empty.
dir = Directory.create("dir")|;
assert(dir.empty);
File.create("dir/file")|;
assert(!dir.empty);
dir.removeAll;
- exists
Whether the directory still exists.
dir = Directory.create("dir");
[00000001] Directory("dir")
assert(dir.exists);
dir.remove;
assert(!dir.exists);
- fileCreated(name)
Event launched when a file is created inside the directory. May not exist if not supported by your
architecture.
if (Path.new("./dummy.txt").exists)
File.new("./dummy.txt").remove;
{
var d = Directory.new(".");
waituntil(d.fileCreated?(var name));
assert
{
name == "dummy.txt";
Path.new(d.asString + "/" + name).exists;
};
}
&
{
sleep(100ms);
File.create("./dummy.txt");
}|;
- fileDeleted(name)
Event launched when a file is deleted from the directory. May not exist if not supported by your
architecture.
if (!Path.new("./dummy.txt").exists)
File.create("./dummy.txt")|;
{
var d = Directory.new(".");
waituntil(d.fileDeleted?(var name));
assert
{
name == "dummy.txt";
!Path.new(d.asString + "/" + name).exists;
};
}
&
{
sleep(100ms);
File.new("./dummy.txt").remove;
}|;
- basename
Return a String containing the path of the directory without its dirname.
var dir1 = Directory.create("dir1");
[00000001] Directory("dir1")
var dir2 = Directory.create("dir1/dir2");
[00000002] Directory("dir1/dir2")
dir1.basename;
[00000002] "dir1"
dir2.basename;
[00000003] "dir2"
dir1.removeAll;
- lastModifiedDate
This feature is experimental. It might be changed in the future. Feedback on its
use would be appreciated.
Return a Date object stating when the directory was last modified.
- moveInto(dirname)
This feature is experimental. It might be changed in the future. Feedback on its
use would be appreciated.
Move this into dirname without creating it.
dir1 = Directory.create("dir1")|;
dir2 = Directory.create("dir1/dir2")|;
var file = File.create("dir1/file")|;
var dir = Directory.create("dir")|;
dir1.moveInto(dir);
[00000001] Directory("dir/dir1")
dir1;
[00000002] Directory("dir/dir1")
dir1.content;
[00000003] ["dir2", "file"]
dir.content;
[00000004] ["dir1"]
dir.removeAll;
- parent
Return the parent of the directory.
Directory.create("dir")|;
dir = Directory.create("dir/dir")|;
dir.parent;
[00000001] Directory("dir")
assert(dir.parent.parent.asString == Directory.current.asString);
dir.parent.removeAll;
- remove
Remove the directory only if it is empty.
dir = Directory.create("dir")|;
File.create("dir/file")|;
dir.remove;
[00000001:error] !!! remove: directory not empty: "dir"
dir.clear;
dir.remove;
assert(!dir.exists);
- removeAll
Remove all children recursively including the directory itself.
dir1 = Directory.create("dir1")|;
dir2 = Directory.create("dir1/dir2")|;
var file1 = File.create("dir1/file1")|;
var file2 = File.create("dir1/dir2/file2")|;
dir1.removeAll;
assert(!dir1.exists);
- rename
Rename or move the directory.
dir = Directory.create("dir")|;
File.create("dir/file")|;
dir.rename("other");
[00000001] Directory("other")
dir;
[00000002] Directory("other")
dir.content;
[00000003] ["file"]
dir2 = Directory.create("dir2")|;
dir.rename("dir2/other2");
[00000004] Directory("dir2/other2")
dir;
[00000005] Directory("dir2/other2")
dir.content;
[00000006] ["file"]
dir2.removeAll;
- size
This feature is experimental. It might be changed in the future. Feedback on its
use would be appreciated.
The size of all the directory content computed recursively.
dir = Directory.create("dir")|;
Directory.create("dir/dir")|;
File.save("dir/file", "content");
file1 = File.create("dir/file")|;
File.save("dir/dir/file", "content");
file2 = File.create("dir/dir/file")|;
assert(dir.size() == file1.size() + file2.size());
23.13 Duration
This class records differences between Dates.
This feature is experimental. It might be changed in the future. Feedback on its use
would be appreciated.
Without argument, a null duration.
Duration.new;
[00000001] Duration(0s)
Duration.new(1h);
[00023593] Duration(3600s)
Durations can be negative.
Duration.new(-1);
[00000001] Duration(-1s)
- asFloat
Return the duration as a Float.
Duration.new(1000).asFloat == 1000;
Duration.new(1000.1234).asFloat == 1000.1234;
- asString
Return the duration as a String.
Duration.new(1000).asString == "1000s";
- seconds
Return the duration as a Float.
Duration.new(1000) .seconds == 1000;
Duration.new(1000.52).seconds == 1000.52;
23.14 Enumeration
Prototype of enumeration types.
See Section 22.5.
An Enumeration is created with two arguments: the name of the enumeration type, and the list of
possible values. Most of the time, it is a good idea to store it in a variable with the same
name.
var Direction = Enumeration.new("Direction", ["up", "down", "left", "right"]);
[00000001] Direction
Direction.up;
[00000002] up
The following syntax is equivalent.
enum Direction
{
up,
down,
left,
right
};
[00000001] Direction
The created values are derive from the created enumeration type.
Direction.isA(Enumeration);
Direction.up.isA(Direction);
23.15 Event
An event can be “emitted” and “caught”, or “sent” and “received”. See also Section 14.2.
There are several examples of uses of events in the documentation of event-based constructs.
See at (Listing 22.10.1), waituntil (Listing 22.10.6), whenever (Listing 22.10.7), and so
forth. The tutorial chapter about event-based programming contains other examples, see
Listing 14.
An Event is created like any other object, without arguments.
var e = Event.new;
[00000001] Event_0x9ad8118
23.16 Exception
Exceptions are used to handle errors. More generally, they are a means to escape from the normal
control-flow to handle exceptional situations.
The language support for throwing and catching exceptions (using try/catch and throw, see
Section 22.8) work perfectly well with any kind of object, yet it is a good idea to throw only objects
that derive from Exception.
There are several types of exceptions, each of which corresponding to a particular kind of error. The
top-level object, Exception, takes a single argument: an error message.
Exception.new("something bad has happened!");
[00000001] Exception ‘something bad has happened!’
Exception.Arity.new("myRoutine", 1, 10, 23);
[00000002] Exception.Arity ‘myRoutine: expected between 10 and 23 arguments, given 1’
Exception has many slots which are specific exceptions. See Section 23.16.4 for their documentation.
- backtrace
The call stack at the moment the exception was thrown (not created), as a List of
StackFrames, from the innermost to the outermost call. Uses Traceable.backtrace.
//#push 1 "file.u"
try
{
function innermost () { throw Exception.new("Ouch") };
function inner () { innermost() };
function outer () { inner() };
function outermost () { outer() };
outermost();
}
catch (var e)
{
assert
{
e.backtrace[0].location.asString == "file.u:4.27-37";
e.backtrace[0].name == "innermost";
e.backtrace[1].location.asString == "file.u:5.27-33";
e.backtrace[1].name == "inner";
e.backtrace[2].location.asString == "file.u:6.27-33";
e.backtrace[2].name == "outer";
e.backtrace[3].location.asString == "file.u:8.3-13";
e.backtrace[3].name == "outermost";
};
};
//#pop
- location
The location from which the exception was thrown (not created).
eval("1/0");
[00090441:error] !!! 1.1-3: /: division by 0
[00090441:error] !!! called from: eval
try
{
eval("1/0");
}
catch (var e)
{
assert (e.location.asString == "1.1-3");
};
- message
The error message provided at construction.
Exception.new("Ouch").message == "Ouch";
In the following, since these slots are actually Objects, what is presented as arguments to the slots
are actually arguments to pass to the constructor of the corresponding exception type.
- Argument(routine, index, exception)
During the call of routine, the instantiation of the index-nth argument has thrown an
exception.
Exception.Argument
.new("myRoutine", 3, Exception.Type.new("19/11/2010", Date))
.asString
== "myRoutine: argument 3: unexpected \"19/11/2010\", expected a Date";
- ArgumentType(routine, index, effective, expected)
Deprecated exception that derives from Type. The routine was called with a index-nth
argument of type effective instead of expected.
Exception.ArgumentType
.new("myRoutine", 1, "hisResult", "Expectation")
.asString
== "myRoutine: argument 1: unexpected \"hisResult\", expected a String";
[00000003:warning] !!! ‘Exception.ArgumentType’ is deprecated
- Arity(routine, effective, min, max = void)
The routine was called with an incorrect number of arguments (effective). It requires at least
min arguments, and, if specified, at most max.
Exception.Arity.new("myRoutine", 1, 10, 23).asString
== "myRoutine: expected between 10 and 23 arguments, given 1";
- BadInteger(routine, fmt, effective)
The routine was called with an inappropriate integer (effective). Use the format fmt to
create an error message from effective. Derives from BadNumber.
Exception.BadInteger.new("myRoutine", "bad integer: %s", 12).asString
== "myRoutine: bad integer: 12";
- BadNumber(routine, fmt, effective)
The routine was called with an inappropriate number (effective). Use the format fmt to
create an error message from effective.
Exception.BadNumber.new("myRoutine", "bad number: %s", 12.34).asString
== "myRoutine: bad number: 12.34";
- Constness
An attempt was made to change a constant value.
Exception.Constness.new.asString
== "cannot modify const slot";
- FileNotFound(name)
The file named name cannot be found.
Exception.FileNotFound.new("foo").asString
== "file not found: foo";
- ImplicitTagComponent(msg)
An attempt was made to create an implicit tag, a component of which being undefined.
Exception.ImplicitTagComponent.new.asString
== "invalid component in implicit tag";
- Lookup(object, name)
A failed name lookup was performed on object to find a slot named name. Suggest what the user
might have meant if Exception.Lookup.fixSpelling is true (which is the default).
Exception.Lookup.new(Object, "GetSlot").asString
== "lookup failed: Object";
- MatchFailure
A pattern matching failed.
Exception.MatchFailure.new.asString
== "pattern did not match";
- NegativeNumber(routine, effective)
The routine was called with a negative number (effective). Derives from BadNumber.
Exception.NegativeNumber.new("myRoutine", -12).asString
== "myRoutine: unexpected -12, expected non-negative number";
- NonPositiveNumber(routine, effective)
The routine was called with a non-positive number (effective). Derives from BadNumber.
Exception.NonPositiveNumber.new("myRoutine", -12).asString
== "myRoutine: unexpected -12, expected positive number";
- Primitive(routine, msg)
The built-in routine encountered an error described by msg.
Exception.Primitive.new("myRoutine", "cannot do that").asString
== "myRoutine: cannot do that";
- Redefinition(name)
An attempt was made to refine a slot named name.
Exception.Redefinition.new("foo").asString
== "slot redefinition: foo";
- Scheduling(msg)
Something really bad has happened with the Urbi task scheduler.
Exception.Scheduling.new("cannot schedule").asString
== "cannot schedule";
- Syntax(loc, message, input)
Declare a syntax error in input, at location loc, described by message. loc is the location of
the syntax error, location is the place the error was thrown. They are usually equal, except
when the errors are caught while using System.eval or System.load. In that case loc is really
the position of the syntax error, while location refers to the location of the System.eval or
System.load invocation.
Exception.Syntax
.new(Location.new(Position.new("file.u", 14, 25)),
"unexpected pouCharque", "file.u")
.asString
== "file.u:14.25: syntax error: unexpected pouCharque";
try
{
eval("1 / / 0");
}
catch (var e)
{
assert
{
e.isA(Exception.Syntax);
e.loc.asString == "1.5";
e.input == "1 / / 0";
e.message == "unexpected /";
}
};
- Type(effective, expected)
A value of type effective was received, while a value of type expected was expected.
Exception.Type.new("hisResult", "Expectation").asString
== "unexpected \"hisResult\", expected a String";
- UnexpectedVoid
An attempt was made to read the value of void.
Exception.UnexpectedVoid.new.asString
== "unexpected void";
var a = void;
a;
[00000016:error] !!! unexpected void
[00000017:error] !!! lookup failed: a
23.17 Executable
This class is used only as a common ancestor to Primitive and Code.
There is no point in constructing an Executable.
- asExecutable
Return this.
23.18 File
Files may be created from a String, or from a Path. Using new, the file must exist on the file system,
and must be a file. You may use create to create a file that does not exist (or to override an existing
one).
File.create("file.txt");
[00000001] File("file.txt")
File.new(Path.new("file.txt"));
[00000001] File("file.txt")
You may use InputStream and OutputStream to read or write to Files.
- asList
Read the file, and return its content as a list of its lines.
File.save("file.txt", "1\n2\n");
assert(File.new("file.txt").asList == ["1", "2"]);
- asPath
A Path being the path of the file.
- asPrintable
File.save("file.txt", "1\n2\n");
assert(File.new("file.txt").asPrintable == "File(\"file.txt\")");
- asString
The name of the opened file.
File.save("file.txt", "1\n2\n");
assert(File.new("file.txt").asString == "file.txt");
- basename
Return a String containing the path of the file without its dirname.
- content
The content of the file as a Binary object.
File.save("file.txt", "1\n2\n");
assert
{
File.new("file.txt").content == Binary.new("", "1\n2\n");
};
- copy(filename)
Copy the file to a new file named filename.
File.save("file", "content");
var file = File.new("file");
[00000001] File("file")
var file2 = file.copy("file2");
[00000002] File("file2")
assert(file2.content == file.content);
file.remove;
file2.remove;
- copyInto(dirname)
This feature is experimental. It might be changed in the future. Feedback on its
use would be appreciated.
Copy file into dirname directory.
var dir = Directory.create("dir")|;
file = File.create("file")|;
file.copyInto(dir);
[00000001] File("dir/file")
file;
[00000002] File("file")
dir.content;
[00000003] ["file"]
dir.removeAll;
file.remove;
- create(name)
If the file name does not exist, create it and a return a File to it. Otherwise, first empty it. See
OutputStream for methods to add content to the file.
var p = Path.new("create.txt") |
assert (!p.exists);
// Create the file, and put something in it.
var f = File.create(p)|;
var o = OutputStream.new(f)|;
o << "Hello, World!"|;
o.close;
assert
{
// The file exists, with the expect contents.
p.exists;
f.content.data == "Hello, World!";
// If we create is again, it is empty.
File.create(p).isA(File);
f.content.data == "";
};
- lastModifiedDate
This feature is experimental. It might be changed in the future. Feedback on its
use would be appreciated.
Return a Date object stating when the file was last modified.
- moveInto(dirname)
This feature is experimental. It might be changed in the future. Feedback on its
use would be appreciated.
Move file into dirname directory.
dir = Directory.create("dir")|;
file = File.create("file")|;
file.moveInto(dir);
[00000001] File("dir/file")
file;
[00000001] File("dir/file")
dir.content;
[00000001] ["file"]
dir.removeAll;
- remove
Remove the current file. Returns void.
var p = Path.new("foo.txt") |
p.exists;
[00000002] false
var f = File.create(p);
[00000003] File("foo.txt")
p.exists;
[00000004] true
f.remove;
p.exists;
[00000006] false
- rename(name)
Rename the file to name. If the target exists, it is replaced by the opened file. Return the file
renamed.
File.save("file.txt", "1\n2\n");
File.new("file.txt").rename("bar.txt");
[00000001] File("bar.txt")
assert
{
!Path.new("file.txt").exists;
File.new("bar.txt").content.data == "1\n2\n";
};
- save(name, content)
Use create to create the File named name, store the content in it, and close the file. Return
void.
File.save("file.txt", "1\n2\n").isVoid;
File.new("file.txt").content.data == "1\n2\n";
- size
The size of the file.
File.save("file.txt", "1234");
File.new("file.txt").size;
[00000001] 4
23.19 Finalizable
Objects that derive from this object will execute their finalize routine right before being
destroyed (reclaimed) by the system. It is comparable to a destructor.
The following object is set up to die verbosely.
var obj =
do (Finalizable.new)
{
function finalize ()
{
echo ("Ouch");
}
}|;
It is reclaimed by the system when it is no longer referenced by any other object.
var alias = obj|;
obj = nil|;
Here, the object is still alive, since alias references it. Once it no longer does, the object
dies.
alias = nil|;
[00000004] *** Ouch
The constructor takes no argument.
Finalizable.new;
[00000527] Finalizable_0x135360
Because of specific constraints of Finalizable, you cannot change the prototype of an object to
make it “finalizable”: it must be an instance of Finalizable from its inception.
There, instead of these two invalid constructs,
class o1 : Finalizable.new
{
function finalize()
{
echo("Ouch");
}
}|;
[00000008:error] !!! apply: cannot inherit from a Finalizable without being one
class o2
{
protos = [Finalizable];
function finalize()
{
echo("Ouch");
}
}|;
[00000010:error] !!! updateSlot: cannot inherit from a Finalizable without being one
write:
var o3 =
do (Finalizable.new)
{
function finalize()
{
echo("Ouch");
}
}|;
If you need multiple prototypes, do as follows.
class Global.Foo
{
function init()
{
echo("1");
};
}|;
class Global.FinalizableFoo
{
addProto(Foo.new);
function ’new’()
{
var r = clone |
r.init |
Finalizable.new.addProto(r);
};
function init()
{
echo("2");
};
function finalize()
{
echo("3");
};
}|;
var i = FinalizableFoo.new|;
[00000117] *** 1
[00000117] *** 2
i = nil;
[00000117] *** 3
- finalize
a simple function that takes no argument that will be evaluated when the object is reclaimed. Its
return value is ignored.
Finalizable.new.setSlot("finalize", function() { echo("Ouch") })|;
[00033240] *** Ouch
23.20 Float
A Float is a floating point number. It is also used, in the current version of urbiscript, to represent
integers.
The most common way to create fresh floats is using the literal syntax. Numbers are composed of three
parts:
-
integral
- (mandatory) a non empty sequence of (decimal) digits;
-
fractional
- (optional) a period, and a non empty sequence of (decimal) digits;
-
exponent
- (optional) either ‘e’ or ‘E’, an optional sign (‘+’ or ‘-’), then a non-empty sequence
of digits.
In other words, float literals match the [0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)? regular
expression. For instance:
0 == 0000.0000;
// This is actually a call to the unary ’+’.
+1 == 1;
0.123456 == 123456 / 1000000;
1e3 == 1000;
1e-3 == 0.001;
1.234e3 == 1234;
There are also some special numbers, nan, inf (see below).
Math.log(0) == -inf;
Math.exp(-inf) == 0;
(inf/inf).isNan;
A null float can also be obtained with Float’s new method.
- abs
Absolute value of the target.
(-5).abs == 5;
0 .abs == 0;
5 .abs == 5;
- acos
Arccosine of the target.
0.acos == Float.pi/2;
1.acos == 0;
- asBool
Whether non null.
0.asBool == false;
0.1.asBool == true;
(-0.1).asBool == true;
inf.asBool == true;
nan.asBool == true;
- asFloat
Return the target.
- asList
Bounces to seq.
3.asList == [0, 1, 2];
0.asList == [];
- asin
Arcsine of the target.
- asString
Return a string representing the target.
42.asString == "42";
42.51.asString == "42.51";
21474836470.asString == "21474836470";
4611686018427387904.asString == "4611686018427387904";
(-4611686018427387904).asString == "-4611686018427387904";
- atan
Return the arctangent of the target.
0.atan == 0;
1.atan == Float.pi/4;
- ’bitand’(that)
The bitwise-and between this and that.
- ’bitor’(that)
Bitwise-or between this and that.
- ceil
The smallest integral value greater than or equal to. See also floor and round.
0.ceil == 0;
1.4.ceil == 2; 1.5.ceil == 2; 1.6.ceil == 2;
(-1.4).ceil == -1; (-1.5).ceil == -1; (-1.6).ceil == -1;
inf.ceil == inf; (-inf).ceil == -inf;
nan.ceil.isNan;
- clone
Return a fresh Float with the same value as the target.
var x = 0;
[00000000] 0
var y = x.clone;
[00000000] 0
x === y;
[00000000] false
- compl
The complement to 1 of the target interpreted as a 32 bits integer.
compl 0 == 4294967295;
compl 4294967295 == 0;
- cos
Cosine of the target.
0.cos == 1;
Float.pi.cos == -1;
- each(fun)
Call the functional argument fun on every integer from 0 to target - 1, sequentially. The number
must be non-negative.
{
var res = [];
3.each(function (i) { res << 100 + i });
res
}
== [100, 101, 102];
{
var res = [];
for(var x : 3) { res << x; sleep(20ms); res << (100 + x); };
res
}
== [0, 100, 1, 101, 2, 102];
{
var res = [];
0.each (function (i) { res << 100 + i });
res
}
== [];
- ’each|’(fun)Call the functional argument fun on every integer from 0 to target - 1, with tight
sequentiality. The number must be non-negative.
{
var res = [];
3.’each|’(function (i) { res << 100 + i });
res
}
== [100, 101, 102];
{
var res = [];
for|(var x : 3) { res << x; sleep(20ms); res << (100 + x); };
res
}
== [0, 100, 1, 101, 2, 102];
- ’each&’(fun)
Call the functional argument fun on every integer from 0 to target - 1, concurrently. The number
must be non-negative.
{
var res = [];
for& (var x : 3) { res << x; sleep(30ms); res << (100 + x) };
res
}
== [0, 1, 2, 100, 101, 102];
- exp
Exponential of the target.
1.exp;
[00000000] 2.71828
- floor
the largest integral value less than or equal to this. See also ceil and round.
0.floor == 0;
1.4.floor == 1; 1.5.floor == 1; 1.6.floor == 1;
(-1.4).floor == -2; (-1.5).floor == -2; (-1.6).floor == -2;
inf.floor == inf; (-inf).floor == -inf;
nan.floor.isNan;
- format(finfo)
Format according to the FormatInfo object finfo. The precision, finfo.precision, sets the
maximum number of digits after decimal point when in fixed or scientific mode, and in total
when in default mode. Beware that 0 plays a special role, as it is not a “significant”
digit.
Windows Issues
Under Windows the behavior differs slightly.
"%1.0d" % 0.1 == "0.1";
"%1.0d" % 1.1 == {if (System.Platform.isWindows) "1.1" else "1"};
"%1.0f" % 0.1 == "0";
"%1.0f" % 1.1 == "1";
Conversion to hexadecimal requires this to be integral.
"%x" % 42 == "2a";
"%x" % 0xFFFF == "ffff";
"%x" % 0.5;
[00000005:error] !!! %: expected integer, got 0.5
- fresh
Return a new integer at each call.
{
var res = [];
for (var i: 10)
res << Float.fresh;
assert (res == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
res = [];
for (var i: 10)
res << Float.fresh;
assert (res == [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]);
};
- hash
Return a Hash object corresponding to this float value. Two float hashes are equal if the float are
equal. See Object.hash.
0.hash.isA(Hash);
0.hash == 0.hash;
0.hash != 1.hash;
- hex
A String with the conversion of this in hexadecimal. Requires this to be integral.
0.hex == "0";
0xFF.hex == "ff";
0xFFFF.hex == "ffff";
65535.hex == "ffff";
0xffffffff.hex == "ffffffff";
0.5.hex;
[00000005:error] !!! format: expected integer, got 0.5
- inf
Return the infinity.
Float.inf;
[00000000] inf
- isInf
Whether is infinite.
!0.isInf; !1.isInf; !(-1).isInf;
!nan.isInf;
inf.isInf; (-inf).isInf;
- isNan
Whether is NaN.
!0.isNan; !1.isNan; !(-1).isNan;
!inf.isNan; !(-inf).isNan;
nan.isNan;
- limits
See Float.limits.
- log
The logarithm of the target.
0.log == -inf;
1.log == 0;
1.exp.log == 1;
- max(arg1, ...)
Bounces to List.max on [this, arg1, ...].
1.max == 1;
1.max(2, 3) == 3;
3.max(1, 2) == 3;
- min(arg1, ...)
Bounces to List.min on [this, arg1, ...].
1.min == 1;
1.min(2, 3) == 1;
3.min(1, 2) == 1;
- nan
The “not a number” special float value. More precisely, this returns the “quiet NaN”, i.e., it is
propagated in the various computations, it does not raise exceptions.
Float.nan;
[00000000] nan
(Float.nan + Float.nan) / (Float.nan - Float.nan);
[00000000] nan
A NaN has one distinctive property over the other Floats: it is equal to no other
float, not even itself. This behavior is mandated by the IEEE 754-2008 standard.
{ var n = Float.nan; n === n};
{ var n = Float.nan; n != n};
- pi
π.
Float.pi.cos ** 2 + Float.pi.sin ** 2 == 1;
- random
A random integer between 0 (included) and the target (excluded).
20.map(function (dummy) { 5.random });
[00000000] [1, 2, 1, 3, 2, 3, 2, 2, 4, 4, 4, 1, 0, 0, 0, 3, 2, 4, 3, 2]
- round
The integral value nearest to this rounding half-way cases away from zero. See also ceil and
floor.
0.round == 0;
1.4.round == 1; 1.5.round == 2; 1.6.round == 2;
(-1.4).round == -1; (-1.5).round == -2; (-1.6).round == -2;
inf.round == inf; (-inf).round == -inf;
nan.round.isNan;
- seq
The sequence of integers from 0 to this- 1 as a list. The number must be non-negative.
3.seq == [0, 1, 2];
0.seq == [];
- sign
Return 1 if this is positive, 0 if it is null, -1 otherwise.
(-1164).sign == -1;
0.sign == 0;
(1164).sign == 1;
- sin
The sine of the target.
- sqr
Square of the target.
32.sqr == 1024;
32.sqr == 32 ** 2;
- sqrt
The square root of the target.
1024.sqrt == 32;
1024.sqrt == 1024 ** 0.5;
- srandom
Initialized the seed used by the random function. As opposed to common usage, you should not
use
{
var now = Date.now.timestamp;
now.srandom;
var list1 = 20.map(function (dummy) { 5.random });
now.srandom;
var list2 = 20.map(function (dummy) { 5.random });
assert
{
list1 == list2;
}
};
- tan
Tangent of the target.
assert(0.tan == 0);
(Float.pi/4).tan;
[00000000] 1
- times(fun)
Call the functional argument fun this times.
3.times(function () { echo("ping") });
[00000000] *** ping
[00000000] *** ping
[00000000] *** ping
- trunc
Return the target truncated.
1.9.trunc == 1;
(-1.9).trunc == -1;
- ’^’(that)
Bitwise exclusive or between this and that.
- ’>>’(that)
this shifted by that bits towards the right.
- ’<’(that)
Whether this is less than that. The other comparison operators (<=, >, …) can thus also be
applied on floats since Float inherits Orderable.
0 < 1;
!(1 < 0);
!(0 < 0);
- ’<<’(that)
this shifted by that bit towards the left.
- ’-’(that)
this subtracted by that.
- ’+’(that)
The sum of this and that.
- ’/’(that)
The quotient of this divided by that.
50 / 10 == 5;
10 / 50 == 0.2;
- ’%’(that)
this modulo that.
- ’*’(that)
Product of this by that.
- ’**’(that)
this to the that power (thisthat).
2 ** 10 == 1024;
2 ** 31 == 2147483648;
-2 ** 31 == -2147483648; // This is -(2**31).
2 ** 32 == 4294967296;
-2 ** 32 == -4294967296; // This is -(2**32).
- ’==’(that)
Whether this equals that.
23.21 Float.limits
This singleton handles various limits related to the Float objects.
- digits
Number of digits (in radix base) in the mantissa.
- digits10
Number of digits (in decimal base) that can be represented without change.
- epsilon
Machine epsilon (the difference between 1 and the least value greater than 1 that is
representable).
1 != 1 + Float.limits.epsilon;
1 == 1 + Float.limits.epsilon / 2;
- max
Maximum finite value.
Float.limits.max != Float.inf;
Float.limits.max * 2 == Float.inf;
- maxExponent
Maximum integer value for the exponent that generates a normalized floating-point number.
Float.inf != Float.limits.radix ** (Float.limits.maxExponent - 1);
Float.inf == Float.limits.radix ** Float.limits.maxExponent;
- maxExponent10
Maximum integer value such that 10 raised to that power generates a normalized finite
floating-point number.
Float.inf != 10 ** Float.limits.maxExponent10;
Float.inf == 10 ** (Float.limits.maxExponent10 + 1);
- min
Minimum positive normalized value.
- minExponent
Minimum negative integer value for the exponent that generates a normalized floating-point
number.
0 != Float.limits.radix ** Float.limits.minExponent;
- minExponent10
Minimum negative integer value such that 10 raised to that power generates a normalized
floating-point number.
0 != 10 ** Float.limits.minExponent10;
- radix
Base of the exponent of the representation.
23.22 FormatInfo
A format info is used when formatting a la printf. It store the formatting pattern itself and all
the format information it can extract from the pattern.
The constructor expects a string as argument, whose syntax is similar to printf’s. It is detailed
below.
var f = FormatInfo.new("%+2.3d");
[00000001] %+2.3d
A formatting pattern must one of the following (brackets denote optional arguments):
- %options spec
- %|options[spec]|
options is a sequence of 0 or several of the following characters:
|
|
| ‘-’ | Left alignment. |
| ‘=’ | Centered alignment. |
| ‘+’ | Show sign even for positive number. |
| ‘ ’ | If the string does not begin with ‘+’ or ‘-’, insert a space before the converted string. |
| ‘0’ | Pad with 0’s (inserted after sign or base indicator). |
| ‘#’ | Show numerical base, and decimal point. |
|
|
| |
spec is the conversion character and must be one of the following:
|
|
| ‘s’ | Default character, prints normally |
| ‘d’ | Case modifier: lowercase |
| ‘D’ | Case modifier: uppercase |
| ‘x’ | Prints in hexadecimal lowercase |
| ‘X’ | Prints in hexadecimal uppercase |
| ‘o’ | Prints in octal |
| ‘e’ | Prints floats in scientific format |
| ‘E’ | Prints floats in scientific format uppercase |
| ‘f’ | Prints floats in fixed format |
|
|
| |
- alignment
Requested alignment: -1 for left, 0 for centered, 1 for right (default).
FormatInfo.new("%s").alignment == 1;
FormatInfo.new("%=s").alignment == 0;
FormatInfo.new("%-s").alignment == -1;
- alt
Whether the “alternative” display is requested (‘#’).
FormatInfo.new("%s").alt == false;
FormatInfo.new("%#s").alt == true;
- group
Separator to use for thousands. Corresponds to the ‘’’ option.
FormatInfo.new("%s").group == "";
FormatInfo.new("%’s").group == " ";
- pad
The padding character to use for alignment requests. Defaults to space.
FormatInfo.new("%s").pad == " ";
FormatInfo.new("%0s").pad == "0";
- pattern
The pattern given to the constructor.
FormatInfo.new("%#’12.8s").pattern == "%#’12.8s";
- precision
When formatting a Float, the maximum number of digits after decimal point when in fixed or
scientific mode, and in total when in default mode. When formatting other objects with
spec-char ‘s’, the conversion string is truncated to the precision first chars. The eventual padding
to width is done after truncation.
FormatInfo.new("%s").precision == 6;
FormatInfo.new("%23.3s").precision == 3;
- prefix
The string to display before positive numbers. Defaults to empty.
FormatInfo.new("%s").prefix == "";
FormatInfo.new("% s").prefix == " ";
FormatInfo.new("%+s").prefix == "+";
- spec
The specification character, regardless of the case conversion requests.
FormatInfo.new("%s").spec == "s";
FormatInfo.new("%23.3s").spec == "s";
FormatInfo.new("%’X").spec == "x";
- uppercase
Case conversion: -1 for lower case, 0 for no conversion (default), 1 for conversion to uppercase.
The value depends on the case of specification character, except for ‘%s’ which corresponds to 0.
FormatInfo.new("%s").uppercase == 0;
FormatInfo.new("%d").uppercase == -1;
FormatInfo.new("%D").uppercase == 1;
FormatInfo.new("%x").uppercase == -1;
FormatInfo.new("%X").uppercase == 1;
- width
Width requested for alignment.
FormatInfo.new("%s").width == 0;
FormatInfo.new("%10s").width == 10;
23.23 Formatter
A formatter stores format information of a format string like used in printf in the C library or in
boost::format.
Formatters are created with the format string. It cuts the string to separate regular parts of string and
formatting patterns, and stores them.
Formatter.new("Name:%s, Surname:%s;");
[00000001] Formatter ["Name:", %s, ", Surname:", %s, ";"]
Actually, formatting patterns are translated into FormatInfo.
- asList
Return the content of the formatter as a list of strings and FormatInfo.
Formatter.new("Name:%s, Surname:%s;").asList.asString
== "[\"Name:\", %s, \", Surname:\", %s, \";\"]";
-
- ’%’(args)
Use this as format string and args as the list of arguments, and return the result (a String).
The arity of the Formatter (i.e., the number of expected arguments) and the size of args must
match exactly.
This operator concatenates regular strings and the strings that are result of asString called on
members of args with the appropriate FormatInfo.
Formatter.new("Name:%s, Surname:%s;") % ["Foo", "Bar"]
== "Name:Foo, Surname:Bar;";
If args is not a List, then the call is equivalent to calling ’%’([args]).
Formatter.new("%06.3f") % Math.pi
== "03.142";
Note that String.’%’ provides a nicer interface to this operator:
"%06.3f" % Math.pi == "03.142";
It is nevertheless interesting to use the Formatter for performance reasons if the format is reused
many times.
{
// Some large database of people.
var people =
[["Foo", "Bar" ],
["One", "Two" ],
["Un", "Deux"],];
var f = Formatter.new("Name:%7s, Surname:%7s;");
for (var p: people)
echo (f % p);
};
[00031939] *** Name: Foo, Surname: Bar;
[00031940] *** Name: One, Surname: Two;
[00031941] *** Name: Un, Surname: Deux;
23.24 Global
Global is designed for the purpose of being global namespace. Since Global is a prototype of Object
and all objects are an Object, all slots of Global are accessible from anywhere.
23.25 Group
A transparent means to send messages to several objects as if they were one.
The following session demonstrates the features of the Group objects. It first creates the Sample family
of object, makes a group of such object, and uses that group.
class Sample
{
var value = 0;
function init(v) { value = v; };
function asString() { "<" + value.asString + ">"; };
function timesTen() { new(value * 10); };
function plusTwo() { new(value + 2); };
};
[00000000] <0>
var group = Group.new(Sample.new(1), Sample.new(2));
[00000000] Group [<1>, <2>]
group << Sample.new(3);
[00000000] Group [<1>, <2>, <3>]
group.timesTen.plusTwo;
[00000000] Group [<12>, <22>, <32>]
// Bouncing getSlot and updateSlot.
group.value;
[00000000] Group [1, 2, 3]
group.value = 10;
[00000000] Group [10, 10, 10]
// Bouncing to each&.
var sum = 0|
for& (var v : group)
sum += v.value;
sum;
[00000000] 30
Groups are created like any other object. The constructor can take members to add to the
group.
Group.new;
[00000000] Group []
Group.new(1, "two");
[00000000] Group [1, "two"]
- add(member, ...)
Add members to this group, and return this.
- asString
Report the members.
- each(action)
Apply action to all the members, in sequence, then return the Group of the results, in
the same order. Allows to iterate over a Group via for.
- each&(action)
Apply action to all the members, concurrently, then return the Group of the results. The
order is not necessarily the same. Allows to iterate over a Group via for&.
- fallback
This function is called when a method call on this failed. It bounces the call to the
members of the group, collects the results returned as a group. This allows to chain grouped
operation in a row. If the dispatched calls return void, returns a single void, not a “group
of void”.
- getProperty(slot, prop)
Bounced to the members so that this.slot->prop actually collects the values of the
property prop of the slots slot of the group members.
- hasProperty(name)
Bounced to the members.
- hasSlot(name)
True if and only if all the members have the slot.
var g = Group.new(1, 2);
[00000000] Group [1, 2]
g.hasSlot("foo");
[00000000] false
g.hasSlot("+");
[00000000] true
g + 1;
[00000000] Group [2, 3]
- remove(member, ...)
Remove members from this group, and return this.
- setProperty(slot, prop, value)
Bounced to the members so that this.slot->prop = value actually updates the value of the
property prop in the slots slot of the group members.
- updateSlot(name, value)
Bounced to the members so that this.name = value actually updates the value of the slot name
in the group members.
- ’<<’(member)
Syntactic sugar for add.
23.26 Hash
A hash is a condensed, easily comparable representation of another value. They are mainly used to
map Dictionary keys to values.
Equal objects must always have the same hash. Different objects should, as much as possible, have
different hashes.
Objects can be hashed with Object.hash.
Object.new.hash.isA(Hash);
- asFloat
A Float value equivalent to the Hash object. Two hashes have the same Float representation if
and only if they are equal.
var h1 = Object.new.hash|;
var h2 = Object.new.hash|;
assert
{
h1.asFloat == h1.asFloat;
h1.asFloat != h2.asFloat;
};
- combine(that)
Combine that’s hash with this, and return this. This is used to hash composite objects based
on more primitive object hashes. For instance, an object with two slots could be hashed by
hashing its first first, and combining the second in.
class C
{
function init(var a, var b)
{
var this.a = a;
var this.b = b;
};
function hash()
{
this.a.hash().combine(b)
};
}|
assert
{
C.new(0, 0).hash == C.new(0, 0).hash;
C.new(0, 0).hash != C.new(0, 1).hash;
};
23.27 InputStream
InputStreams are used to read (possibly binary) files by hand. File provides means to swallow a
whole file either as a single large string, or a list of lines. InputStream provides a more fine-grained
interface to read files.
Windows Issues
Beware that because of limitations in the current implementation, one cannot safely
read from two different files at the same time under Windows.
An InputStream is a reading-interface to a file, so its constructor requires a File.
File.save("file.txt", "1\n2\n");
var is = InputStream.new(File.new("file.txt"));
[00000001] InputStream_0x827000
Bear in mind that open streams should be closed (Section 23.61.2).
- get
Get the next available byte as a Float, or void if the end of file was reached. Raise an error if
the file is closed.
{
File.save("file.txt", "1\n2\n");
var i = InputStream.new(File.new("file.txt"));
var x;
while (!(x = i.get.acceptVoid).isVoid)
cout << x;
i.close;
i.get;
};
[00000001:output] 49
[00000002:output] 10
[00000003:output] 50
[00000004:output] 10
[00000005:error] !!! get: stream is closed
- getChar
Get the next available byte as a String, or void if the end of file was reached. Raise an error if
the file is closed.
{
File.save("file.txt", "1\n2\n");
var i = InputStream.new(File.new("file.txt"));
var x;
while (!(x = i.getChar.acceptVoid).isVoid)
cout << x;
i.close;
i.getChar;
};
[00000001:output] "1"
[00000002:output] "\n"
[00000003:output] "2"
[00000004:output] "\n"
[00000005:error] !!! getChar: stream is closed
- getLine
Get the next available line as a String, or void if the end of file was reached. The end-of-line
characters are trimmed. Raise an error if the file is closed.
{
File.save("file.txt", "1\n2\n");
var i = InputStream.new(File.new("file.txt"));
var x;
while (!(x = i.getLine.acceptVoid).isVoid)
cout << x;
i.close;
i.getLine;
};
[00000001:output] "1"
[00000002:output] "2"
[00000005:error] !!! getLine: stream is closed
23.28 IoService
A IoService is used to manage the various operations of a set of Socket.
All Socket and Server are by default using the default IoService which is polled regularly by the
system.
Using a different IoService is required if you need to perform synchronous read operations.
The Socket must be created by the IoService that will handle it using its makeSocket
function.
var io = IoService.new|;
var s = io.makeSocket|;
You can then use this socket like any other.
// Make a simple hello server.
var serverPort = 0|
do(Server.new)
{
listen("127.0.0.1", "0");
lobby.serverPort = port;
at(connection?(var s))
{
s.write("hello");
}
}|;
// Connect to it using our socket.
s.connect("0.0.0.0", serverPort);
at(s.received?(var data))
echo("received something");
s.write("1;");
... except that nothing will be read from the socket unless you call one of the poll functions of
io.
sleep(200ms);
s.isConnected(); // Nothing was received yet
[00000001] true
io.poll();
[00000002] *** received something
sleep(200ms);
A IoService is constructed with no argument.
- makeServer
Create and return a new Server using this IoService.
- makeSocket
Create and return a new Socket using this IoService.
- poll
Handle all pending socket operations(read, write, accept) that can be performed without
waiting.
- pollFor(duration)
Will block for duration seconds, and handle all ready socket operations during this period.
- pollOneFor(duration)
Will block for at most duration, and handle the first ready socket operation and
immediately return.
23.29 Job
Jobs are independent threads of executions. Jobs can run concurrently. They can also be managed
using Tags.
A Job is typically constructed via Control.detach, Control.disown, or System.spawn.
detach(sleep(10));
[00202654] Job<shell_4>
disown(sleep(10));
[00204195] Job<shell_5>
spawn (function () { sleep(10) }, false);
[00274160] Job<shell_6>
- asJob
Return this.
- asString
The string Job<name> where name is the name of the job.
- backtrace
The current backtrace of the job as a list of StackFrames. Uses Traceable.backtrace.
//#push 1 "file.u"
var s = detach(sleep(10))|;
// Leave some time for s to be started.
sleep(1);
assert
{
s.backtrace[0].asString == "file.u:1.16-24: sleep";
s.backtrace[1].asString == "file.u:1.16-24: detach";
};
//#pop
- clone
Cloning a job is impossible since Job is considered as being an atom.
- dumpState
Pretty-print the state of the job.
//#push 1 "file.u"
var t = detach(sleep(10))|;
// Leave some time for s to be started.
sleep(1);
t.dumpState;
[00004295] *** Job: shell_10
[00004295] *** State: sleeping
[00004295] *** Tags:
[00004295] *** Tag<Lobby_1>
[00004297] *** Backtrace:
[00004297] *** file.u:1.16-24: sleep
[00004297] *** file.u:1.16-24: detach
//#pop
- name
The name of the job.
detach(sleep(10)).name;
[00004297] "shell_5"
- setSideEffectFree(value)
If value is true, mark the current job as side-effect free. It indicates whether the current state
may influence other parts of the system. This is used by the scheduler to choose whether other
jobs need scheduling or not. The default value is false.
- status
The current status of the job (starting, running, …), and its properties (frozen, …).
- tags
The list of Tags that manage this job.
- terminate
Kill this job.
var r = detach({ sleep(1s); echo("done") })|;
assert (r in jobs);
r.terminate;
assert (r not in jobs);
sleep(2s);
- timeShift
Get the total amount of time during which we were frozen.
tag: r = detach({ sleep(3); echo("done") })|;
tag.freeze();
sleep(2);
tag.unfreeze();
Math.round(r.timeShift);
[00000001] 2
- waitForChanges
Resume the scheduler, putting the current Job in a waiting status. The scheduler may reschedule
the job immediately.
- waitForTermination
Wait for the job to terminate before resuming execution of the current one. If the job has already
terminated, return immediately.
23.30 Kernel1
This object plays the role of a name-space in which obsolete functions from urbiscript
1.0 are provided for backward compatibility. Do not use these functions, scheduled for
removal.
Since it is a Singleton, you are not expected to build other instances.
- commands
Ignored for backward compatibility.
- connections
Ignored for backward compatibility.
- copy(binary)
Obsolete syntax for binary.copy, see Binary.
// copy.
var a = BIN 10;0123456789
[00000001] BIN 10
0123456789
var b = Kernel1.copy(a);
[00000003:warning] !!! ‘copy(binary)’ is deprecated, use ‘binary.copy’
[00000004] BIN 10
0123456789
echo (b);
[00000005] *** BIN 10
0123456789
- devices
Ignored for backward compatibility.
- events
Ignored for backward compatibility.
- functions
Ignored for backward compatibility.
- isvoid(obj)
Obsolete syntax for obj.isVoid, see Object.
- noop
Do nothing. Use {} instead.
- ping
Return time verbosely, see System.
Kernel1.ping;
[00000421] *** pong time=0.12s
- reset
Ignored for backward compatibility.
- runningcommands
Ignored for backward compatibility.
- seq(number)
Obsolete syntax for number.seq, see Float.
- size(list)
Obsolete syntax for list.size, see List.
Kernel1.size([1, 2, 3]) == [1, 2, 3].size;
[00000002:warning] !!! ‘size(list)’ is deprecated, use ‘list.size’
- strict
Ignored for backward compatibility.
- strlen(string)
Obsolete syntax for string.length, see String.
Kernel1.strlen("123") == "123".length;
[00000002:warning] !!! ‘strlen(string)’ is deprecated, use ‘string.length’
- taglist
Ignored for backward compatibility.
- undefall
Ignored for backward compatibility.
- unstrict
Ignored for backward compatibility.
- uservars
Ignored for backward compatibility.
- vars
Ignored for backward compatibility.
23.31 Lazy
Lazies are objects that hold a lazy value, that is, a not yet evaluated value. They provide facilities
to evaluate their content only once (memoization) or several times. Lazy are essentially used in call
messages, to represent lazy arguments, as described in Section 23.4.
One usage of lazy values is to avoid evaluating an expression unless it’s actually needed, because it’s
expensive or has undesired side effects. The listing below presents a situation where an
expensive-to-compute value (heavy_computation) might be needed zero, one or two times. The
objective is to save time by:
- Not evaluating it if it’s not needed.
- Evaluating it only once if it’s needed once or twice.
We thus make the wanted expression lazy, and use the value method to fetch its value when
needed.
// This function supposedly performs expensive computations.
function heavy_computation()
{
echo("Heavy computation");
return 1 + 1;
}|;
// We want to do the heavy computations only if needed,
// and make it a lazy value to be able to evaluate it "on demand".
var v = Lazy.new(closure () { heavy_computation() });
[00000000] heavy_computation()
/* some code */;
// So far, the value was not needed, and heavy_computation
// was not evaluated.
/* some code */;
// If the value is needed, heavy_computation is evaluated.
v.value;
[00000000] *** Heavy computation
[00000000] 2
// If the value is needed a second time, heavy_computation
// is not reevaluated.
v.value;
[00000000] 2
Evaluating a lazy several times only makes sense with lazy arguments and call messages. See example
with call messages in Section 23.4.1.1.
Lazy is meant for functions without argument. If you need caching for functions that depend on
arguments, it is straightforward to implement using a Dictionary. In the future urbiscript might
support dictionaries whose indices are not only strings, but in the meanwhile, convert the arguments
into strings, as the following sample object demonstrates.
class UnaryLazy
{
function init(f)
{
results = [ => ];
func = f;
};
function value(p)
{
var sp = p.asString;
if (results.has(sp))
return results[sp];
var res = func(p);
results[sp] = res |
res
};
var results;
var func;
} |
// The function to cache.
var inc = function(x) { echo("incing " + x) | x+1 } |
// The function with cache.
// Use "getSlot" to get the function, not its evaluation.
var p = UnaryLazy.new(getSlot("inc"));
[00062847] UnaryLazy_0x78b750
p.value(1);
[00066758] *** incing 1
[00066759] 2
p.value(1);
[00069058] 2
p.value(2);
[00071558] *** incing 2
[00071559] 3
p.value(2);
[00072762] 3
p.value(1);
[00074562] 2
Lazies are seldom instantiated manually. They are mainly created automatically when a lazy function
call is made (see Section 22.3.4). One can however create a lazy value with the standard new
method of Lazy, giving it an argument-less function which evaluates to the value made
lazy.
Lazy.new(closure () { /* Value to make lazy */ 0 });
[00000000] 0
- Whether this and that are the same source code and value (an not yet evaluated Lazy is never
equal to an evaluated one).
Lazy.new(closure () { 1 + 1 }) == Lazy.new(closure () { 1 + 1 });
Lazy.new(closure () { 1 + 2 }) != Lazy.new(closure () { 2 + 1 });
{
var l1 = Lazy.new(closure () { 1 + 1 });
var l2 = Lazy.new(closure () { 1 + 1 });
assert (l1 == l2);
l1.eval;
assert (l1 != l2);
l2.eval;
assert (l1 == l2);
};
- asString
The conversion to String of the body of a non-evaluated argument.
Lazy.new(closure () { echo(1); 1 }).asString == "echo(1);\n1";
- eval
Force the evaluation of the held lazy value. Two calls to eval will systematically evaluate the
expression twice, which can be useful to duplicate its side effects.
- value
Return the held value, potentially evaluating it before. value performs memoization, that is, only
the first call will actually evaluate the expression, subsequent calls will return the cached value.
Unless you want to explicitly trigger side effects from the expression by evaluating it several time,
this should be preferred over eval to avoid evaluating the expression several times
uselessly.
23.32 List
Lists implement possibly-empty ordered (heterogeneous) collections of objects.
Since lists are RangeIterable, they also support RangeIterable.all and RangeIterable.any.
// Are all elements positive?
! [-2, 0, 2, 4].all(function (e) { 0 < e });
// Are all elements even?
[-2, 0, 2, 4].all(function (e) { e % 2 == 0 });
// Is there any even element?
! [-3, 1, -1].any(function (e) { e % 2 == 0 });
// Is there any positive element?
[-3, 1, -1].any(function (e) { 0 < e });
Lists can be created with their literal syntax: a possibly empty sequence of expressions in square
brackets, separated by commas. Non-empty lists may actually end with a comma.
[]; // The empty list
[00000000] []
[1, "2", [3,],];
[00000000] [1, "2", [3]]
However, new can be used as expected.
List.new;
[00000001] []
[1, 2, 3].new;
[00000002] [1, 2, 3]
- append(that)
Deprecated alias for ’+=’.
var one = [1]|;
one.append(["one", [1]]);
[00000005:warning] !!! ‘list.append(that)’ is deprecated, use ‘list += that’
[00000005] [1, "one", [1]]
- argMax(fun = function(a, b) { a < b })
The index of the (leftmost) “largest” member based on the comparison function fun.
[1].argMax == 0;
[1, 2].argMax == 1;
[1, 2, 2].argMax == 1;
[2, 1].argMax == 0;
[2, -1, 3, -4].argMax == 2;
[2, -1, 3, -4].argMax (function (a, b) { a.abs < b.abs }) == 3;
The list cannot be empty.
[].argMax;
[00000007:error] !!! argMax: list cannot be empty
- argMin(fun = function(a, b) { a < b })
The index of the (leftmost) “smallest” member based on the comparison function fun.
[1].argMin == 0;
[1, 2].argMin == 0;
[1, 2, 1].argMin == 0;
[2, 1].argMin == 1;
[2, -1, 3, -4].argMin == 3;
[2, -1, 3, -4].argMin (function (a, b) { a.abs < b.abs }) == 1;
The list cannot be empty.
[].argMin;
[00000011:error] !!! argMin: list cannot be empty
- asBool
Whether not empty.
[].asBool == false;
[1].asBool == true;
- asList
Return the target.
{
var l = [0, 1, 2];
assert (l.asList === l);
};
- asString
A string describing the list. Uses asPrintable on its members, so that, for instance, strings are
displayed with quotes.
[0, [1], "2"].asString == "[0, [1], \"2\"]";
- back
The last element of the target. An error if the target is empty.
assert([0, 1, 2].back == 2);
[].back;
[00000017:error] !!! back: cannot be applied onto empty list
- clear
Empty the target.
var x = [0, 1, 2];
[00000000] [0, 1, 2]
assert(x.clear == []);
- each(fun)
Apply the given functional value fun on all members, sequentially.
[0, 1, 2].each(function (v) {echo (v * v); echo (v * v)});
[00000000] *** 0
[00000000] *** 0
[00000000] *** 1
[00000000] *** 1
[00000000] *** 4
[00000000] *** 4
- eachi(fun)
Apply the given functional value fun on all members sequentially, additionally passing the
current element index.
["a", "b", "c"].eachi(function (v, i) {echo ("%s: %s" % [i, v])});
[00000000] *** 0: a
[00000000] *** 1: b
[00000000] *** 2: c
- ’each&’(fun)
Apply the given functional value on all members simultaneously.
[0, 1, 2].’each&’(function (v) {echo (v * v); echo (v * v)});
[00000000] *** 0
[00000000] *** 1
[00000000] *** 4
[00000000] *** 0
[00000000] *** 1
[00000000] *** 4
- empty
Whether the target is empty.
- filter(fun)
The list of all the members of the target that verify the predicate fun.
do ([0, 1, 2, 3, 4, 5])
{
assert
{
// Keep only odd numbers.
filter(function (v) {v % 2 == 1}) == [1, 3, 5];
// Keep all.
filter(function (v) { true }) == this;
// Keep none.
filter(function (v) { false }) == [];
};
}|;
- foldl(action, value)
Fold, also known as reduce or accumulate, computes a result from a list. Starting from value as
the initial result, apply repeatedly the binary action to the current result and the next member
of the list, from left to right. For instance, if action were the binary addition and value
were 0, then folding a list would compute the sum of the list, including for empty
lists.
[].foldl(function (a, b) { a + b }, 0) == 0;
[1, 2, 3].foldl(function (a, b) { a + b }, 0) == 6;
[1, 2, 3].foldl(function (a, b) { a - b }, 0) == -6;
- front
Return the first element of the target. An error if the target is empty.
assert([0, 1, 2].front == 0);
[].front;
[00000000:error] !!! front: cannot be applied onto empty list
- has(that)
Whether one of the members of the target equals the argument.
[0, 1, 2].has(1);
! [0, 1, 2].has(5);
The infix operators in and not in use has (see Section 22.1.8.7).
1 in [0, 1];
2 not in [0, 1];
!(2 in [0, 1]);
!(1 not in [0, 1]);
- hash
Return a Hash object corresponding to this list value. Two list hashes are equal if the list have
the same size, and elements hashes are equal two by two. See Object.hash.
[].hash.isA(Hash);
[].hash == [].hash;
[1, "foo"].hash == [1, "foo"].hash;
[0, 1].hash != [1, 0].hash;
- hasSame(that)
Whether one of the members of the target is physically equal to that.
var y = 1|;
assert
{
[0, y, 2].hasSame(y);
![0, y, 2].hasSame(1);
};
- head
Synonym for front.
assert([0, 1, 2].head == 0);
[].head;
[00000000:error] !!! head: cannot be applied onto empty list
- insert(where, what)
Insert what before the value at index where, return this.
{
var l = [0, 1];
assert
{
l.insert(0, 10) === l;
l == [10, 0, 1];
l.insert(2, 20) === l;
l == [10, 0, 20, 1];
};
}|;
The index must be valid, to insert past the end, use insertBack.
[].insert(0, "foo");
[00044239:error] !!! insert: invalid index: 0
[1, 2, 3].insert(4, 30);
[00044339:error] !!! insert: invalid index: 4
- insertBack(that)
Insert the given element at the end of the target, return this.
{
var l = [0, 1];
assert
{
l.insertBack(2) === l;
l == [0, 1, 2];
};
}|;
- insertFront(that)
Insert the given element at the beginning of the target. Return this.
{
var l = [0, 1];
assert
{
l.insertFront(0) === l;
l == [0, 0, 1];
};
}|;
- insertUnique(that)
If that is not in this, append it. Return this.
{
var l = [0, 1];
assert
{
l.insertUnique(0) === l;
l == [0, 1];
l.insertUnique(2) === l;
l == [0, 1, 2];
};
};
- join(sep = "", prefix = "", suffix = "")
Bounce to String.join.
["", "ob", ""].join == "ob";
["", "ob", ""].join("a") == "aoba";
["", "ob", ""].join("a", "B", "b") == "Baobab";
- keys
The list of valid indexes. This allows uniform iteration over a Dictionary or a List.
{
var l = ["a", "b", "c"];
assert
{
l.keys == [0, 1, 2];
{
var res = [];
for (var k: l.keys)
res << l[k];
res
}
== l;
};
};
- map(fun)
Apply the given functional value on every member, and return the list of results.
[0, 1, 2, 3].map(function (v) { v % 2 == 0})
== [true, false, true, false];
- matchAgainst(handler, pattern)
If pattern is a List of same size, use handler to match each member of this against the
corresponding pattern. Return true if the match succeeded, false in other cases.
assert
{
([1, 2] = [1, 2]) == [1, 2];
([1, var a] = [1, 2]) == [1, 2];
a == 2;
([var u, var v, var w] = [1, 2, 3]) == [1, 2, 3];
[u, v, w] == [1, 2, 3];
};
[1, 2] = [2, 1];
[00005863:error] !!! pattern did not match
[1, var a] = [2, 1];
[00005864:error] !!! pattern did not match
[1, var a] = [1];
[00005865:error] !!! pattern did not match
[1, var a] = [1, 2, 3];
[00005865:error] !!! pattern did not match
- max(fun = function(a, b) { a < b })
Return the “largest” member based on the comparison function fun.
[1].max == 1;
[1, 2].max == 2;
[2, 1].max == 2;
[2, -1, 3, -4].max == 3;
[2, -1, 3, -4].max (function (a, b) { a.abs < b.abs }) == -4;
The list cannot be empty.
[].max;
[00000001:error] !!! max: list cannot be empty
The members must be comparable.
[0, 2, "a", 1].max;
[00000002:error] !!! max: argument 2: unexpected "a", expected a Float
- min(fun = function(a, b) { a < b })
Return the “smallest” member based on the comparison function fun.
[1].min == 1;
[1, 2].min == 1;
[2, 1].min == 1;
[2, -1, 3, -4].min == -4;
[2, -1, 3, -4].min (function (a, b) { a.abs < b.abs }) == -1;
The list cannot be empty.
[].min;
[00000001:error] !!! min: list cannot be empty
- range(begin, end = nil)
Return a sub-range of the list, from the first index included to the second index excluded. An
error if out of bounds. Negative indices are valid, and number from the end.
If end is nil, calling range(n) is equivalent to calling range(0, n).
do ([0, 1, 2, 3])
{
assert
{
range(0, 0) == [];
range(0, 1) == [0];
range(1) == [0];
range(1, 3) == [1, 2];
range(-3, -2) == [1];
range(-3, -1) == [1, 2];
range(-3, 0) == [1, 2, 3];
range(-3, 1) == [1, 2, 3, 0];
range(-4, 4) == [0, 1, 2, 3, 0, 1, 2, 3];
};
}|;
[].range(1, 3);
[00428697:error] !!! range: invalid index: 1
- remove(val)
Remove all elements from the target that are equal to val, return this.
var c = [0, 1, 0, 2, 0, 3]|;
assert
{
c.remove(0) === c; c == [1, 2, 3];
c.remove(42) === c; c == [1, 2, 3];
};
- removeBack
Remove and return the last element of the target. An error if the target is empty.
var t = [0, 1, 2];
[00000000] [0, 1, 2]
assert(t.removeBack == 2);
assert(t == [0, 1]);
[].removeBack;
[00000000:error] !!! removeBack: cannot be applied onto empty list
- removeById(that)
Remove all elements from the target that physically equals that.
var d = 1|;
var e = [0, 1, d, 1, 2]|;
assert
{
e.removeById(d) == [0, 1, 1, 2];
e == [0, 1, 1, 2];
};
- removeFront
Remove and return the first element from the target. An error if the target is empty.
var g = [0, 1, 2]|;
assert
{
g.removeFront == 0;
g == [1, 2];
};
[].removeFront;
[00000000:error] !!! removeFront: cannot be applied onto empty list
- reverse
Return the target with the order of elements inverted.
[0, 1, 2].reverse == [2, 1, 0];
- size
Return the number of elements in the target.
[0, 1, 2].size == 3;
[].size == 0;
- sort(fun = function(a, b) { a < b })
A new List with the contents of this, sorted with respect to the comp comparison
function.
{
var l = [3, 0, -2, 1];
assert
{
l.sort == [-2, 0, 1, 3];
l == [3, 0, -2, 1];
l.sort(function(a, b) {a.abs < b.abs})
== [0, 1, -2, 3];
};
};
- subset(that)
Whether the members of this are members of that.
[].subset([]);
[].subset([1, 2, 3]);
[3, 2, 1].subset([1, 2, 3]);
[1, 3].subset([1, 2, 3]);
[1, 1].subset([1, 2, 3]);
![3].subset([]);
![3, 2].subset([1, 2]);
![1, 2, 3].subset([1, 2]);
- tail
Return the target, minus the first element. An error if the target is empty.
assert([0, 1, 2].tail == [1, 2]);
[].tail;
[00000000:error] !!! tail: cannot be applied onto empty list
- zip(fun, other)
Zip this list and the other list with the fun function, and return the list of results.
[1, 2, 3].zip(closure (x, y) { (x, y) }, [4, 5, 6])
== [(1, 4), (2, 5), (3, 6)];
[1, 2, 3].zip(closure (x, y) { x + y }, [4, 5, 6])
== [5, 7, 9];
- ’==’(that)
Check whether all elements in the target and that, are equal two by two.
[0, 1, 2] == [0, 1, 2];
!([0, 1, 2] == [0, 0, 2]);
- ’[]’(n)
Return the nth member of the target (indexing is zero-based). If n is negative, start from the end.
An error if out of bounds.
assert
{
["0", "1", "2"][0] == "0";
["0", "1", "2"][2] == "2";
};
["0", "1", "2"][3];
[00007061:error] !!! []: invalid index: 3
assert
{
["0", "1", "2"][-1] == "2";
["0", "1", "2"][-3] == "0";
};
["0", "1", "2"][-4];
[00007061:error] !!! []: invalid index: -4
- ’[]=’(index, value)
Assign value to the element of the target at the given index.
var f = [0, 1, 2];
[00000000] [0, 1, 2]
assert
{
(f[1] = 42) == 42;
f == [0, 42, 2];
};
for (var i: [0, 1, 2])
f[i] = 10 * f[i];
assert (f == [0, 420, 20]);
- ’*’(n)
Return the target, concatenated n times to itself.
[0, 1] * 0 == [];
[0, 1] * 3 == [0, 1, 0, 1, 0, 1];
n must be a non-negative integer.
[0, 1] * -2;
[00000063:error] !!! *: argument 1: expected non-negative integer, got -2
Note that since it is the very same list which is repeatedly concatenated (the content is not
cloned), side-effects on one item will reflect on “all the items”.
var l = [[]] * 3;
[00000000] [[], [], []]
l[0] << 1;
[00000000] [1]
l;
[00000000] [[1], [1], [1]]
- ’+’(other)
Return the concatenation of the target and the other list.
[0, 1] + [2, 3] == [0, 1, 2, 3];
[] + [2, 3] == [2, 3];
[0, 1] + [] == [0, 1];
[] + [] == [];
The target is left unmodified (contrary to ’+=’).
{
var l = [1, 2, 3];
assert
{
l + l == [1, 2, 3, 1, 2, 3];
l == [1, 2, 3];
};
};
- ’+=’(that)
Concatenate the contents of the List that to this, and return this. This function modifies its
target, contrary to ’+’. See also ’<<’.
{
var l = [];
var alias = l;
assert
{
(l += [1, 2]) == l;
l == [1, 2];
(l += [3, 4]) == l;
l == [1, 2, 3, 4];
alias == [1, 2, 3, 4];
};
};
- ’-’(other)
Return the target without the elements that are equal to any element in the other
list.
[0, 1, 0, 2, 3] - [1, 2] == [0, 0, 3];
[0, 1, 0, 1, 0] - [1, 2] == [0, 0, 0];
- ’<<’(that)
A synonym for insertBack.
- ’<’(other)
Return whether this is less than the other list. This is the lexicographic comparison:
this is “less that” if one of its member is “less than” the corresponding member of
other:
[0, 0, 0] < [0, 0, 1];
[0, 1, 2] < [0, 2, 1];
!([0, 1, 2] < [0, 1, 2]);
!([0, 1, 2] < [0, 0, 2]);
or other is a prefix (strict) of this:
[] < [0]; !( [0] < []);
[0, 1] < [0, 1, 2]; !([0, 1, 2] < [0, 1]);
!([0, 1, 2] < [0, 1, 2]);
Since List derives from Orderable, the other order-based operators are defined.
[] <= [];
[] <= [0, 1, 2];
[0, 1, 2] <= [0, 1, 2];
[] >= [];
[0, 1, 2] >= [];
[0, 1, 2] >= [0, 1, 2];
[0, 1, 2] >= [0, 0, 2];
!([] > []);
[0, 1, 2] > [];
!([0, 1, 2] > [0, 1, 2]);
[0, 1, 2] > [0, 0, 2];
23.33 Loadable
Loadable objects can be switched on and off — typically physical devices.
The intended use is rather as follows:
class Motor: Loadable
{
var val = 0;
function go(var d)
{
if (load)
val += d
else
echo("cannot advance, the motor is off")|;
};
};
[00000002] Motor
var m = Motor.new;
[00000003] Motor_0xADDR
m.load;
[00000004] false
m.go(1);
[00000006] *** cannot advance, the motor is off
m.on;
[00000007] Motor_0xADDR
m.go(123);
m.val;
[00000009] 123
Loadable can be constructed, but it hardly makes sense. This object should serve as a
prototype.
- load
The current status.
- off(val)
Set load to false and return this.
do (Loadable.new)
{
assert
{
!load;
off === this;
!load;
on === this;
load;
off === this;
!load;
};
};
- on(val)
Set load to true and return this.
do (Loadable.new)
{
assert
{
!load;
on === this;
load;
on === this;
load;
};
};
- toggle
Set load from true to false, and vice-versa. Return val.
do (Loadable.new)
{
assert
{
!load;
toggle === this;
load;
toggle === this;
!load;
};
};
23.34 Lobby
A lobby is the local environment for each (remote or local) connection to an Urbi server.
A lobby is implicitly created at each connection. At the top level, this is a Lobby.
this.protos;
[00000001] [Lobby]
this.protos[0].protos;
[00000003] [Channel_0xADDR]
Lobbies cannot be cloned, they must be created using create.
Lobby.new;
[00000177:error] !!! new: ‘Lobby’ objects cannot be cloned
Lobby.create;
[00000174] Lobby_0x126450
Since every lobby is-a Channel, one can use the methods of Channel.
lobby << 123;
[00478679] 123
lobby << "foo";
[00478679] "foo"
- authors
Credit the authors of Urbi SDK. See also thanks and Section 1.4.
lobby.authors;
[00478679] *** Authors of Urbi:
[00478679] *** - Jean-Christophe Baillie (original designer)
[00478679] ***
[00478679] *** Urbi 2 and subsequent versions:
[00478679] *** - Akim Demaille
[00478679] *** - Matthieu Nottale
[00478679] *** - Quentin Hocquet
[00478679] ***
[00478679] *** See also ‘thanks;’.
- banner
Internal. Display Urbi SDK banner.
lobby.banner;
[00006124] *** ********************************************************
[00006124] *** Urbi version 2.7.4 rev. 268868e
[00006124] *** Copyright (C) 2004-2012 Gostai S.A.S.
[00006124] ***
[00006124] *** This program comes with ABSOLUTELY NO WARRANTY. It can
[00006124] *** be used under certain conditions. Type ‘license;’,
[00006124] *** ‘authors;’, or ‘copyright;’ for more information.
[00006124] ***
[00006124] *** Check our community site: http://www.urbiforge.org.
[00006124] *** ********************************************************
- bytesReceived
The number of bytes that were “input” to this. See also receive.
var l = Lobby.create|;
assert (l.bytesReceived == 0);
l.receive("123456789;");
[00000022] 123456789
assert (l.bytesReceived == 10);
l.receive("1234;");
[00000023] 1234
assert (l.bytesReceived == 15);
- bytesSent
The number of bytes that were “output” by this. See also send and write.
var l = Lobby.create|;
assert (l.bytesSent == 0);
l.send("0123456789");
[00011988] 0123456789
// 22 = "[00011988] 0123456789\n".size.
assert (l.bytesSent == 22);
l.send("xx", "label");
[00061783:label] xx
// 20 = "[00061783:label] xx\n".size.
assert (l.bytesSent == 42);
l.write("[01234567]\n");
[01234567]
assert (l.bytesSent == 53);
- connected
Whether this is connected.
- connectionTag
The tag of all code executed in the context of this. This tag applies to this, but the top-level
loop is immune to Tag.stop, therefore connectionTag controls every thing that was launched
from this lobby, yet the lobby itself is still usable.
every (1s) echo(1), sleep(0.5s); every (1s) echo(2),
sleep(1.2s);
connectionTag.stop;
[00000507] *** 1
[00001008] *** 2
[00001507] *** 1
[00002008] *** 2
"We are alive!";
[00002008] "We are alive!"
every (1s) echo(3), sleep(0.5s); every (1s) echo(4),
sleep(1.2s);
connectionTag.stop;
[00003208] *** 3
[00003710] *** 4
[00004208] *** 3
[00004710] *** 4
"and kicking!";
[00002008] "and kicking!"
Of course, a background job may stop a foreground one.
{ sleep(1.2s); connectionTag.stop; },
// Note the ‘;’, this is a foreground statement.
every (1s) echo(5);
[00005008] *** 5
[00005508] *** 5
"bye!";
[00006008] "bye!"
- copyright(deep = true)
Display the copyright of Urbi SDK. Include copyright information about sub-components if deep.
lobby.copyright(false);
[00028588] *** Urbi version 2.7.4 rev. 268868e
[00028588] *** Copyright (C) 2004-2012 Gostai S.A.S.
lobby.copyright;
[00041874] *** Urbi version 2.7.4 rev. 268868e
[00041874] *** Copyright (C) 2004-2012 Gostai S.A.S.
[00041874] ***
[00041874] *** Libport version 2.7.4 rev. 268868e
[00041874] *** Copyright (C) 2004-2012 Gostai S.A.S.
- create
Instantiate a new Lobby.
- echo(value, channel = "")
Send value.asString to this, prefixed by the String channel name if specified. This is the
preferred way to send informative messages (prefixed with ‘***’).
lobby.echo("111", "foo");
[00015895:foo] *** 111
lobby.echo(222, "");
[00051909] *** 222
lobby.echo(333);
[00055205] *** 333
- echoEach(list, channel = "")
Apply echo(m, channel) for each member m of list.
lobby.echo([1, "2"], "foo");
[00015895:foo] *** [1, "2"]
lobby.echoEach([1, "2"], "foo");
[00015895:foo] *** 1
[00015895:foo] *** 2
lobby.echoEach([], "foo");
- instances
A list of the currently alive lobbies. It contains at least the Lobby object itself, and the current
lobby.
lobby in Lobby.instances;
Lobby in Lobby.instances;
- license
Display the end user license agreement of the Urbi SDK.
lobby.license;
[00000000] *** GNU AFFERO GENERAL PUBLIC LICENSE
[00000000] *** Version 3, 19 November 2007
[00000000] ***
[00000000] *** Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
[00000000] *** Everyone is permitted to copy and distribute verbatim copies
[00000000] *** of this license document, but changing it is not allowed.
[00000000] ***
[...]
[00000000] *** For more information on this, and how to apply and follow the GNU AGPL, see
[00000000] *** <http://www.gnu.org/licenses/>.
- lobby
The lobby of the current connection. This is typically this.
But when several connections are active (e.g., when there are remote connections), it can be
different from the target of the call.
Lobby.create| Lobby.create|;
for (var l : lobbies)
assert (l.lobby == Lobby.lobby);
- onDisconnect(lobby)
Event launched when this is disconnected. There is a single event instance for all the lobby,
Lobby.onDisconnect, the disconnected lobby being passed as argument.
- quit
Shut this lobby down, i.e., close the connection. The server is still running, see System.shutdown
to quit the server.
- receive(value)
This is low-level routine. Pretend the String value was received from the connection. There is
no guarantee that value will be the next program block that will be processed: for instance, if
you load a file which, in its middle, uses lobby.receive("foo"), then "foo" will be appended
after the end of the file.
Lobby.create.receive("12;");
[00478679] 12
- remoteIP
When this is connected to a remote server, it’s Internet address.
- send(value, channel = "")
This is low-level routine. Send the String value to this, prefixed by the String channel name
if specified.
lobby.send("111", "foo");
[00015895:foo] 111
lobby.send("222", "");
[00051909] 222
lobby.send("333");
[00055205] 333
- thanks
Credit the contributors of Urbi SDK. See also authors and Section 1.4.
lobby.thanks;
[00478679] *** Contributors to Urbi:
[00478679] ***
[00478679] *** - Adam Oleksy <adam.oleksy@pwr.wroc.pl>
[00478679] *** - Alexandre Morgand
[...]
[00478679] ***
[00478679] *** See also ‘authors;’.
- wall(value, channel = "")
Perform echo(value, channel) on all the existing lobbies (except Lobby itself).
Lobby.wall("111", "foo");
[00015895:foo] *** 111
- write(value)
This is low-level routine. Send the String value to the connection. Note that because of
buffering, the output might not be visible before an end-of-line character is output.
lobby.write("[");
lobby.write("999999999:");
lobby.write("myTag] ");
lobby.write("Hello, World!");
lobby.write("\n");
[999999999:myTag] Hello, World!
23.35 Location
This class aggregates two Positions and provides a way to print them as done in error
messages.
Without argument, a newly constructed Location has its Positions initialized to the first line and the
first column.
Location.new;
[00000001] 1.1
With a Position argument p, the Location will clone the Position into the begin and end
Positions.
Location.new(Position.new("file.u",14,25));
[00000001] file.u:14.25
With two Positions arguments begin and end, the Location will clone both Positions into its own
fields.
Location.new(Position.new("file.u",14,25), Position.new("file.u",14,35));
[00000001] file.u:14.25-34
23.36 Logger
Logger is used to report information to the final user or to the developer. It allows to pretty print
warnings, errors, debug messages or simple logs. Logger can also be used as Tag objects for it to
handle nested calls indentation. A log message is assigned a category which is shown between brackets
at beginning of lines, and a level which defines the context in which it has to be shown (see
Section 21.1.2). Log level definition and categories filtering can be changed using environment
variables defined in Section 21.1.2.
The proper use of Loggers is to instantiate your own category, and then to use the operator << for log
messages, possibly qualified by the proper level (in increase order of importance: dump, debug, trace,
log, warn, err):
var logger = Logger.new("Category")|;
logger.dump << "Low level debug message"|;
// Nothing displayed, unless the debug level is set to DUMP.
logger.warn << "something wrong happened, proceeding"|;
[ Category ] something wrong happened, proceeding
logger.err << "something really bad happened!"|;
[ Category ] something really bad happened!
You may also directly use the logger and passing arguments to these slots.
Logger.log("message", "Category") |;
[ Category ] message
Logger.log("message", "Category") :
{
Logger.log("indented message", "SubCategory")
}|;
[ Category ] message
[ SubCategory ] indented message
Logger can be used as is, without being cloned. It is possible to clone Logger defining a category
and/or a level of debug.
Logger.log("foo");
[ Logger ] foo
[00004702] Logger<Logger>
Logger.log("foo", "Category") |;
[ Category ] foo
var l = Logger.new("Category2");
[00004703] Logger<Category2>
l.log("foo")|;
[ Category2 ] foo
l.log("foo", "ForcedCategory") |;
[ ForcedCategory ] foo
- ’<<’(object)
Allow to use the Logger object as a Channel. This slot can only be used if both category
and level have been defined when cloning.
l = Logger.new("Category", Logger.Levels.Log);
[00090939] Logger<Category>
l << "foo";
[ Category ] foo
[00091939] Logger<Category>
- debug(message = "", category = category)
Report a debug message of category to the user. It will be shown if the debug level is Debug or
Dump. Return this to allow chained operations.
// None of these are displayed unless the current level is at least DEBUG.
logger.debug << "debug 1"|;
logger.debug("debug 2")|;
logger.debug("debug 3", "Category2")|;
- dump(message = "", category = category)
Report a debug message of category to the user. It will be shown if the debug level is Dump.
Return this to allow chained operations.
// None of these are displayed unless the current level is at least DEBUG.
logger.dump << "dump 1"|;
logger.dump("dump 2")|;
logger.dump("dump 3", "Category2")|;
- err(message = "", category = category)
Report an error message of category to the user. Return this to allow chained
operations.
- init(category)
Define the category of the new Logger object. If no category is given the new Logger will
inherit the category of its prototype.
- Levels
An Enumeration of the log levels defined in Section 21.1.2.
Logger.Levels.values;
[00000001] [None, Log, Trace, Debug, Dump]
- log(message = "", category = category)
Report a debug message of category to the user. It will be shown if debug is not disabled.
Return this to allow chained operations.
logger.log << "log 1"|;
[ Category ] log 1
logger.log("log 2")|;
[ Category ] log 2
logger.log("log 3", "Category2")|;
[ Category2 ] log 3
- onEnter
The primitive called when Logger is used as a Tag and is entered. This primitive only increments
the indentation level.
- onLeave
The primitive called when Logger is used as a Tag and is left. This primitive only decrements the
indentation level.
- trace(message = "", category = category)
Report a debug message of category to the user. It will be shown if the debug level is Trace,
Debug or Dump. Return this to allow chained operations.
// None of these are displayed unless the current level is at least TRACE.
logger.trace << "trace 1"|;
logger.trace("trace 2")|;
logger.trace("trace 3", "Category2")|;
- warn(message = "", category = category)
Report a warning message of category to the user. Return this to allow chained operations.
logger.warn << "warn 1"|;
[ Category ] warn 1
logger.warn("warn 2")|;
[ Category ] warn 2
logger.warn("warn 3", "Category2")|;
[ Category2 ] warn 3
23.37 Math
This object is actually meant to play the role of a name-space in which the mathematical functions
are defined with a more conventional notation. Indeed, in an object-oriented language, writing pi.cos
makes perfect sense, yet cos(pi) is more usual.
Since it is a Singleton, you are not expected to build other instances.
- abs(float)
Bounce to float.abs.
Math.abs(1) == 1;
Math.abs(-1) == 1;
Math.abs(0) == 0;
Math.abs(3.5) == 3.5;
- acos(float)
Bounce to float.acos.
- asin(float)
Bounce to float.asin.
- atan(float)
Bounce to float.atan.
- atan2(x, y)
Bounce to x.atan2(y).
Math.atan2(2, 2) ∼= pi/4;
Math.atan2(-2, 2) ∼= -pi/4;
- cos(float)
Bounce to float.cos.
Math.cos(0) == 1;
Math.cos(pi) ∼= -1;
- exp(float)
Bounce to float.exp.
- inf
Bounce to Float.inf.
- log(float)
Bounce to float.log.
- max(arg1, ...)
Bounce to [arg1, ...].max, see List.max.
max( 100, 20, 3 ) == 100;
max("100", "20", "3") == "3";
- min(arg1, ...)
Bounce to [arg1, ...].min, see List.min.
min( 100, 20, 3 ) == 3;
min("100", "20", "3") == "100";
- nan
Bounce to Float.nan.
- pi
Bounce to Float.pi.
- random(float)
Bounce to float.random.
- round(float)
Bounce to float.round.
Math.round(1) == 1;
Math.round(1.1) == 1;
Math.round(1.49) == 1;
Math.round(1.5) == 2;
Math.round(1.51) == 2;
- sign(float)
Bounce to float.sign.
Math.sign(2) == 1;
Math.sign(-2) == -1;
Math.sign(0) == 0;
- sin(float)
Bounce to float.sin.
Math.sin(0) == 0;
Math.sin(pi) ∼= 0;
- sqr(float)
Bounce to float.sqr.
- sqrt(float)
Bounce to float.sqrt.
- srandom(float)
Bounce to float.srandom.
- tan(float)
Bounce to float.tan.
- trunc(float)
Bounce to float.trunc.
Math.trunc(1) == 1;
Math.trunc(1.1) == 1;
Math.trunc(1.49) == 1;
Math.trunc(1.5) == 1;
Math.trunc(1.51) == 1;
23.38 Mutex
Mutex allow to define critical sections.
A Mutex can be constructed like any other Tag but without name.
var m = Mutex.new;
[00000000] Mutex_0x964ed40
You can define critical sections by tagging your code using the Mutex.
var m = Mutex.new|;
m: echo("this is critical section");
[00000001] *** this is critical section
As a critical section, two pieces of code tagged by the same “Mutex” will never be executed at the
same time.
- asMutex
Return this.
var m1 = Mutex.new|;
assert
{
m1.asMutex === m1;
};
23.39 nil
The special entity nil is an object used to denote an empty value. Contrary to void, it is a regular
value which can be read.
Being a singleton, nil is not to be constructed, just used.
- isNil
Whether this is nil. I.e., true. See also Object.isNil.
nil.isNil;
!Object.isNil;
23.40 Object
Object includes the mandatory primitives for all objects in urbiscript. All objects in urbiscript
must inherit (directly or indirectly) from it.
A fresh object can be instantiated by cloning Object itself.
Object.new;
[00000421] Object_0x00000000
The keyword class also allows to define objects intended to serve as prototype of a family
of objects, similarly to classes in traditional object-oriented programming languages (see
Section 11.4).
{
class Foo
{
var attr = 23;
};
assert
{
Foo.localSlotNames == ["asFoo", "attr", "type"];
Foo.asFoo === Foo;
Foo.attr == 23;
Foo.type == "Foo";
};
};
- acceptVoid
Return this. See void to know why.
{
var o = Object.new;
assert(o.acceptVoid === o);
};
- addProto(proto)
Add proto into the list of prototypes of this. Return this.
do (Object.new)
{
assert
{
addProto(Orderable) === this;
protos == [Orderable, Object];
};
}|;
- allProto
A list with this, its parents, their parents,…
123.allProtos.size == 12;
- allSlotNames
Deprecated alias for slotNames.
Object.allSlotNames == Object.slotNames;
- apply(args)
“Invoke this”. The size of the argument list, args, must be one. This argument is ignored. This
function exists for compatibility with Code.apply.
Object.apply([this]) === Object;
Object.apply([1]) === Object;
- as(type)
Convert this to type. This is syntactic sugar for asType when Type is the type of type.
12.as(Float) == 12;
"12".as(Float) == 12;
12.as(String) == "12";
Object.as(Object) === Object;
- asBool
Whether this is “true”, see Section 23.3.3.
assert
{
Global.asBool == true;
nil.asBool == false;
};
void.asBool;
[00000421:error] !!! unexpected void
- bounce(name)
Return this.name transformed from a method into a function that takes its target (its “this”)
as first and only argument. this.name must take no argument.
{ var myCos = Object.bounce("cos"); myCos(0) } == 0.cos;
{ var myType = bounce("type"); myType(Object); } == "Object";
{ var myType = bounce("type"); myType(3.14); } == "Float";
- callMessage(msg)
Invoke the CallMessage msg on this.
- clone
Clone this, i.e., create a fresh, empty, object, which sole prototype is this.
Object.clone.protos == [Object];
Object.clone.localSlotNames == [];
- cloneSlot(from, to)
Set the new slot to using a clone of from. This can only be used into the same object.
var foo = Object.new |;
cloneSlot("foo", "bar") |;
assert(!(foo === bar));
- copySlot(from, to)
Same as cloneSlot, but the slot aren’t cloned, so the two slot are the same.
var moo = Object.new |;
cloneSlot("moo", "loo") |;
assert(!(moo === loo));
- createSlot(name)
Create an empty slot (which actually means it is bound to void) named name. Raise an error if
name was already defined.
do (Object.new)
{
assert(!hasLocalSlot("foo"));
assert(createSlot("foo").isVoid);
assert(hasLocalSlot("foo"));
}|;
- dump(depth)
Describe this: its prototypes and slots. The argument depth specifies how recursive
the description is: the greater, the more detailed. This method is mostly useful for
debugging low-level issues, for a more human-readable interface, see also inspect.
do (2) { var this.attr = "foo"; this.attr->prop = "bar" }.dump(0);
[00015137] *** Float_0x240550 {
[00015137] *** /* Special slots */
[00015137] *** protos = Float
[00015137] *** value = 2
[00015137] *** /* Slots */
[00015137] *** attr = String_0x23a750 <...>
[00015137] *** /* Properties */
[00015137] *** prop = String_0x23a7a0 <...>
[00015137] *** }
do (2) { var this.attr = "foo"; this.attr->prop = "bar" }.dump(1);
[00020505] *** Float_0x240550 {
[00020505] *** /* Special slots */
[00020505] *** protos = Float
[00020505] *** value = 2
[00020505] *** /* Slots */
[00020505] *** attr = String_0x23a750 {
[00020505] *** /* Special slots */
[00020505] *** protos = String
[00020505] *** /* Slots */
[00020505] *** }
[00020505] *** /* Properties */
[00020505] *** prop = String_0x239330 {
[00020505] *** /* Special slots */
[00020505] *** protos = String
[00020505] *** /* Slots */
[00020505] *** }
[00020505] *** }
- getPeriod
Deprecated. Use System.period instead.
- getProperty(slotName, propName)
The value of the propName property associated to the slot slotName if defined. Raise an error
otherwise.
const var myPi = 3.14|;
assert (getProperty("myPi", "constant"));
getProperty("myPi", "foobar");
[00000045:error] !!! property lookup failed: myPi->foobar
- getLocalSlot(name)
The value associated to name in this, excluding its ancestors (contrary to getSlot).
var a = Object.new|;
// Local slot.
var a.slot = 21|;
assert
{
a.locateSlot("slot") === a;
a.getLocalSlot("slot") == 21;
};
// Inherited slot are not looked-up.
assert { a.locateSlot("init") == Object };
a.getLocalSlot("init");
[00041066:error] !!! lookup failed: init
- getSlot(name)
The value associated to name in this, possibly after a look-up in its prototypes (contrary to
getLocalSlot).
var b = Object.new|;
var b.slot = 21|;
assert
{
// Local slot.
b.locateSlot("slot") === b;
b.getSlot("slot") == 21;
// Inherited slot.
b.locateSlot("init") === Object;
b.getSlot("init") == Object.getSlot("init");
};
// Unknown slot.
assert { b.locateSlot("ENOENT") == nil; };
b.getSlot("ENOENT");
[00041066:error] !!! lookup failed: ENOENT
- hash
A Hash object for this. This default implementation returns a different hash for every object, so
every key maps to a different cells. Classes that have value semantic should override the hash
method so as objects that are equal (in the Object.’==’ sense) have the same hash.
String.hash does so for instance; as a consequence different String objects with the same value
map to the same cell.
A hash only makes sense as long as the hashed object exists.
var o1 = Object.new|
var o2 = Object.new|
assert
{
o1.hash == o1.hash;
o1.hash != o2.hash;
};
- hasLocalSlot(slot)
Whether this features a slot slot, locally (not from some ancestor). See also hasSlot.
class Base { var this.base = 23; } |;
class Derive: Base { var this.derive = 43 } |;
assert(Derive.hasLocalSlot("derive"));
assert(!Derive.hasLocalSlot("base"));
- hasProperty(slotName, propName)
Whether the slot slotName of this has a property propName.
const var halfPi = pi / 2|;
assert
{
hasProperty("halfPi", "constant");
!hasProperty("halfPi", "foobar");
};
- hasSlot(slot)
Whether this has the slot slot, locally, or from some ancestor. See also hasLocalSlot.
Derive.hasSlot("derive");
Derive.hasSlot("base");
!Base.hasSlot("derive");
- ’$id’
- inspect(deep = false)
Describe this: its prototypes and slots, and their properties. If deep, all the slots are described,
not only the local slots. See also dump.
do (2) { var this.attr = "foo"; this.attr->prop = "bar"}.inspect;
[00001227] *** Inspecting 2
[00001227] *** ** Prototypes:
[00001227] *** 0
[00001227] *** ** Local Slots:
[00001228] *** attr : String
[00001228] *** Properties:
[00001228] *** prop : String = "bar"
- isA(obj)
Whether this has obj in his parents.
Float.isA(Orderable);
! String.isA(Float);
- isNil
Whether this is nil.
- isProto
Whether this is a prototype.
Float.isProto;
! 42.isProto;
- isVoid
Whether this is void. See void.
void.isVoid;
! 42.isVoid;
- localSlotNames
A list with the names of the local (i.e., not including those of its ancestors) slots of this. See also
slotNames.
var top = Object.new|;
var top.top1 = 1|;
var top.top2 = 2|;
var bot = top.new|;
var bot.bot1 = 10|;
var bot.bot2 = 20|;
assert
{
top.localSlotNames == ["top1", "top2"];
bot.localSlotNames == ["bot1", "bot2"];
};
- locateSlot(slot)
The Object that provides slot to this, or nil if this does not feature slot.
locateSlot("locateSlot") == Object;
locateSlot("doesNotExist").isNil;
- print
Send this to the Channel.topLevel channel.
1.print;
[00001228] 1
[1, "12"].print;
[00001228] [1, "12"]
- protos
The list of prototypes of this.
- properties(slotName)
A dictionary of the properties of slot slotName. Raise an error if the slot does not exist.
2.properties("foo");
[00238495:error] !!! lookup failed: foo
do (2) { var foo = "foo" }.properties("foo");
[00238501] ["constant" => false]
do (2) { var foo = "foo" ; foo->bar = "bar" }.properties("foo");
[00238502] ["bar" => "bar", "constant" => false]
- removeLocalSlot(slot)
Remove slot from the (local) list of slots of this, and return this. Raise an error if slot does
not exist. See also removeSlot.
var base = Object.new|;
var base.slot = "base"|;
var derive = Base.new|;
var derive.slot = "derive"|;
derive.removeLocalSlot("foo");
[00000080:error] !!! lookup failed: foo
assert
{
derive.removeLocalSlot("slot") === derive;
derive.localSlotNames == [];
base.slot == "base";
};
derive.removeLocalSlot("slot");
[00000090:error] !!! lookup failed: slot
assert
{
base.slot == "base";
};
- removeProperty(slotName, propName)
Remove the property propName from the slot slotName. Raise an error if the slot does
not exist. Warn if propName does not exist; in a future release this will be an error.
var r = Object.new|;
// Non-existing slot.
r.removeProperty("slot", "property");
[00000072:error] !!! lookup failed: slot
var r.slot = "slot value"|;
// Non-existing property.
r.removeProperty("slot", "property");
[00000081:warning] !!! no such property: slot->property
[00000081:warning] !!! called from: removeProperty
r.slot->property = "property value"|;
assert
{
r.hasProperty("slot", "property");
// Existing property.
r.removeProperty("slot", "property") == "property value";
! r.hasProperty("slot", "property");
};
- removeProto(proto)
Remove proto from the list of prototypes of this, and return this. Do nothing if proto is not a
prototype of this.
do (Object.new)
{
assert
{
addProto(Orderable);
removeProto(123) === this;
protos == [Orderable, Object];
removeProto(Orderable) === this;
protos == [Object];
};
}|;
- removeSlot(slot)
Remove slot from the (local) list of slots of this, and return this. Warn if slot
does not exist; in a future release this will be an error. See also removeLocalSlot.
{
var base = Object.new;
var base.slot = "base";
var derive = Base.new;
var derive.slot = "derive";
assert
{
derive.removeSlot("foo") === derive;
[00000080:warning] !!! no such local slot: foo
[00000080:warning] !!! called from: removeSlot
[00000080:warning] !!! called from: code
[00000080:warning] !!! called from: eval
[00000080:warning] !!! called from: value
[00000080:warning] !!! called from: assertCall
derive.removeSlot("slot") === derive;
derive.localSlotNames == [];
base.slot == "base";
derive.removeSlot("slot") === derive;
[00000099:warning] !!! no such local slot: slot
[00000099:warning] !!! called from: removeSlot
[00000099:warning] !!! called from: code
[00000099:warning] !!! called from: eval
[00000099:warning] !!! called from: value
[00000099:warning] !!! called from: assertCall
base.slot == "base";
};
};
- setConstSlot
Like setSlot but the created slot is const.
assert(setConstSlot("fortyTwo", 42) == 42);
fortyTwo = 51;
[00000000:error] !!! cannot modify const slot
- setProperty(slotName, propName, value)
Set the property propName of slot slotName to value. Raise an error in slotName does not
exist. Return value. This is what slotName->propName = value actually performs.
do (Object.new)
{
var slot = "slot";
var value = "value";
assert
{
setProperty("slot", "prop", value) === value;
"prop" in properties("slot");
getProperty("slot", "prop") === value;
slot->prop === value;
setProperty("slot", "noSuchProperty", value) === value;
};
}|;
setProperty("noSuchSlot", "prop", "12");
[00000081:error] !!! lookup failed: noSuchSlot
- setProtos(protos)
Set the list of prototypes of this to protos. Return void.
do (Object.new)
{
assert
{
protos == [Object];
setProtos([Orderable, Object]).isVoid;
protos == [Orderable, Object];
};
}|;
- setSlot(name, value)
Create a slot name mapping to value. Raise an error if name was already defined. This is what
var name = value actually performs.
Object.setSlot("theObject", Object) === Object;
Object.theObject === Object;
theObject === Object;
If the current job is in redefinition mode, setSlot on an already defined slot is not an error and
overwrites the slot like updateSlot would. See the redefinitionMode method in
System.
- slotNames
A list with the slot names of this and its ancestors.
Object.localSlotNames
.subset(Object.slotNames);
Object.protos.foldl(function (var r, var p) { r + p.localSlotNames },
[])
.subset(Object.slotNames);
- type
The name of the type of this. The class construct defines this slot to the name of the class
(Section 11.4). This is used to display the name of “instances”.
class Example {};
[00000081] Example
assert
{
Example.type == "Example";
};
Example.new;
[00000081] Example_0x6fb2720
- uid
The unique id of this.
{
var foo = Object.new;
var bar = Object.new;
assert
{
foo.uid == foo.uid;
foo.uid != bar.uid;
};
};
- unacceptVoid
Return this. See void to know why.
{
var o = Object.new|
assert(o.unacceptVoid === o);
};
- updateSlot(name, value)
Map the existing slot named name to value. Raise an error if name was not defined.
Object.setSlot("one", 1) == 1;
Object.updateSlot("one", 2) == 2;
Object.one == 2;
- ’!’
Logical negation. If this evaluates to false return true and vice-versa.
!1 == false;
!0 == true;
!"foo" == false;
!"" == true;
- ’+=’(that)
Bounce to this ’+’ that.
- ’-=’(that)
Bounce to this ’-’ that.
- ’*=’(that)
Bounce to this ’*’ that.
- ’/=’(that)
Bounce to this ’/’ that.
- ’^=’(that)
Bounce to this ’^’ that.
- ’%=’(that)
Bounce to this ’-’ that.
- ’==’(that)
Whether this and that are equal. See also Comparable and Section 22.1.8.6. By
default, bounces to ’===’. This operator must be redefined for objects that have a
value-semantics; for instance two String objects that denotes the same string should be
equal according to ==, although physically different (i.e., not equal according to ===).
{
var o1 = Object.new;
var o2 = Object.new;
assert
{
o1 == o1;
!(o1 == o2);
o1 != o2;
!(o1 != o1);
1 == 1;
"1" == "1";
[1] == [1];
};
};
- ’===’(that)
Whether this and that are exactly the same object (i.e., this and that are two different
means to denote the very same location in memory). To denote equivalence, use ’==’;
for instance two Float objects that denote 42 can be different objects (in the sense
of ===), but will be considered equal by ==. See also ’===’ and Section 22.1.8.6.
{
var o1 = Object.new;
var o2 = Object.new;
assert
{
o1 === o1;
!(o1 === o2);
!( 1 === 1 );
!("1" === "1");
!([1] === [1]);
};
};
- ’!==’(that)
The negation of \this === \that, see ’===’.
{
var o1 = Object.new;
var o2 = Object.new;
assert
{
o1 !== o2;
!(o1 !== o1);
1 !== 1;
"1" !== "1";
[1] !== [1];
};
};
23.41 Orderable
Objects that have a concept of “less than”. See also Comparable.
This object, made to serve as prototype, provides a definition of < based on >, and vice versa; and
definition of <=/>= based on </>==. You must define either < or >, otherwise invoking either method
will result in endless recursions.
class Foo : Orderable
{
var value = 0;
function init (v) { value = v; };
function ’<’ (that) { value < that.value; };
function asString() { "<" + value.asString + ">"; };
}|;
var one = Foo.new(1)|;
var two = Foo.new(2)|;
assert
{
one <= one ; one <= two ; !(two <= one);
!(one > one) ; !(one > two) ; two > one;
(one >= one) ; !(one >= two) ; two >= one;
};
23.42 OutputStream
OutputStreams are used to write (possibly binary) files by hand.
An OutputStream is a writing-interface to a file; its constructor requires a File. If the file already
exists, content is appended to it. Remove the file beforehand if you want to override its
content.
var o1 = OutputStream.new(File.create("file.txt"));
[00000001] OutputStream_0x827000
var o2 = OutputStream.new(File.new("file.txt"));
[00000002] OutputStream_0x827000
When a stream (OutputStream or InputStream) is opened on a File, that File cannot be removed.
On Unix systems, this is handled gracefully (the references to the file are removed, but the content is
still there for the streams that were already bound to this file); so in practice, the File appears to be
removable. On Windows, the File cannot be removed at all. Therefore, do not forget to close the
streams you opened.
- Output this.asString. Return this to enable chains of calls. Raise an error if the file is closed.
var o = OutputStream.new(File.create("fresh.txt"))|;
o << 1 << "2" << [3, [4]]|;
o.close;
assert (File.new("fresh.txt").content.data == "12[3, [4]]");
o << 1;
[00000005:error] !!! <<: stream is closed
- flush
To provide efficient input/output operations, buffers are used. As a consequence,
what is put into a stream might not be immediately saved on the actual file. To flush
a buffer means to dump its content to the file. Raise an error if the file is closed.
var s = OutputStream.new(File.create("file.txt"))|
s.flush;
s.close;
s.flush;
[00039175:error] !!! flush: stream is closed
- put(byte)
Output the character corresponding to the numeric code byte in this, and return this. Raise an
error if the file is closed.
var f = File.create("put.txt") |
var os = OutputStream.new(f) |
assert
{
os.put(0)
.put(255)
.put(72).put(101).put(108).put(108).put(111)
=== os;
f.content.data == "\0\xffHello";
};
os.put(12.5);
[00029816:error] !!! put: argument 1: bad numeric conversion: overflow or non empty fractional part: 12.5
os.put(-1);
[00034840:error] !!! put: argument 1: bad numeric conversion: negative overflow: -1
os.put(256);
[00039175:error] !!! put: argument 1: bad numeric conversion: positive overflow: 256
os.close;
os.put(0);
[00039179:error] !!! put: stream is closed
23.43 Pair
A pair is a container storing two objects, similar in spirit to std::pair in C++.
A Pair is constructed with two arguments.
Pair.new(1, 2);
[00000001] (1, 2)
Pair.new;
[00000003:error] !!! new: expected 2 arguments, given 0
Pair.new(1, 2, 3, 4);
[00000003:error] !!! new: expected 2 arguments, given 4
- first
Return the first member of the pair.
Pair.new(1, 2).first == 1;
Pair[0] === Pair.first;
- second
Return the second member of the pair.
Pair.new(1, 2).second == 2;
Pair[1] === Pair.second;
23.44 Path
A Path points to a file system entity (directory, file and so forth).
A Path is constructed with the string that points to the file system entity. This path can be relative or
absolute.
Path.new("/path/file.u");
[00000001] Path("/path/file.u")
Some minor simplifications are made, such as stripping useless ‘./’ occurrences.
Path.new("././///.//foo/");
[00000002] Path("foo")
- absolute
Whether this is absolute.
Path.new("/abs/path").absolute;
!Path.new("rel/path").absolute;
- asList
List of names used in path (directories and possibly file), from bottom up. There is no difference
between relative path and absolute path.
Path.new("/path/to/file.u").asList == ["path", "to", "file.u"];
Path.new("/path").asList == Path.new("path").asList;
- asPrintable
Path.new("file.txt").asPrintable == "Path(\"file.txt\")";
- asString
The name of the file.
Path.new("file.txt").asString == "file.txt";
- basename
Base name of the path.
Path.new("/absolute/path/file.u").basename == "file.u";
Path.new("relative/path/file.u").basename == "file.u";
- cd
Change current working directory to this. Return the new current working directory as a
Path.
- cwd
The current working directory.
{
// Save current directory.
var pwd = Path.cwd|
// Go into ‘‘/’’.
var root = Path.new("/").cd;
// Current working directory is ‘‘/’’.
assert(Path.cwd == root);
// Go back to the directory we were in.
assert(pwd.cd == pwd);
};
- dirname
Directory name of the path.
Path.new("/abs/path/file.u").dirname == Path.new("/abs/path");
Path.new("rel/path/file.u").dirname == Path.new("rel/path");
- exists
Whether something (a file, a directory, …) exists where this points to.
Path.cwd.exists;
Path.new("/").exists;
!Path.new("/this/path/does/not/exists").exists;
- isDir
Whether this is a directory.
- isReg
Whether this is a regular file.
- open
Open this. Return either a Directory or a File according the type of this. See File and
Directory.
- readable
Whether this is readable. Throw if does not even exist.
- writable
Whether this is writable. Throw if does not even exist.
- ’/’(rhs)
Create a new Path that is the concatenation of this and rhs. rhs can be a Path or a String and
cannot be absolute.
assert(Path.new("/foo/bar") / Path.new("baz/qux/quux")
== Path.new("/foo/bar/baz/qux/quux"));
Path.cwd / Path.new("/tmp/foo");
[00000003:error] !!! /: Rhs of concatenation is absolute: /tmp/foo
- ’==’(that)
Same as comparing the string versions of this and that. Beware that two paths may be different
and point to the very same location.
Path.new("/a") == Path.new("/a");
!(Path.new("/a") == Path.new("a") );
- ’<’(that)
Same as comparing the string versions of this and that.
Path.new("/a") < Path.new("/a/b");
!(Path.new("/a/b") < Path.new("/a") );
23.45 Pattern
Pattern class is used to make correspondences between a pattern and another Object. The visit is
done either on the pattern or on the element against which the pattern is compared.
Patterns are used for the implementation of the pattern matching. So any class made compatible
with the pattern matching implemented by this class will allow you to use it implicitly in your
scripts.
[1, var a, var b] = [1, 2, 3];
[00000000] [1, 2, 3]
a;
[00000000] 2
b;
[00000000] 3
A Pattern can be created with any object that can be matched.
Pattern.new([1]); // create a pattern to match the list [1].
[00000000] Pattern_0x189ea80
Pattern.new(Pattern.Binding.new("a")); // match anything into "a".
[00000000] Pattern_0x18d98b0
- Binding
A class used to create pattern variables.
Pattern.Binding.new("a");
[00000000] var a
- bindings
A Dictionary filled by the match function for each Binding contained inside the
pattern.
{
var p = Pattern.new([Pattern.Binding.new("a"), Pattern.Binding.new("b")]);
assert (p.match([1, 2]));
p.bindings
};
[00000000] ["a" => 1, "b" => 2]
- match(value)
Use value to unify the current pattern with this value. Return the status of the match.
- If the match is correct, then the bindings member will contain the result of every
matched values.
- If the match is incorrect, then the bindings member should not be used.
If the pattern contains multiple Binding with the same name, then the behavior is
undefined.
Pattern.new(1).match(1);
Pattern.new([1, 2]).match([1, 2]);
! Pattern.new([1, 2]).match([1, 3]);
! Pattern.new([1, 2]).match([1, 2, 3]);
Pattern.new(Pattern.Binding.new("a")).match(0);
Pattern.new([1, Pattern.Binding.new("a")]).match([1, 2]);
! Pattern.new([1, Pattern.Binding.new("a")]).match(0);
- matchPattern(pattern, value)
This function is used as a callback function to store all bindings in the same place. This function
is useful inside objects that implement a match or matchAgainst function that need to continue
the match deeper. Return the status of the match (a Boolean).
The pattern should provide a method match(handler,value) otherwise the value method
matchAgainst(handler, pattern) is used. If none are provided the ’==’ operator is
used.
To see how to use it, you can have a look at the implementation of List.matchAgainst.
- pattern
The pattern given at the creation.
Pattern.new(1).pattern == 1;
Pattern.new([1, 2]).pattern == [1, 2];
{
var pattern = [1, Pattern.Binding.new("a")];
Pattern.new(pattern).pattern === pattern
};
23.46 Position
This class is used to handle file locations with a line, column and file name.
Without argument, a newly constructed Position has its fields initialized to the first line and the first
column.
Position.new;
[00000001] 1.1
With a position argument p, the newly constructed Position is a clone of p.
Position.new(Position.new(2, 3));
[00000001] 2.3
With two float arguments l and c, the newly constructed Position has its line and column defined
and an empty file name.
Position.new(2, 3);
[00000001] 2.3
With three arguments f, l and c, the newly constructed Position has its file name, line and column
defined.
Position.new("file.u", 2, 3);
[00000001] file.u:2.3
- ’+’(n)
Return a new Position which is shifted from n columns to the right. The minimal value of the
new position column is 1.
Position.new(2, 3) + 2 == Position.new(2, 5);
Position.new(2, 3) + -4 == Position.new(2, 1);
- ’-’(n)
Return a new Position which is shifted from n columns to the left. The minimal value of the new
Position column is 1.
Position.new(2, 3) - 1 == Position.new(2, 2);
Position.new(2, 3) - -4 == Position.new(2, 7);
- ’==’(other)
Compare the lines and columns of two Positions.
Position.new(2, 3) == Position.new(2, 3);
Position.new("a.u", 2, 3) == Position.new("b.u", 2, 3);
Position.new(2, 3) != Position.new(2, 2);
- ’<’(other)
Order comparison of lines and columns.
Position.new(2, 3) < Position.new(2, 4);
Position.new(2, 3) < Position.new(3, 1);
- asString
Present as ‘file:line.column ’, the file name is omitted if it is not defined.
Position.new("file.u", 2, 3).asString == "file.u:2.3";
- column
Field which give access to the column number of the Position.
Position.new(2, 3).column == 3;
- columns(n)
Identical to ’+’(n).
Position.new(2, 3).columns(2) == Position.new(2, 5);
Position.new(2, 3).columns(-4) == Position.new(2, 1);
- file
The Path of the Position file.
Position.new("file.u", 2, 3).file == Path.new("file.u");
Position.new(2, 3).file == nil;
- line
Field which give access to the line number of the Position.
Position.new(2, 3).line == 2;
- lines(n)
Add n lines and reset the column number to 1.
Position.new(2, 3).lines(2) == Position.new(4, 1);
Position.new(2, 3).lines(-1) == Position.new(1, 1);
23.47 Primitive
C++ routine callable from urbiscript.
It is not possible to construct a Primitive.
- apply(args)
Invoke a primitive. The argument list, args, must start with the target.
Float.getSlot("+").isA(Global.getSlot("Primitive"));
Float.getSlot("+").apply([1, 2]) == 3;
String.getSlot("+").isA(Global.getSlot("Primitive"));
String.getSlot("+").apply(["1", "2"]);
- asPrimitive
Return this.
Float.getSlot("+").asPrimitive === Float.getSlot("+");
23.48 Process
A Process is a separated task handled by the underneath operating system.
Windows Issues
Process is not yet supported under Windows.
The following examples runs the cat program, a Unix standard command that simply copies on its
(standard) output its (standard) input.
var p = Process.new("cat", []);
[00000004] Process cat
Just created, this process is not running yet. Use run to launch it.
p.status;
[00000005] not started
p.run;
p.status;
[00000006] running
Then we feed its input, named stdin in the Unix tradition, and close its input.
p.stdin << "1\n" |
p.stdin << "2\n" |
p.stdin << "3\n" |;
p.status;
[00000007] running
p.stdin.close;
At this stage, the status of the process is unknown, as it is running asynchronously. If it has had
enough time to “see” that its input is closed, then it will have finished, otherwise we might have to
wait for awhile. The method join means “wait for the process to finish”.
p.join;
p.status;
[00000008] exited with status 0
Finally we can check its output.
p.stdout.asList;
[00000009] ["1", "2", "3"]
A Process needs a program name to run and a possibly-empty list of command line arguments. Calling
run is required to execute the process.
Process.new("cat", []);
[00000004] Process cat
Process.new("cat", ["--version"]);
[00000004] Process cat
- asProcess
Return this.
do (Process.new("cat", []))
{
assert (asProcess === this);
}|;
- asString
Process and the name of the program.
Process.new("cat", ["--version"]).asString
== "Process cat";
- done
Whether the process has completed its execution.
do (Process.new("sleep", ["1"]))
{
assert (!done);
run;
assert (!done);
join;
assert (done);
}|;
- join
Wait for the process to finish. Changes its status.
do (Process.new("sleep", ["2"]))
{
var t0 = System.time;
assert (status.asString == "not started");
run;
assert (status.asString == "running");
join;
assert (t0 + 2s <= System.time);
assert (status.asString == "exited with status 0");
}|;
- kill
If the process is not done, interrupt it (with a SIGKILL in Unix parlance). You still have to wait
for its termination with join.
do (Process.new("sleep", ["1"]))
{
run;
kill;
join;
assert (done);
assert (status.asString == "killed by signal 9");
}|;
- name
The (base) name of the program the process runs.
Process.new("cat", ["--version"]).name == "cat";
- run
Launch the process. Changes it status. A process can only be run once.
do (Process.new("sleep", ["1"]))
{
assert (status.asString == "not started");
run;
assert (status.asString == "running");
join;
assert (status.asString == "exited with status 0");
run;
}|;
[00021972:error] !!! run: Process was already run
- runTo
- status
An object whose slots describe the status of the process.
- stderr
An InputStream (the output of the Process is an input for Urbi) to the standard error stream of
the process.
do (Process.new("urbi-send", ["--no-such-option"]))
{
run;
join;
assert
{
stderr.asList ==
["urbi-send: invalid option: --no-such-option",
"Try ‘urbi-send --help’ for more information."];
};
}|;
- stdin
An OutputStream (the input of the Process is an output for Urbi) to the standard input stream
of the process.
do (Process.new(System.programName, ["--version"]))
{
run;
join;
assert
{
stdout.asList[1] == "Copyright (C) 2004-2012 Gostai S.A.S..";
};
}|;
- stdout
An InputStream (the output of the Process is an input for Urbi) to the standard output stream
of the process.
do (Process.new("cat", []))
{
run;
stdin << "Hello, World!\n";
stdin.close;
join;
assert (stdout.asList == ["Hello, World!"]);
}|;
23.49 Profile
A Profile object contains information about the efficiency of a piece of code.
One can profile a piece of code with the System.profile function.
var profile = System.profile(function() { echo("foo") });
[00000001] *** foo
[00001672] Profile(
Yields: 0
Total time (us): 112
Wall-clock time (us): 112
Function calls: 16
Max depth: 5
.-------------------------------------------------------------------.
| function | % | cumulative | self | calls | self |
| | | (us) | (us) | | (us/call) |
|--------------+--------+------------+--------+---------+-----------|
| send | 24.11 | 27 | 27 | 1 | 27 |
| echo | 14.29 | 43 | 16 | 1 | 16 |
| apply | 10.71 | 55 | 12 | 1 | 12 |
| apply | 9.82 | 66 | 11 | 1 | 11 |
| + | 8.93 | 76 | 10 | 2 | 5 |
| <profiled> | 6.25 | 83 | 7 | 1 | 7 |
| asString | 6.25 | 90 | 7 | 1 | 7 |
| lobby | 5.36 | 96 | 6 | 2 | 3 |
| getSlot | 3.57 | 104 | 4 | 1 | 4 |
| + | 2.68 | 107 | 3 | 1 | 3 |
| lobby | 2.68 | 110 | 3 | 2 | 1 |
| Lobby | 1.79 | 112 | 2 | 2 | 1 |
’--------------’--------’------------’--------’---------’-----------’
)
The result is a Profile object that contains information about which functions where used when
evaluating the given code, how many time they were called, how much time was spent in them, …Lines
are sorted by decreasing “self time”. Note that the <profiled> special function stands for the function
given in parameter. Every line is represented by a Profile.Function object, see its documentation for
the meaning of every column.
If the profiled code spawns asynchronous tasks via detach or at for instance, additional statistics will
be included in the resulting Profile every time the detached code is executed. This is extremely useful
to profile asynchronous code based on at for instance.
var Global.x = false|;
function profiled()
{
at (x)
echo("true")
onleave
echo("false")
}|;
// This is the profiling for the creation of the ’at’. Note that the
// condition was already evaluated once, to see whether it should trigger
// immediately.
var profile_async = System.profile(&profiled);
[00000000] Profile(
Yields: 0
Total time (us): 485
Wall-clock time (us): 485
Function calls: 15
Max depth: 7
.-------------------------------------------------------------------.
| function | % | cumulative | self | calls | self |
| | | (us) | (us) | | (us/call) |
|--------------+--------+------------+--------+---------+-----------|
| <profiled> | 38.14 | 185 | 185 | 1 | 185 |
| new | 13.20 | 249 | 64 | 1 | 64 |
| at: { x } | 12.37 | 309 | 60 | 1 | 60 |
| onEvent | 10.10 | 358 | 49 | 1 | 49 |
| callMessage | 5.77 | 386 | 28 | 1 | 28 |
| map | 5.15 | 411 | 25 | 1 | 25 |
| evalArgs | 3.92 | 430 | 19 | 1 | 19 |
| clone | 3.30 | 446 | 16 | 1 | 16 |
| updateSlot | 2.47 | 458 | 12 | 1 | 12 |
| each| | 2.06 | 468 | 10 | 1 | 10 |
| getSlot | 1.44 | 475 | 7 | 1 | 7 |
| init | 0.82 | 479 | 4 | 1 | 4 |
| x | 0.82 | 483 | 4 | 2 | 2 |
| args | 0.41 | 485 | 2 | 1 | 2 |
’--------------’--------’------------’--------’---------’-----------’
)
// Trigger the at twice.
Global.x = true;
[00106213] true
[00106213] *** true
Global.x = false;
[00172119] false
[00172119] *** false
// The profile now includes additional statistic about the evaluations of
// the condition and the bodies of the at.
profile_async;
[00178623] Profile(
Yields: 2
Total time (us): 1307
Wall-clock time (us): 1307
Function calls: 51
Max depth: 7
.-------------------------------------------------------------------.
| function | % | cumulative | self | calls | self |
| | | (us) | (us) | | (us/call) |
|--------------+--------+------------+--------+---------+-----------|
| event | 15.61 | 204 | 204 | 1 | 204 |
| event | 15.00 | 400 | 196 | 1 | 196 |
| <profiled> | 14.15 | 585 | 185 | 1 | 185 |
| at: { x } | 9.26 | 706 | 121 | 3 | 40.333 |
| echo | 6.12 | 786 | 80 | 2 | 40 |
| apply | 5.66 | 860 | 74 | 2 | 37 |
| lobby | 4.97 | 925 | 65 | 4 | 16.250 |
| new | 4.90 | 989 | 64 | 1 | 64 |
| onEvent | 3.75 | 1038 | 49 | 1 | 49 |
| send | 2.60 | 1072 | 34 | 2 | 17 |
| callMessage | 2.14 | 1100 | 28 | 1 | 28 |
| getSlot | 1.99 | 1126 | 26 | 3 | 8.667 |
| map | 1.91 | 1151 | 25 | 1 | 25 |
| + | 1.53 | 1171 | 20 | 4 | 5 |
| evalArgs | 1.45 | 1190 | 19 | 1 | 19 |
| + | 1.30 | 1207 | 17 | 2 | 8.500 |
| clone | 1.22 | 1223 | 16 | 1 | 16 |
| asString | 1.07 | 1237 | 14 | 2 | 7 |
| apply | 1.07 | 1251 | 14 | 2 | 7 |
| updateSlot | 0.92 | 1263 | 12 | 1 | 12 |
| lobby | 0.84 | 1274 | 11 | 4 | 2.750 |
| each| | 0.77 | 1284 | 10 | 1 | 10 |
| Lobby | 0.54 | 1291 | 7 | 4 | 1.750 |
| x | 0.46 | 1297 | 6 | 3 | 2 |
| init | 0.31 | 1301 | 4 | 1 | 4 |
| x | 0.31 | 1305 | 4 | 1 | 4 |
| args | 0.15 | 1307 | 2 | 1 | 2 |
’--------------’--------’------------’--------’---------’-----------’
)
Profile objects are not meant to be cloned as they are created by System.profile internal
machinery.
- calls
Return a List of Profile.Function objects. Each element of this list describes, for a
given function, statistics about how many times it is called and how much time is spent
in it.
- maxFunctionCallDepth
The maximum function call depth reached.
// Example continued from Construction.
profile.maxFunctionCallDepth == 5;
- Function
See Profile.Function.
- totalCalls
The total number of function calls made.
// Example continued from Construction.
profile.totalCalls == 16;
- totalTime
The total CPU time. It can be higher than the wall clock time on multi-core processors for
instance.
- wallClockTime
The time spent between the beginning and the end as if measured on a wall clock.
- yields
The scheduler has to execute many coroutines in parallel. A coroutine yields when it gives the
opportunity to an other to be executed until this one yields and so on…This slot contains the
number of scheduler yields.
// Example continued from Construction.
profile.yields == 0;
23.50 Profile.Function
A Function object contains information about calls of a given function during a profiling
operation.
Function objects are not meant to be cloned as they are created by System.profile internal
machinery.
function Float.fact()
{
if (this <= 1)
this
else
this * (this - 1).fact;
}|;
var profile = System.profile(function() { 20.fact });
[00009050] Profile(
Yields: 0
Total time (us): 171
Wall-clock time (us): 171
Function calls: 79
Max depth: 22
.-------------------------------------------------------------------.
| function | % | cumulative | self | calls | self |
| | | (us) | (us) | | (us/call) |
|--------------+--------+------------+--------+---------+-----------|
| fact | 70.18 | 120 | 120 | 20 | 6 |
| - | 10.53 | 138 | 18 | 19 | 0.947 |
| <= | 8.77 | 153 | 15 | 20 | 0.750 |
| * | 8.19 | 167 | 14 | 19 | 0.737 |
| <profiled> | 2.34 | 171 | 4 | 1 | 4 |
’--------------’--------’------------’--------’---------’-----------’
)
profile.calls[0];
[00123833] Function(’fact’, 20, 0.000120, 0.000006)
- calls
The number of times this function was called during the profiling.
// Example continued from Construction section.
profile.calls[0].calls == 20;
- name
The name of the function called.
// Example continued from Construction section.
profile.calls[0].name == "fact";
- selfTimePer
Average CPU time spent in one function call. It is computed as the ratio of selfTime divided by
calls.
// Example continued from Construction section.
do (profile.calls[0])
{
selfTimePer == selfTime / calls;
}
- selfTime
Total CPU time spent in all calls of the function.
// Example continued from Construction section.
profile.calls[0].selfTime.isA(Float);
23.51 PseudoLazy
23.52 PubSub
PubSub provides an abstraction over Barrier Barrier to queue signals for each subscriber.
A PubSub can be created with no arguments. Values can be published and read by each
subscriber.
var ps = PubSub.new;
[00000000] PubSub_0x28c1bc0
- publish(ev)
Queue the value ev to the queue of each subscriber. This method returns the value ev.
{
var sub = ps.subscribe;
assert
{
ps.publish(2) == 2;
sub.getOne == 2;
};
ps.unsubscribe(sub)
}|;
- subscribe
Create a Subscriber and insert it inside the list of subscribers.
var sub = ps.subscribe |
ps.subscribers == [sub];
[00000000] true
- Subscriber
See PubSub.Subscriber.
- subscribers
Field containing the list of Subscriber which are watching published values. This field only
exists in instances of PubSub.
- unsubscribe(sub)
Remove a subscriber from the list of subscriber watching the published values.
ps.unsubscribe(sub) |
ps.subscribers;
[00000000] []
23.53 PubSub.Subscriber
Subscriber is created by PubSub.subscribe. It provides methods to access to the list of values
published by PubSub instances.
A PubSub.Subscriber can be created with a call to PubSub.subscribe. This way of creating a
Subscriber adds the subscriber as a watcher of values published on the instance of PubSub.
var ps = PubSub.new |;
var sub = ps.subscribe;
[00000000] Subscriber_0x28607c0
- getOne
Block until a value is accessible and return it. If a value is already queued, then the method
returns it without blocking.
echo(sub.getOne) &
ps.publish(3);
[00000000] *** 3
- getAll
Block until a value is accessible. Return the list of queued values. If the values are already
queued, then return them without blocking.
ps.publish(4) |
ps.publish(5) |
echo(sub.getAll);
[00000000] *** [4, 5]
23.54 RangeIterable
This object is meant to be used as a prototype for objects that support an asList method, to use
range-based for loops (Section 22.7.5.2).
- all(fun)
Return whether all the members of the target verify the predicate fun.
// Are all elements positive?
! [-2, 0, 2, 4].all(function (e) { e > 0 });
// Are all elements even?
[-2, 0, 2, 4].all(function (e) { e % 2 == 0 });
- any(fun)
Whether at least one of the members of the target verifies the predicate fun.
// Is there any even element?
! [-3, 1, -1].any(function (e) { e % 2 == 0 });
// Is there any positive element?
[-3, 1, -1].any(function (e) { e > 0 });
- each(fun)
Apply the given functional value fun on all “members”, sequentially. Corresponds to range-for
loops.
class range : RangeIterable
{
var asList = [10, 20, 30];
}|;
for (var i : range)
echo (i);
[00000000] *** 10
[00000000] *** 20
[00000000] *** 30
- ’each&’(fun)
Apply the given functional value fun on all “members”, in parallel, starting all the computations
simultaneously. Corresponds to range-for& loops.
{
var res = [];
for& (var i : range)
res << i;
assert(res.sort == [10, 20, 30]);
};
- ’each|’(fun)Apply the given functional value fun on all “members”, with tight sequentially.
Corresponds to range-for| loops.
{
var res = [];
for| (var i : range)
res << i;
assert(res == [10, 20, 30]);
};
23.55 Regexp
A Regexp is an object which allow you to match strings with a regular expression.
A Regexp is created with the regular expression once and for all, and it can be used many times to
match with other strings.
Regexp.new(".");
[00000001] Regexp(".")
urbiscript supports Perl regular expressions, see the perlre man page.
Expressions cannot be empty.
Regexp.new("");
[00000001:error] !!! new: invalid regular expression ‘’: Empty expression
- asPrintable
A string that shows that this is a Regexp, and its value.
Regexp.new("abc").asPrintable == "Regexp(\"abc\")";
Regexp.new("\\d+(\\.\\d+)?").asPrintable == "Regexp(\"\\\\d+(\\\\.\\\\d+)?\")";
- asString
The regular expression that was compiled.
Regexp.new("abc").asString == "abc";
Regexp.new("\\d+(\\.\\d+)?").asString == "\\d+(\\.\\d+)?";
- has(str)
An experimental alias to match, so that the infix operators in and not in can be used (see
Section 22.1.8.7).
"23.03" in Regexp.new("^\\d+\\.\\d+$");
"-3.14" not in Regexp.new("^\\d+\\.\\d+$");
- match(str)
Whether this matches str.
// Ordinary characters
var r = Regexp.new("oo")|
assert
{
r.match("oo");
r.match("foobar");
!r.match("bazquux");
};
// ^, anchoring at the beginning of line.
r = Regexp.new("^oo")|
assert
{
r.match("oops");
!r.match("woot");
};
// $, anchoring at the end of line.
r = Regexp.new("oo$")|
assert
{
r.match("foo");
!r.match("mooh");
};
// *, greedy repetition, 0 or more.
r = Regexp.new("fo*bar")|
assert
{
r.match("fbar");
r.match("fooooobar");
!r.match("far");
};
// (), grouping.
r = Regexp.new("f(oo)*bar")|
assert
{
r.match("foooobar");
!r.match("fooobar");
};
- matches
If the latest match was successful, the matched groups, as delimited by parentheses in the regular
expression; the first element being the whole match. Otherwise, the empty list. See also
’[]’.
var re = Regexp.new("([a-zA-Z0-9._]+)@([a-zA-Z0-9._]+)")|;
assert
{
re.match("Someone <someone@somewhere.com>");
re.matches == ["someone@somewhere.com", "someone", "somewhere.com"];
"does not match" not in re;
re.matches == [];
};
- ’[]’(n)
Same as this.matches[n].
var d = Regexp.new("(1+)(2+)(3+)")|;
assert
{
"01223334" in d;
d[0] == "122333";
d[1] == "1";
d[2] == "22";
d[3] == "333";
};
d[4];
[00000009:error] !!! []: out of bound index: 4
23.56 Semaphore
Semaphore are useful to limit the number of access to a limited number of resources.
A Semaphore can be created with as argument the number of processes allowed to enter critical
sections at the same time.
Semaphore.new(1);
[00000000] Semaphore_0x8c1e80
- criticalSection(function() { code })
Put the piece of code inside a critical section which can be executed simultaneously at
most the number of time given at the creation of the Semaphore. This method is similar
to a call to acquire and a call to release when the code ends by any means.
{
var s = Semaphore.new(1);
for& (var i : [0, 1, 2, 3])
{
s.criticalSection(function () {
echo("start " + i);
echo("end " + i);
})
}
};
[00000000] *** start 0
[00000000] *** end 0
[00000000] *** start 1
[00000000] *** end 1
[00000000] *** start 2
[00000000] *** end 2
[00000000] *** start 3
[00000000] *** end 3
{
var s = Semaphore.new(2);
for& (var i : [0, 1, 2, 3])
{
s.criticalSection(function () {
echo("start " + i);
// Illustrate that processes can be intertwined
sleep(i * 100ms);
echo("end " + i);
})
}
};
[00000000] *** start 0
[00000000] *** start 1
[00000000] *** end 0
[00000000] *** start 2
[00000000] *** end 1
[00000000] *** start 3
[00000000] *** end 2
[00000000] *** end 3
- acquire
Wait to enter a critical section delimited by the execution of acquire and release. Enter
the critical section when the number of processes inside it goes below the maximum
allowed.
- p
Historical synonym for acquire.
- release
Leave a critical section delimited by the execution of acquire and release.
{
var s = Semaphore.new(1);
for& (var i : [0, 1, 2, 3])
{
s.acquire;
echo("start " + i);
echo("end " + i);
s.release;
}
};
[00000000] *** start 0
[00000000] *** end 0
[00000000] *** start 1
[00000000] *** end 1
[00000000] *** start 2
[00000000] *** end 2
[00000000] *** start 3
[00000000] *** end 3
- v
Historical synonym for release.
23.57 Server
A Server can listen to incoming connections. See Socket for an example.
A Server is constructed with no argument. At creation, a new Server has its own slot connection.
This slot is an event that is launched when a connection establishes.
var s = Server.new|
s.localSlotNames;
[00000001] ["connection"]
- connection
The event launched at each incoming connection. This event is launched with one argument: the
socket of the established connection. This connection uses the same IoService as the server.
at (s.connection?(var socket))
{
// This code is run at each connection. ’socket’ is the incoming
// connection.
};
- getIoService
Return the IoService used by this socket. Only the default IoService is automatically
polled.
- host
The host on which this is listening. Raise an error if this is not listening.
Server.host;
[00000003:error] !!! host: server not listening
- listen(host, port)
Listen incoming connections with host and port.
- port
The port on which this is listening. Raise an error if this is not listening.
Server.port;
[00000004:error] !!! port: server not listening
- sockets
The list of the sockets created at each incoming connection.
23.58 Singleton
A singleton is a prototype that cannot be cloned. All prototypes derived of Singleton are also
singletons.
To be a singleton, the object must have Singleton as a prototype. The common way to do this is
var s = Singleton.new, but this does not work : s is not a new singleton, it is the Singleton itself
since it cannot be cloned. There are two other ways:
// Defining a new class and specifying Singleton as a parent.
class NewSingleton1: Singleton
{
var asString = "NewSingleton1";
}|
var s1 = NewSingleton1.new;
[00000001] NewSingleton1
assert(s1 === NewSingleton1);
assert(NewSingleton1 !== Singleton);
// Create a new Object and set its prototype by hand.
var NewSingleton2 = Object.new|
var NewSingleton2.asString = "NewSingleton2"|
NewSingleton2.protos = [Singleton]|
var s2 = NewSingleton2.new;
[00000001] NewSingleton2
assert(s2 === NewSingleton2);
assert(NewSingleton2 !== Singleton);
- clone
Return this.
- ’new’
Return this.
23.59 Socket
A Socket can manage asynchronous input/output network connections.
The following example demonstrates how both the Server and Socket object work.
This simple example will establish a dialog between server and client. The following
object, Dialog, contains the script of this exchange. It is put into Global so that both
the server and client can read it. Dialog.reply(var s) returns the reply to a message
s.
class Global.Dialog
{
var lines =
[
"Hi!",
"Hey!",
"Hey you doin’?",
"Whazaaa!",
"See ya.",
]|;
function reply(var s)
{
for (var i: lines.size - 1)
if (s == lines[i])
return lines[i + 1];
"off";
}
}|;
The server, an instance of Server, expects incoming connections, notified by the socket’s
connection? event. Once the connection establish, it listens to the socket for incoming messages,
notified by the received? event. Its reaction to this event is to send the following line of the dialog. At
the end of the dialog, the socket is disconnected.
var server =
do (Server.new)
{
at (connection?(var socket))
at (socket.received?(var data))
{
var reply = Dialog.reply(data);
socket.write(reply);
echo("server: " + reply);
if (reply == "off")
socket.disconnect;
};
}|;
The client, an instance of Socket expects incoming messages, notified by the received? event. Its
reaction is to send the following line of the dialog.
var client =
do (Socket.new)
{
at (received?(var data))
{
var reply = Dialog.reply(data);
write(reply);
echo("client: " + reply);
};
}|;
As of today, urbiscript’s socket machinery requires to be regularly polled.
every (100ms)
Socket.poll,
The server is then activated, listening to incoming connections on a port that will be chosen by the
system among the free ones.
server.listen("localhost", "0");
clog << "connecting to %s:%s" % [server.host, server.port];
The client connects to the server, and initiates the dialog.
client.connect(server.host, server.port);
echo("client: " + Dialog.lines[0]);
client.write(Dialog.lines[0]);
[00000003] *** client: Hi!
Because this dialog is asynchronous, the easiest way to wait for the dialog to finish is to wait for
the disconnected? event.
waituntil(client.disconnected?);
[00000004] *** server: Hey!
[00000005] *** client: Hey you doin’?
[00000006] *** server: Whazaaa!
[00000007] *** client: See ya.
[00000008] *** server: off
A Socket is constructed with no argument. At creation, a new Socket has four own slots: connected,
disconnected, error and received.
- connect(host, port)
Connect this to host and port. The port can be either an integer, or a string that denotes
symbolic ports, such as "smtp", or "ftp" and so forth.
- connected
Event launched when the connection is established.
- connectSerial(device, baudRate)
Connect this to the serial port device, with given baudRate.
- disconnect
Close the connection.
- disconnected
Event launched when a disconnection happens.
- error
Event launched when an error happens. This event is launched with the error message in
argument. The event disconnected is also always launched.
- getIoService
Return the IoService used by this socket. Only the default IoService is automatically
polled.
- host
The remote host of the connection.
- isConnected
Whether this is connected.
- localHost
The local host of the connection.
- localPort
The local port of the connection.
- poll
Call getIoService.poll(). This method is called regularly every pollInterval on the
Socket object. You do not need to call this function on your sockets unless you use your
own IoService.
- pollInterval
Each pollInterval amount of time, poll is called. If pollInterval equals zero, poll is
not called.
- port
The remote port of the connection.
- received
Event launched when this has received data. The data is given by argument to the event.
- write(data)
Sends data trough the connection.
- syncWrite(data)
Similar to write, but forces the operation to complete synchronously. Synchronous and
asynchronous write operations cannot be mixed.
23.60 StackFrame
This class is meant to record backtrace (see Exception.backtrace) information.
For convenience, all snippets of code are supposed to be run after these function definitions. In this
code, the getStackFrame function is used to get the first StackFrame of an exception backtrace.
Backtrace of Exception are filled with StackFrames when the is thrown.
//#push 1 "foo.u"
function inner () { throw Exception.new("test") }|;
function getStackFrame()
{
try
{
inner
}
catch(var e)
{
e.backtrace[0]
};
}|;
//pop
This feature is experimental. It might be changed in the future. Feedback on its use
would be appreciated.
StackFrame are not made to be manually constructed. The initialization function expect 2
arguments, which are the name of the called function and the Location from which it has been
called.
StackFrame.new("inner",
Location.new(
Position.new("foo.u", 7, 5),
Position.new("foo.u", 7, 10)
)
);
[00000001] foo.u:7.5-9: inner
- name
String, representing the name of the called function.
getStackFrame.name;
[00000002] "inner"
- location
Location of the function call.
getStackFrame.location;
[00000003] foo.u:7.5-9
- asString
Clean display of the call location.
getStackFrame;
[00000004] foo.u:7.5-9: inner
23.61 Stream
This is used to factor code between InputStream and OutputStream.
Streams are not meant to be built, rather, use InputStream or OutputStream.
When a stream (OutputStream or InputStream) is opened on a File, that File cannot be removed.
On Unix systems, this is handled gracefully (the references to the file are removed, but the content is
still there for the streams that were already bound to this file); so in practice, the File appears to be
removable. On Windows, the File cannot be removed at all. Therefore, do not forget to close the
streams you opened.
- close
Flush the buffers, close the stream, return void. Raise an error if the file is closed.
{
var i = InputStream.new(File.create("file.txt"));
assert(i.close.isVoid);
i.close;
};
[00000001:error] !!! close: stream is closed
{
var o = OutputStream.new(File.create("file.txt"));
assert(o.close.isVoid);
o.close;
};
[00000002:error] !!! close: stream is closed
23.62 String
A string is a sequence of characters.
Fresh Strings can easily be built using the literal syntax. Several escaping sequences (the traditional
ones and urbiscript specific ones) allow to insert special characters. Consecutive string literals are
merged together. See Section 22.1.6.6 for details and examples.
A null String can also be obtained with String’s new method.
String.new == "";
String == "";
"123".new == "123";
- asFloat
If the whole content of this is an number, return it as a Float, otherwise raise an error.
assert
{
"23".asFloat == 23;
"23.03".asFloat == 23.03;
};
"123abc".asFloat;
[00000001:error] !!! asFloat: cannot convert to float: "123abc"
- asList
Return a List of one-letter Strings that, concatenated, equal this. This allows to use for to
iterate over the string.
assert("123".asList == ["1", "2", "3"]);
for (var v : "123")
echo(v);
[00000001] *** 1
[00000001] *** 2
[00000001] *** 3
- asPrintable
Return this as a literal (escaped) string.
"foo".asPrintable == "\"foo\"";
"foo".asPrintable.asPrintable == "\"\\\"foo\\\"\"";
- asString
Return this.
"\"foo\"".asString == "\"foo\"";
- closest(set)
Return the string in set that is the closest (in the sense of distance) to this. If there is no
convincing match, return nil.
"foo".closest(["foo", "baz", "qux", "quux"]) == "foo";
"bar".closest(["foo", "baz", "qux", "quux"]) == "baz";
"FOO".closest(["foo", "bar", "baz"]) == "foo";
"qux".closest(["foo", "bar", "baz"]) == nil;
- distance(other)
Return the Damerau-Levenshtein distance between this and other. The more alike the strings
are, the smaller the distance is.
"foo".distance("foo") == 0;
"bar".distance("baz") == 1;
"foo".distance("bar") == 3;
- empty
Whether this is the empty string.
- fresh
Return a String that has never been used as an identifier, prefixed by this. It can safely be used
with Object.setSlot and so forth.
String.fresh == "_5";
"foo".fresh == "foo_6";
- fromAscii(v)
The character corresponding to the integer v according to the ASCII coding. See also toAscii.
String.fromAscii( 97) == "a";
String.fromAscii( 98) == "b";
String.fromAscii(0xFF) == "\xff";
[0, 1, 2, 254, 255]
.map(function (var v) { String.fromAscii(v) })
.map(function (var v) { v.toAscii })
== [0, 1, 2, 254, 255];
- hash
A Hash object corresponding to this string value. Two string hashes are equal if the string are
equal. See Object.hash.
"".hash.isA(Hash);
"foo".hash == "foo".hash;
"foo".hash != "bar".hash;
- Character handling functions
Here is a map of how the original 127-character ASCII set is considered by each function (a ∙
indicates that the function returns true if all characters of this are on the row).
|
|
|
|
|
|
|
|
|
|
|
|
|
| | | | | | | | | | | | | |
| ASCII values | Characters | iscntrl | isspace | isupper | islower | isalpha | isdigit | isxdigit | isalnum | ispunct | isgraph | print |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x00 .. 0x08 | | ∙ | | | | | | | | | | |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x09 .. 0x0D | ∖t, ∖f, ∖v, ∖n, ∖r | ∙ | ∙ | | | | | | | | | |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x0E .. 0x1F | | ∙ | | | | | | | | | | |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x20 | space (’ ’) | | ∙ | | | | | | | | | ∙ |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x21 .. 0x2F | !"#$%&’()*+,-./ | | | | | | | | | ∙ | ∙ | ∙ |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x30 .. 0x39 | 0-9 | | | | | | ∙ | ∙ | ∙ | | ∙ | ∙ |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x3a .. 0x40 | :;<=>?@ | | | | | | | | | ∙ | ∙ | ∙ |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x41 .. 0x46 | A-F | | | ∙ | | ∙ | | ∙ | ∙ | | ∙ | ∙ |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x47 .. 0x5A | G-Z | | | ∙ | | ∙ | | | ∙ | | ∙ | ∙ |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x5B .. 0x60 | [\]^{}_‘ | | | | | | | | | ∙ | ∙ | ∙ |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x61 .. 0x66 | a-f | | | | ∙ | ∙ | | ∙ | ∙ | | ∙ | ∙ |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x67 .. 0x7A | g-z | | | | ∙ | ∙ | | | ∙ | | ∙ | ∙ |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x7B .. 0x7E | {|}~ | | | | | | | | | ∙ | ∙ | ∙ |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 0x7F | (DEL) | ∙ | | | | | | | | | | |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
"".isDigit;
"0123456789".isDigit;
!"a".isDigit;
"".isLower;
"lower".isLower;
! "Not Lower".isLower;
"".isUpper;
"UPPER".isUpper;
! "Not Upper".isUpper;
- join(list, prefix, suffix)
Glue the result of asString applied to the members of list, separated by this, and embedded
in a pair prefix/suffix.
"|".join([1, 2, 3], "(", ")") == "(1|2|3)";
", ".join([1, [2], "3"], "[", "]") == "[1, [2], 3]";
- length
The number of characters in the string. Currently, this is a synonym of size.
"foo".length == 3;
"".length == 0;
- replace(from, to)
Replace every occurrence of the string from in this by to, and return the result. this is not
modified.
"Hello, World!".replace("Hello", "Bonjour")
.replace("World!", "Monde !") ==
"Bonjour, Monde !";
- size
The size of the string.
"foo".size == 3;
"".size == 0;
- split(sep = [" ", "\t", "\n", "\r"], lim = -1, keepSep = false, keepEmpty = true)
Split this on the separator sep, in at most lim components, which include the separator if
keepSep, and the empty components of keepEmpty. Return a list of strings.
The separator, sep, can be a string.
"a,b;c".split(",") == ["a", "b;c"];
"a,b;c".split(";") == ["a,b", "c"];
"foobar".split("x") == ["foobar"];
"foobar".split("ob") == ["fo", "ar"];
It can also be a list of strings.
"a,b;c".split([",", ";"]) == ["a", "b", "c"];
By default splitting is performed on white-spaces:
" abc def\tghi\n".split == ["abc", "def", "ghi"];
Splitting on the empty string stands for splitting between each character:
"foobar".split("") == ["f", "o", "o", "b", "a", "r"];
The limit lim indicates a maximum number of splits that can occur. A negative number
corresponds to no limit:
"a:b:c".split(":", 1) == ["a", "b:c"];
"a:b:c".split(":", -1) == ["a", "b", "c"];
keepSep indicates whether to keep delimiters in the result:
"aaa:bbb;ccc".split([":", ";"], -1, false) == ["aaa", "bbb", "ccc"];
"aaa:bbb;ccc".split([":", ";"], -1, true) == ["aaa", ":", "bbb", ";", "ccc"];
keepEmpty indicates whether to keep empty elements:
"foobar".split("o") == ["f", "", "bar"];
"foobar".split("o", -1, false, true) == ["f", "", "bar"];
"foobar".split("o", -1, false, false) == ["f", "bar"];
- toAscii
Convert the first character of this to its integer value in the ASCII coding. See also fromAscii.
"a".toAscii == 97;
"b".toAscii == 98;
"\xff".toAscii == 0xff;
"Hello, World!\n"
.asList
.map(function (var v) { v.toAscii })
.map(function (var v) { String.fromAscii(v) })
.join
== "Hello, World!\n";
- toLower
Make lower case every upper case character in this and return the result. this is not modified.
"Hello, World!".toLower == "hello, world!";
- toUpper
Make upper case every lower case character in this and return the result. this is not modified.
"Hello, World!".toUpper == "HELLO, WORLD!";
- ’==’(that)
Whether this and that are the same string.
"" == ""; !("" != "");
!("" == "\0"); "" != "\0";
"0" == "0"; !("0" != "0");
!("0" == "1"); "0" != "1";
!("1" == "0"); "1" != "0";
- ’%’(args)
It is an equivalent of Formatter.new(this) % args. See Formatter.
"%s + %s = %s" % [1, 2, 3] == "1 + 2 = 3";
- ’*’(n)
Concatenate thisn times.
"foo" * 0 == "";
"foo" * 1 == "foo";
"foo" * 3 == "foofoofoo";
- ’+’(other)
Concatenate this and other.asString.
"foo" + "bar" == "foobar";
"foo" + "" == "foo";
"foo" + 3 == "foo3";
"foo" + [1, 2, 3] == "foo[1, 2, 3]";
- ’<’(other)
Whether this is lexicographically before other, which must be a String.
"" < "a";
!("a" < "");
"a" < "b";
!("a" < "a");
- ’[]’(from)
’[]’(from, to)
Return the sub-string starting at from, up to and not including to (which defaults to to + 1).
"foobar"[0, 3] == "foo";
"foobar"[0] == "f";
- ’[]=’(from, other)
’[]=’(from, to, other)
Replace the sub-string starting at from, up to and not including to (which defaults to to + 1),
by other. Return other.
Beware that this routine is imperative: it changes the value of this.
var s1 = "foobar" | var s2 = s1 |
assert((s1[0, 3] = "quux") == "quux");
assert(s1 == "quuxbar");
assert(s2 == "quuxbar");
assert((s1[4, 7] = "") == "");
assert(s2 == "quux");
23.63 System
Details on the architecture the Urbi server runs on.
- _exit(status)
Shut the server down brutally: the connections are not closed, and the resources are not
explicitly released (the operating system reclaims most of them: memory, file descriptors
and so forth). Architecture dependent.
- aliveJobs
The number of detached routines currently running.
{
var nJobs = aliveJobs;
for (var i: [1s, 2s, 3s])
detach({sleep(i)});
sleep(0.5s);
assert(aliveJobs - nJobs == 3);
sleep(1s);
assert(aliveJobs - nJobs == 2);
sleep(1s);
assert(aliveJobs - nJobs == 1);
sleep(1s);
assert(aliveJobs - nJobs == 0);
};
- arguments
The list of the command line arguments passed to the user script. This is especially useful in
scripts.
$ cat >echo <<EOF
#! /usr/bin/env urbi
System.arguments;
shutdown;
EOF
$ chmod +x echo
$ ./echo 1 2 3
[00000172] ["1", "2", "3"]
$ ./echo -x 12 -v "foo"
[00000172] ["-x", "12", "-v", "foo"]
- ’assert’(assertion)
Unless ndebug is true, throw an error if assertion is not verified. See also the assertion support
in urbiscript, Section 22.9.
’assert’(true);
’assert’(42);
’assert’(1 == 1 + 1);
[00000002:error] !!! failed assertion: 1.’==’(1.’+’(1))
- assert_(assertion, message)
If assertion does not evaluate to true, throw the failure message.
assert_(true, "true failed");
assert_(42, "42 failed");
assert_(1 == 1 + 1, "one is not two");
[00000001:error] !!! failed assertion: one is not two
- assert_op(operator, lhs, rhs)
Deprecated, use assert instead, see Section 22.9.
- backtrace
Display the call stack on the channel backtrace.
This feature is experimental. It might be changed in the future. Feedback on its
use would be appreciated.
//#push 100 "foo.u"
function innermost () { backtrace }|;
function inner () { innermost }|;
function outer () { inner }|;
function outermost () { outer }|;
outermost;
[00000013:backtrace] innermost (foo.u:101.25-33)
[00000014:backtrace] inner (foo.u:102.25-29)
[00000015:backtrace] outer (foo.u:103.25-29)
[00000016:backtrace] outermost (foo.u:104.1-9)
//#pop
- cycle
The number of execution cycles since the beginning.
This feature is experimental. It might be changed in the future. Feedback on its
use would be appreciated.
{
var first = cycle ; var second = cycle ;
assert(first + 1 == second);
first = cycle | second = cycle ;
assert(first == second);
};
- eval(source, target = this)
Evaluate the urbiscriptsource, and return its result. See also loadFile. The source must be
complete, yet the terminator (e.g., ‘;’) is not required.
eval("1+2") == 1+2;
eval("\"x\" * 10") == "x" * 10;
eval("eval(\"1\")") == 1;
eval("{ var x = 1; x + x; }") == 2;
The evaluation is performed in the context of the current object (this) or target if specified. In
particular, to create local variables, create scopes.
// Create a slot in the current object.
eval("var a = 23;") == 23;
this.a == 23;
eval("var a = 3", Global) == 3;
Global.a == 3;
Exceptions are thrown on error (including syntax errors).
eval("1/0");
[00008316:error] !!! 1.1-3: /: division by 0
[00008316:error] !!! called from: eval
try
{
eval("1/0")
}
catch (var e)
{
assert
{
e.isA(Exception.Primitive);
e.location.asString == "1.1-3";
e.routine == "/";
e.message == "division by 0";
}
};
Warnings are reported.
eval("new Object");
[00001388:warning] !!! 1.1-10: ‘new Obj(x)’ is deprecated, use ‘Obj.new(x)’
[00001388:warning] !!! called from: eval
[00001388] Object_0x1001b2320
Nested calls to eval behave as expected. The locations in the inner calls refer to the position
inside the evaluated string.
eval("/");
[00001028:error] !!! 1.1: syntax error: unexpected /
[00001028:error] !!! called from: eval
eval("eval(\"/\")");
[00001032:error] !!! 1.1: syntax error: unexpected /
[00001032:error] !!! called from: 1.1-9: eval
[00001032:error] !!! called from: eval
eval("eval(\"eval(\\\"/\\\")\")");
[00001035:error] !!! 1.1: syntax error: unexpected /
[00001035:error] !!! called from: 1.1-9: eval
[00001035:error] !!! called from: 1.1-19: eval
[00001035:error] !!! called from: eval
- getenv(name)
The value of the environment variable name as a String if set, nil otherwise. See also setenv
and unsetenv.
getenv("UndefinedEnvironmentVariable").isNil;
!getenv("PATH").isNil;
- load(file, target = this)
Look for file in the Urbi path (Section 21.1), and load it in the context of target. See also
loadFile. Throw a Exception.FileNotFound error if the file cannot be found. Return the last
value of the file.
// Create the file ‘‘123.u’’ that contains exactly ‘‘var t = 123;’’.
File.save("123.u", "var t = 123;");
assert
{
load("123.u") == 123;
this.t == 123;
load("123.u", Global) == 123;
Global.t == 123;
};
- loadFile(file, target = this)
Load the urbiscript file file in the context of target. Behaves like eval applied to the content
of file. Throw a Exception.FileNotFound error if the file cannot be found. Return the last
value of the file.
// Create the file ‘‘123.u’’ that contains exactly ‘‘var y = 123;’’.
File.save("123.u", "var y = 123;");
assert
{
loadFile("123.u") == 123;
this.y == 123;
loadFile("123.u", Global) == 123;
Global.y == 123;
};
- loadLibrary(library)
Load the library library, to be found in UObject.searchPath. The library may be a String
or a Path. The C++ symbols are made available to the other C++ components. See also
loadModule.
- loadModule(module)
Load the UObjectmodule. Same as loadLibrary, except that the low-level C++ symbols are not
made “global” (in the sense of the shared library loader).
- lobbies
Bounce to Lobby.instances.
- lobby
Bounce to Lobby.lobby.
- maybeLoad(file, channel = Channel.null)
Look for file in the Urbi path (Section 21.1). If the file is found announce on Channel that
file is about to be loaded, and load it.
// Create the file ‘‘123.u’’ that contains exactly ‘‘123;’’.
File.save("123.u", "123;");
assert
{
maybeLoad("123.u") == 123;
maybeLoad("u.123").isVoid;
};
- ndebug
If true, do not evaluate the assertions. See Section 22.9.
function one() { echo("called!"); 1 }|;
assert(!System.ndebug);
assert(one);
[00000617] *** called!
// Beware of copy-on-write.
System.ndebug = true|;
assert(one);
System.ndebug = false|;
assert(one);
[00000622] *** called!
- PackageInfo
See System.PackageInfo.
- period
The period of the Urbi kernel. Influences the trajectories (TrajectoryGenerator), and the
UObject monitoring. Defaults to 20ms.
- Platform
See System.Platform.
- profile(function)
Compute some measures during the execution of function and return the results
as a Profile object. A Profile details information about time, function calls and
scheduling.
- programName
The path under which the Urbi process was called. This is typically ‘.../urbi’ (Section 21.3) or
‘.../urbi-launch’ (Section 21.5).
Path.new(System.programName).basename
in ["urbi", "urbi.exe", "urbi-launch", "urbi-launch.exe"];
- reboot
Restart the Urbi server. Architecture dependent.
- redefinitionMode
Switch the current job in redefinition mode until the end of the current scope. While in
redefinition mode, setSlot on already existing slots will overwrite the slot instead of
erring.
var Global.x = 0;
[00000001] 0
{
System.redefinitionMode;
// Not an error
var Global.x = 1;
echo(Global.x);
};
[00000002] *** 1
// redefinitionMode applies only to the scope.
var Global.x = 0;
[00000003:error] !!! slot redefinition: x
- requireFile(file, target)
Load file in the context of target if it was not loaded before (with load or requireFile).
Unlike load, requireFile always returns void. If file is being loaded concurrently
requireFile waits until the loading is finished.
// Create the file ‘‘test.u’’ that echoes a string.
File.save("test1.u", "echo(\"test 1\"); 1;");
requireFile("test1.u");
[00000001] *** test 1
requireFile("test1.u");
// File is not re-loaded
File.save("test2.u", "echo(\"test 2\"); 2;");
load("test2.u");
[00000004] *** test 2
[00000004] 2
requireFile("test2.u");
load("test2.u");
[00000006] *** test 2
[00000006] 2
The target is not taken into account to check whether the file has already been loaded: if you
require twice the same file with two different targets, it will be loaded only for the
first.
requireFile("test2.u", Global);
- resetStats
Reinitialize the stats computation.
0 < System.stats["cycles"];
System.resetStats.isVoid;
1 == System.stats["cycles"];
- scopeTag
Bounce to Tag.scope.
- searchFile(file)
Look for file in the searchPath and return its Path. Throw a Exception.FileNotFound error
if the file cannot be found.
// Create the file ‘‘123.u’’ that contains exactly ‘‘123;’’.
File.save("123.u", "123;");
assert
{
searchFile("123.u") == Path.cwd / Path.new("123.u");
};
- searchPath
The Urbi path (i.e., the directories where the urbiscript files are looked for, see Section 21.1) as a
List of Paths.
System.searchPath.isA(List);
System.searchPath[0].isA(Path);
- setenv(name, value)
Set the environment variable name to value.asString, and return this value. See also getenv
and unsetenv.
Windows Issues
Under Windows, setting to an empty value is equivalent to making undefined.
setenv("MyVar", 12) == "12";
getenv("MyVar") == "12";
// A child process that uses the environment variable.
System.system("exit $MyVar") >> 8 ==
{if (Platform.isWindows) 0 else 12};
setenv("MyVar", 23) == "23";
System.system("exit $MyVar") >> 8 ==
{if (Platform.isWindows) 0 else 23};
// Defining to empty is defining, unless you are on Windows.
setenv("MyVar", "") == "";
getenv("MyVar").isNil == Platform.isWindows;
- shiftedTime
Return the number of seconds elapsed since the Urbi server was launched. Contrary to time,
time spent in frozen code is not counted.
{ var t0 = shiftedTime | sleep(1s) | shiftedTime - t0 }.round ∼= 1;
1 ==
{
var t = Tag.new|;
var t0 = time|;
var res;
t: { sleep(1s) | res = shiftedTime - t0 },
t.freeze;
sleep(1s);
t.unfreeze;
sleep(1s);
res.round;
};
- shutdown
Have the Urbi server shut down. All the connections are closed, the resources are released.
Architecture dependent.
- sleep(duration = inf)
Suspend the execution for duration seconds. No CPU cycle is wasted during this wait. If no
duration is given the execution is suspended indefinitely.
(time - {sleep(1s); time}).round == -1;
- spawn(function, clear)
Run the function, with fresh tags if clear is true, otherwise under the control of the current
tags. Return the spawn Job.
var jobs = []|;
var res = []|;
for (var i : [0, 1, 2])
{
jobs << System.spawn(closure () { res << i; res << i },
true) |
if (i == 2)
break
}|
jobs;
[00009120] [Job<shell_11>, Job<shell_12>, Job<shell_13>]
// Wait for the jobs to be done.
jobs.each (function (var j) { j.waitForTermination });
assert (res == [0, 1, 0, 2, 1, 2]);
jobs = []|;
res = []|;
for (var i : [0, 1, 2])
{
jobs << System.spawn(closure () { res << i; res << i },
false) |
if (i == 2)
break
}|
jobs;
[00009120] [Job<shell_14>, Job<shell_15>, Job<shell_16>]
// Give some time to get the output of the detached expressions.
sleep(100ms);
assert (res == [0, 1, 0]);
- stats
Return a Dictionary containing information about the execution cycles of Urbi. This is an
internal feature made for developers, it might be changed without notice. See also resetStats.
var stats = System.stats|;
assert
{
stats.isA(Dictionary);
stats.keys.sort == ["cycles",
"cyclesMin", "cyclesMean", "cyclesMax",
"cyclesVariance", "cyclesStdDev"].sort;
0 < stats["cycles"];
stats["cyclesMin"] <= stats["cyclesMean"];
stats["cyclesMean"] <= stats["cyclesMax"];
};
- system(command)
Ask the operating system to run the command. This is typically used to start new processes. The
exact syntax of command depends on your system. On Unix systems, this is typically ‘/bin/sh’,
while Windows uses ‘command.exe’.
Return the exit status.
Windows Issues
Under Windows, the exit status is always 0.
System.system("exit 0") == 0;
System.system("exit 23") >> 8
== { if (System.Platform.isWindows) 0 else 23 };
- time
Return the number of seconds elapsed since the Urbi server was launched. In presence of a frozen
Tag, see also shiftedTime.
{ var t0 = time | sleep(1s) | time - t0 }.round ∼= 1;
2 ==
{
var t = Tag.new|;
var t0 = time|;
var res;
t: { sleep(1s) | res = time - t0 },
t.freeze;
sleep(1s);
t.unfreeze;
sleep(1s);
res.round;
};
- timeReference
The “origin of time” of this run of Urbi, as a Date. It is a constant during the run.
Basically, System.time is about Date.now - System.timeReference. See also time and
Date.now.
var t1 = System.timeReference|;
sleep(1s);
var t2 = System.timeReference|;
assert
{
t1 == t2;
t1.isA(Date);
(Date.now - (System.timeReference + System.time)) < 0.5s;
};
- unsetenv(name)
Undefine the environment variable name, return its previous value. See also getenv and
setenv.
setenv("MyVar", 12) == "12";
!getenv("MyVar").isNil;
unsetenv("MyVar") == "12";
getenv("MyVar").isNil;
- version
The version of Urbi SDK. A string composed of two or more numbers separated by periods:
‘"2.7.5"’.
System.version in Regexp.new("\\d+(\\.\\d+)+");
23.64 System.PackageInfo
Information about Urbi SDK and its components.
- copyrightHolder
The Urbi SDK copyright holder.
System.PackageInfo.copyrightHolder == "Gostai S.A.S.";
- copyrightYears
The Urbi SDK copyright years.
System.PackageInfo.copyrightYears == "2004-2012";
23.65 System.Platform
A description of the platform (the computer) the server is running on.
- host
The type of system Urbi SDK runs on. Composed of the CPU, the vendor, and the OS.
System.Platform.host ==
"%s-%s-%s" % [System.Platform.hostCpu,
System.Platform.hostVendor,
System.Platform.hostOs];
- hostAlias
The name of the system Urbi SDK runs on as the person who compiled it decided to name it.
Typically empty, it is fragile to depend on it.
System.Platform.hostAlias.isA(String);
- hostCpu
The CPU type of system Urbi SDK runs on. The following values are those for which Gostai
provides binary builds.
System.Platform.hostCpu in ["i386", "i686", "x86_64"];
- hostOs
The OS type of system Urbi SDK runs on. For instance darwin9.8.0 or linux-gnu or
mingw32.
- hostVendor
The vendor type of system Urbi SDK runs on. The following values are those for which Gostai
provides binary builds.
System.Platform.hostVendor in ["apple", "pc", "unknown"];
- isWindows
Whether running under Windows.
System.Platform.isWindows in [true, false];
- kind
Either "POSIX" or "WIN32".
System.Platform.kind in ["POSIX", "WIN32"];
23.66 Tag
A tag is an object meant to label blocks of code in order to control them externally. Tagged code
can be frozen, resumed, stopped…See also Section 13.3.
23.66.1.1 Stop
To stop a tag means to kill all the code currently running that it labels. It does not affect
“newcomers”.
var t = Tag.new|;
var t0 = time|;
t: every(1s) echo("foo"),
sleep(2.2s);
[00000158] *** foo
[00001159] *** foo
[00002159] *** foo
t.stop;
// Nothing runs.
sleep(2.2s);
t: every(1s) echo("bar"),
sleep(2.2s);
[00000158] *** bar
[00001159] *** bar
[00002159] *** bar
t.stop;
Tag.stop can be used to inject a return value to a tagged expression.
var t = Tag.new|;
var res;
detach(res = { t: every(1s) echo("computing") })|;
sleep(2.2s);
[00000001] *** computing
[00000002] *** computing
[00000003] *** computing
t.stop("result");
assert(res == "result");
Be extremely cautious, the precedence rules can be misleading: var = tag: exp is read as
(var = tag): exp (i.e., defining var as an alias to tag and using it to tag exp), not as
var = { tag: exp }. Contrast the following example, which is most probably an error from the user,
with the previous, correct, one.
var t = Tag.new("t")|;
var res;
res = t: every(1s) echo("computing"),
sleep(2.2s);
[00000001] *** computing
[00000002] *** computing
[00000003] *** computing
t.stop("result");
assert(res == "result");
[00000004:error] !!! failed assertion: res == "result" (Tag<t> != "result")
To block a tag means:
- Stop running pieces of code it labels (as with stop).
- Ignore new pieces of code it labels (this differs from stop).
One can unblock the tag. Contrary to freeze/unfreeze, tagged code does not resume the
execution.
var ping = Tag.new("ping")|;
ping:
every (1s)
echo("ping"),
assert(!ping.blocked);
sleep(2.1s);
[00000000] *** ping
[00002000] *** ping
[00002000] *** ping
ping.block;
assert(ping.blocked);
ping:
every (1s)
echo("pong"),
// Neither new nor old code runs.
ping.unblock;
assert(!ping.blocked);
sleep(2.1s);
// But we can use the tag again.
ping:
every (1s)
echo("ping again"),
sleep(2.1s);
[00004000] *** ping again
[00005000] *** ping again
[00006000] *** ping again
As with stop, one can force the value of stopped expressions.
{
var t = Tag.new;
var res = [];
for (3)
detach(res << {t: sleep});
t.block("foo");
res;
}
==
["foo", "foo", "foo"];
To freeze a tag means holding the execution of code it labels. This applies to code already being run,
and “arriving” pieces of code.
var t = Tag.new|;
var t0 = time|;
t: every(1s) echo("time : %.0f" % (time - t0)),
sleep(2.2s);
[00000158] *** time : 0
[00001159] *** time : 1
[00002159] *** time : 2
t.freeze;
assert(t.frozen);
t: every(1s) echo("shifted: %.0f" % (shiftedTime - t0)),
sleep(2.2s);
// The tag is frozen, nothing is run.
// Unfreeze the tag: suspended code is resumed.
// Note the difference between "time" and "shiftedTime".
t.unfreeze;
assert(!t.frozen);
sleep(2.2s);
[00004559] *** shifted: 2
[00005361] *** time : 5
[00005560] *** shifted: 3
[00006362] *** time : 6
[00006562] *** shifted: 4
Scopes feature a scopeTag, i.e., a tag which will be stopped when the execution reaches the end of
the current scope. This is handy to implement cleanups, however the scope was exited
from.
{
var t = scopeTag;
t: every(1s)
echo("foo"),
sleep(2.2s);
};
[00006562] *** foo
[00006562] *** foo
[00006562] *** foo
{
var t = scopeTag;
t: every(1s)
echo("bar"),
sleep(2.2s);
throw 42;
};
[00006562] *** bar
[00006562] *** bar
[00006562] *** bar
[00006562:error] !!! 42
sleep(2s);
Tags provide two events, enter and leave, that trigger whenever flow control enters or leaves tagged
statements.
var t = Tag.new("t");
[00000000] Tag<t>
at (t.enter?)
echo("enter");
at (t.leave?)
echo("leave");
t: {echo("inside"); 42};
[00000000] *** enter
[00000000] *** inside
[00000000] *** leave
[00000000] 42
This feature is fundamental; it is a concise and safe way to ensure code will be executed upon
exiting a chunk of code (like raii in C++ or finally in Java). The exit code will be run no matter
what the reason for leaving the block was: natural exit, exceptions, flow control statements like return
or break, …
For instance, suppose we want to make sure we turn the gas off when we’re done cooking. Here is
the bad way to do it:
{
function cook()
{
turnGasOn();
// Cooking code ...
turnGasOff();
}|
enterTheKitchen();
cook();
leaveTheKitchen();
};
This cook function is wrong because there are several situations where we could leave the kitchen
with gas still turned on. Consider the following cooking code:
{
function cook()
{
turnGasOn();
if (mealReady)
{
echo("The meal is already there, nothing to do!");
// Oops ...
return;
};
for (var i in recipe)
if (i in kitchen)
putIngredient(i)
else
// Oops ...
throw Exception("missing ingredient: %s" % i);
// ...
turnGasOff();
}|
};
Here, if the meal was already prepared, or if an ingredient is missing, we will leave the cook
function without executing the turnGasOff statement, through the return statement or the exception.
One correct way to ensure gas is necessarily turned off is:
{
function cook()
{
var withGas = Tag.new("withGas");
at (withGas.enter?)
turnGasOn();
// Even if exceptions are thrown or return is called,
// the gas will be turned off.
at (withGas.leave?)
turnGasOff();
withGas: {
// Cooking code...
}
}|
};
Alternatively, the try/finally construct provides an elegant means to achieve the same result
(Section 22.8.4).
{
function cook()
{
try
{
turnGasOn();
// Cooking code...
}
finally
{
// Even if exceptions are thrown or return is called,
// the gas will be turned off.
turnGasOff();
}
}|
};
The begin and end methods enable to monitor when code is executed. The following example
illustrates the proper use of enter and leave events (Section 23.66.1.5), which are used to implement
this feature.
var myTag = Tag.new("myTag");
[00000000] Tag<myTag>
myTag.begin: echo(1);
[00000000] *** myTag: begin
[00000000] *** 1
myTag.end: echo(2);
[00000000] *** 2
[00000000] *** myTag: end
myTag.begin.end: echo(3);
[00000000] *** myTag: begin
[00000000] *** 3
[00000000] *** myTag: end
As any object, tags are created using new to create derivatives of the Tag object. The name is optional,
it makes easier to display a tag and remember what it is.
// Anonymous tag.
var t1 = Tag.new;
[00000001] Tag<tag_8>
// Named tag.
var t2 = Tag.new("cool name");
[00000001] Tag<cool name>
- begin
A sub-tag that prints out ”tag_name: begin” each time flow control enters the tagged code.
See Section 23.66.1.6.
- block(result = void)
Block any code tagged by this. Blocked tags can be unblocked using unblock. If some
result was specified, let stopped code return result as value. See Section 23.66.1.2.
- blocked
Whether code tagged by this is blocked. See Section 23.66.1.2.
- end
A sub-tag that prints out ”tag_name: end” each time flow control leaves the tagged code.
See Section 23.66.1.6.
- enter
An event triggered each time the flow control enters the tagged code. See Section 23.66.1.5.
- freeze
Suspend code tagged by this, already running or forthcoming. Frozen code can be later
unfrozen using unfreeze. See Section 23.66.1.3.
- frozen
Whether the tag is frozen. See Section 23.66.1.3.
- leave
An event triggered each time flow control leaves the tagged code. See Section 23.66.1.5.
- scope
Return a fresh Tag whose stop will be invoked a the end of the current scope. This function
is likely to be removed. See Section 23.66.1.4.
- stop(result = void)
Stop any code tagged by this. If some result was specified, let stopped code return
result as value. See Section 23.66.1.1.
- tags
All the undeclared tags are created as slots in this object. Using this feature is discouraged.
{
assert ("brandNewTag" not in Tag.tags.localSlotNames);
brandNewTag: 1;
assert ("brandNewTag" in Tag.tags.localSlotNames);
assert (Tag.tags.brandNewTag.isA(Tag));
};
- unblock
Unblock this. See Section 23.66.1.2.
- unfreeze
Unfreeze code tagged by this. See Section 23.66.1.3.
Tags can be arranged in a parent/child relationship: any operation done on a tag — freezing, stopping,
…is also performed on its descendants. Another way to see it is that tagging a piece of
code with a child will also tag it with the parent. To create a child Tag, simply clone its
parent.
var parent = Tag.new |
var child = parent.clone |
// Stopping parent also stops children.
{
parent: {sleep(100ms); echo("parent")},
child: {sleep(100ms); echo("child")},
parent.stop;
sleep(200ms);
echo("end");
};
[00000001] *** end
// Stopping child has no effect on parent.
{
parent: {sleep(100ms); echo("parent")},
child: {sleep(100ms); echo("child")},
child.stop;
sleep(200ms);
echo("end");
};
[00000002] *** parent
[00000003] *** end
Hierarchical tags are commonly laid out in slots so as to reflect their tag hierarchy.
var a = Tag.new;
var a.b = a.clone;
var a.b.c = a.b.clone;
a: foo; // Tagged by a
a.b: bar; // Tagged by a and b
a.b.c: baz; // Tagged by a, b and c
23.67 Timeout
Timeout objects can be used as Tags to execute some code in limited time.
At construction, a Timeout takes a duration, and a Boolean stating whether an exception should be
thrown on timeout (by default, it does).
Timeout.new(300ms);
[00000000] Timeout_0x953c1e0
Timeout.new(300ms, false);
[00000000] Timeout_0x953c1e0
Use it as a tag:
var t = Timeout.new(300ms);
[00000000] Timeout_0x133ec0
t:{
echo("This will be displayed.");
sleep(500ms);
echo("This will not.");
};
[00000000] *** This will be displayed.
[00000007:error] !!! Timeout_0x133ec0 has timed out.
The same Timeout, t can be reused. It is armed again each time it is used to tag some
code.
t: { echo("Open"); sleep(1s); echo("Close"); };
[00000007] *** Open
[00000007:error] !!! Timeout_0x133ec0 has timed out.
t: { echo("Open"); sleep(1s); echo("Close"); };
[00000007] *** Open
[00000007:error] !!! Timeout_0x133ec0 has timed out.
Even if exceptions have been disabled, you can check whether the count-down expired with
timedOut.
t:sleep(500ms);
[00000007:error] !!! Timeout_0x133ec0 has timed out.
if (t.timedOut)
echo("The Timeout expired.");
[00000000] *** The Timeout expired.
23.68 Traceable
Objects that have a concept of backtrace.
This object, made to serve as prototype, provides a definition of backtrace which can be filtered
based on the desired level of verbosity.
This prototype is not made to be constructed.
- backtrace
A call stack as a List of StackFrames. Used by Exception.backtrace and Job.backtrace.
try
{
[1].map(closure (v) { throw Exception.new("Ouch") })
}
catch (var e)
{
for| (var sf: e.backtrace)
echo(sf.name)
};
[00000001] *** map
- hideSystemFiles
Remove system files from the backtrace if this value equals true. Defaults to true.
Traceable.hideSystemFiles = false |
try
{
[1].map(closure (v) { throw Exception.new("Ouch") })
}
catch (var e)
{
for| (var sf: e.backtrace)
echo(sf.name)
};
[00000002] *** f
[00000003] *** each|
[00000004] *** map
23.69 TrajectoryGenerator
The trajectory generators change the value of a given variable from an initial value to a target
value. They can be open-loop, i.e., the intermediate values depend only on the initial and/or target
value of the variable; or closed-loop, i.e., the intermediate values also depend on the current value value
of the variable.
Open-loop trajectories are insensitive to changes made elsewhere to the variable. Closed-loop
trajectories are sensitive to changes made elsewhere to the variable — for instance when the human
physically changes the position of a robot’s motor.
Trajectory generators are not made to be used directly, rather use the “continuous assignment”
syntax (Section 22.11).
The Accel trajectory reaches a target value at a fixed acceleration (accel attribute).
23.69.2.2 Cos
The Cos trajectory implements a cosine around the target value, given an amplitude (ampli attribute)
and period (cos attribute).
This trajectory is not “smooth”: the initial value of the variable is not taken into account.
23.69.2.3 Sin
The Sin trajectory implements a sine around the target value, given an amplitude (ampli attribute)
and period (sin attribute).
This trajectory is not “smooth”: the initial value of the variable is not taken into account.
The Smooth trajectory implements a sigmoid. It changes the variable from its current value to the
target value “smoothly” in a given amount of time (smooth attribute).
The Speed trajectory changes the value of the variable from its current value to the target value at a
fixed speed (the speed attribute).
If the adaptive attribute is set to true, then the duration of the trajectory is constantly
reevaluated.
23.69.2.6 Time
The Time trajectory changes the value of the variable from its current value to the target value within
a given duration (the time attribute).
If the adaptive attribute is set to true, then the duration of the trajectory is constantly
reevaluated.
Trajectories can be managed using Tags. Stopping or blocking a tag that manages a trajectory kill the
trajectory.
When a trajectory is frozen, its local time is frozen too, the movement proceeds from where it was
rather than from where it would have been had it been not frozen.
You are not expected to construct trajectory generators by hand, using modifiers is the recommended
way to construct trajectories. See Section 22.11 for details about trajectories, and see Section 23.69.2
for an extensive set of examples.
- Accel
This class implements the Accel trajectory (Section 23.69.2.1). It derives from OpenLoop.
- ClosedLoop
This class factors the implementation of the closed-loop trajectories. It derives from
TrajectoryGenerator.
- OpenLoop
This class factors the implementation of the open-loop trajectories. It derives from
TrajectoryGenerator.
- Sin
This class implements the Cos and Sin trajectories (Section 23.69.2.2, Section 23.69.2.3).
It derives from OpenLoop.
- Smooth
This class implements the Smooth trajectory (Section 23.69.2.4). It derives from OpenLoop.
- SpeedAdaptive
This class implements the Speed trajectory when the adaptive attribute is given
(Section 23.69.2.5). It derives from ClosedLoop.
- Time
This class implements the non-adaptive Speed and Time trajectories (Section 23.69.2.5,
Section 23.69.2.6). It derives from OpenLoop.
- TimeAdaptive
This class implements the Time trajectory when the adaptive attribute is given
(Section 23.69.2.6). It derives from ClosedLoop.
23.70 Triplet
A triplet (or triple) is a container storing three objects.
A Triplet is constructed with three arguments.
Triplet.new(1, 2, 3);
[00000001] (1, 2, 3)
Triplet.new(1, 2);
[00000003:error] !!! new: expected 3 arguments, given 2
Triplet.new(1, 2, 3, 4);
[00000003:error] !!! new: expected 3 arguments, given 4
- first
Return the first member of the pair.
Triplet.new(1, 2, 3).first == 1;
Triplet[0] === Triplet.first;
- second
Return the second member of the triplet.
Triplet.new(1, 2, 3).second == 2;
Triplet[1] === Triplet.second;
- third
Return the third member of the triplet.
Triplet.new(1, 2, 3).third == 3;
Triplet[2] === Triplet.third;
23.71 Tuple
A tuple is a container storing a fixed number of objects. Examples include Pair and
Triplet.
The Tuple object is not meant to be instantiated, its main purpose is to share code for its descendants,
such as Pair. Yet it accepts its members as a list.
var t = Tuple.new([1, 2, 3]);
[00000000] (1, 2, 3)
The output generated for a Tuple can also be used to create a Tuple. Expressions are put inside
parentheses and separated by commas. One extra comma is allowed after the last element. To avoid
confusion between a 1 member Tuple and a parenthesized expression, the extra comma must be added.
Tuple with no expressions are also accepted.
// not a Tuple
(1);
[00000000] 1
// Tuples
();
[00000000] ()
(1,);
[00000000] (1,)
(1, 2);
[00000000] (1, 2)
(1, 2, 3, 4,);
[00000000] (1, 2, 3, 4)
- asString
The string ‘(first, second, ..., last)’, using asPrintable to convert members to
strings.
().asString == "()";
(1,).asString == "(1,)";
(1, 2).asString == "(1, 2)";
(1, 2, 3, 4,).asString == "(1, 2, 3, 4)";
- matchAgainst(handler, pattern)
Pattern matching on members. See Pattern.
{
// Match a tuple.
(var first, var second) = (1, 2);
assert { first == 1; second == 2 };
};
- size
Number of members.
().size == 0;
(1,).size == 1;
(1, 2, 3, 4).size == 4;
(1, 2, 3, 4,).size == 4;
- ’[]’(index)
Return the index-th element. index must be in bounds.
(1, 2, 3)[0] == 1;
(1, 2, 3)[1] == 2;
- ’[]=’(index, value)
Set (and return) the index-th element to value. index must be in bounds.
{
var t = (1, 2, 3);
assert
{
(t[0] = 2) == 2;
t == (2, 2, 3);
};
};
- ’<’(other)
Lexicographic comparison between two tuples.
(0, 0) < (0, 1);
(0, 0) < (1, 0);
(0, 1) < (1, 0);
- ’==’(other)
Whether this and other have the same contents (equality-wise).
(1, 2) == (1, 2);
!((1, 1) == (2, 2));
- ’*’(value)
Return a Tuple in which all elements of this are multiplied by a value.
(0, 1, 2, 3) * 3 == (0, 3, 6, 9);
(1, "foo") * 2 == (2, "foofoo");
- ’+’(other)
Return a Tuple in which each element of this is summed with its corresponding element in the
other Tuple.
(0, 1) + (2, 3) == (2, 4);
(1, "foo") + (2, "bar") == (3, "foobar");
23.72 UObject
UObject is used by the UObject API (see Listing I) to represent a bound C++ instance.
All the UObjects are copied under a unique name as slots of Global.uobjects.
23.73 uobjects
This object serves only to store the UObjects that are bound into the system (plug or
remote).
- asuobjects
Return this.
- clearStats
Reset counters.
- connectionStats
- enableStats(bool)
Depending on bool, enable or disable the statistics gathering.
- getStats
Return a dictionary of all bound C++ functions called, including timer callbacks, along
with the average, min, max call durations, and the number of calls.
- resetConnectionStats
- searchPath
- setTrace(bool)
23.74 UValue
The UValue object is used internally by the UObject API and is mostly hidden from the
user.
23.75 UVar
This class is used internally by the UObject middleware (see Listing I) to represent a variable that
can be hooked in C++. Each slot on which a C++ urbi::UVar exists contains an instance of this
class.
Instances of UVar are mostly transparent, they appear as the value they contain. Thus, since
the UVar evaluates to the contained value, you must use getSlot to manipulate the UVar
itself.
To instantiate a new UVar, pass the owner object and the slot name to the constructor.
UVar.new(Global, "x")|
Global.x = 5;
[000000001] 5
x;
[000000002] 5
- copy(targetObject, targetName)
Copy the UVar to the slot targetName of object targetObject. Since the UVar is using
properties, you must use this method to copy it to an other location.
- hookChanged
A Boolean that states whether future UVar instantiations support the changed event.
Code like:
at (headTouch.val->changed? if headTouch.val)
tts.say("ouch");
works, but costs one at per UVar (whose cost is light in recent version of Urbi SDK). Set
hookChanged to false before instantiating new UVars to disable this feature; you may also set it
to true to re-enable the feature for UVars that will be instantiating afterward. See also the
environment variable URBI_UVAR_HOOK_CHANGED, Section 21.1.2.
- notifyAccess(onAccess)
Similar to the C++ UNotifyAccess, calls onAccess each time the UVar is accessed
(read).
var Global.counter = 0|
UVar.new(Global, "access")|
var accessHandle = &access.notifyAccess(closure() {
Global.access = Global.counter += 1
})|
assert
{
access == 1;
access == 2;
access == 3;
};
&access.removeNotifyAccess(accessHandle)|;
assert
{
access == 3;
access == 3;
};
- notifyChange(onChange)
Similar to the C++ UNotifyChange for a non-owned UVar (see Section 4.5), register onChange
and call it each time this UVar is written to. Return an identifier that can be passed to
removeNotifyChange to unregister the callback.
UVar.new(Global, "y")|
var handle = Global.&y.notifyChange(closure() {
echo("The value is now " + Global.y)
})|
Global.y = 12;
[00000001] *** The value is now 12
[00000002] 12
Global.&y.removeNotifyChange(handle)|;
Global.y = 13;
[00000003] 13
- notifyChangeOwned(onChangeOwned)
Similar to the C++ UNotifyChange for an owned UVar (see Section 4.5), register onChange and
call it each time this UVar is written to. Return an identifier that can be passed to
removeNotifyChange to unregister the callback.
- removeNotifyAccess(id)
Disable the notification installed as id by notifyAccess.
- removeNotifyChange(id)
Disable the notification installed as id by notifyChange.
- removeNotifyChangeOwned(id)
Disable the notification installed as id by notifyChangeOwned.
- owned
True if the UVar is in owned mode, that is if it contains both a sensor and a command
value.
23.76 void
The special entity void is an object used to denote “no value”. It has no prototype and cannot be
used as a value. In contrast with nil, which is a valid object, void denotes a value one is not allowed
to read.
None.
void is the value returned by constructs that return no value.
void.isVoid;
{}.isVoid;
{if (false) 123}.isVoid;
- acceptVoid
Trick this so that, even if it is void it can be used as a value. See also unacceptVoid.
void.foo;
[00096374:error] !!! unexpected void
void.acceptVoid.foo;
[00102358:error] !!! lookup failed: foo
- isVoid
Whether this is void. Therefore, return true.
void.isVoid;
void.acceptVoid.isVoid;
! 123.isVoid;
- unacceptVoid
Remove the magic from this that allowed to manipulate it as a value, even if it is void. See also
acceptVoid.
void.acceptVoid.unacceptVoid.foo;
[00096374:error] !!! unexpected void