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.
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 (Section 23.62).
Beware that the third line above (‘my content’), was output by the system, although not preceded by a timestamp.
assert(Binary.new("head", "content").asString
== "BIN 7 head\ncontent");
var b = BIN 7 header;content;
[00000002] BIN 7 header
content
assert(b == Binary.new("header", "content"));
This syntax (BIN size header; content) is partially supported in urbiscript, but it is strongly discouraged. Rather, use the \B(size)(data) special escape (see Section 22.1.6.6):
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.
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:
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
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
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
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
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;
};
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;
};
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
The Filter channel outputs text that can be parsed without error by the liburbi. It does this by filtering types not handled by the liburbi, and displaying them using echo.
// Use a filtering channel on our lobby output.
topLevel = Channel.Filter.new("")|;
// liburbi knows about List, Dictionary, String and Float, so standard display.
[1, "foo", ["test" => 5]];
[00000001] [1, "foo", ["test" => 5]]
// liburbi does not know ’lobby’, so it is escaped with echo:
lobby;
[00000002] *** Lobby_0xADDR
// The following list contains a function which is not handled by liburbi, so
// it gets escaped too.
[1, function () {}];
[00000003] *** [1, function () {}]
// Restore default display to see the difference.
topLevel = Channel.topLevel|;
// The echo is now gone.
[1, function () {}];
[00001758] [1, function () {}]
Functions written in urbiscript.
The keywords function and closure build Code instances.
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.
Arguments do matter, even if in practice the functions are the same.
A lazy function cannot be equal to a strict one.
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.
Objects that can be compared for equality and inequality. See also Orderable (Section 23.41).
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);
};
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.
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.
This function is used to implement
as
The persist action will be controlled by the same tags as the initial at block.
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.
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");
[00000001] 2003-10-10 20:10:50
Date.new("2003-Oct-10 20:10");
[00000002] 2003-10-10 20:10:00
Date.new("2003-10-10 20");
[00000003] 2003-10-10 20:00:00
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
Date.new("2010-08-17 12:01") - Date.new("2010-08-17 12:00") == 60s;
Date.new("2010-08-17 12:00") - Date.new("2010-08-17 12:01") == -60s;
If that is a Duration or a Float, the corresponding Date.
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.
You are encouraged to use the specific syntax for Dictionary literals:
An extra comma can be added at the end of the list.
It is guaranteed that the pairs to insert are evaluated left-to-write, key first, the value.
Since Dictionary derives from RangeIterable (Section 23.54), it is easy to iterate over a Dictionary using a range-for (Section 22.7.5.2). No particular order is ensured.
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] [ => ]
The infix operators in and not in use has (see Section 22.1.8.7).
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 (Section 23.62) or a Path (Section 23.44). It can also be constructed by the method open of Path (Section 23.44).
Directory.new(".");
[00000001] Directory(".")
Directory.new(Path.new("."));
[00000002] Directory(".")
This feature is experimental. It might be changed in the future. Feedback on its use would be appreciated.
The str String (Section 23.62) is concatenated with the directory path. If the resulting path is either a directory or a file, ’/’ will returns either a Directory (Section 23.12) or a File (Section 23.18) object.
This feature is experimental. It might be changed in the future. Feedback on its use would be appreciated.
If entity is a Directory (Section 23.12) or a File (Section 23.18), ’<<’ copies entity in the this directory. Return this to allow chained operations.
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;
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;
This feature is experimental. It might be changed in the future. Feedback on its use would be appreciated.
Return a Date (Section 23.10) object stating when the directory was last modified.
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;
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;
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.
This class records differences between Dates (Section 23.10).
This feature is experimental. It might be changed in the future. Feedback on its use would be appreciated.
Without argument, a null duration.
Durations can be negative.
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.
The created values are derive from the created enumeration type.
Since it also derives from RangeIterable (Section 23.54), this enables all its features. For instance:
Direction.each(function (var d) { echo(d) });
[00000001] *** up
[00000001] *** down
[00000001] *** left
[00000001] *** right
for (var d in Direction)
echo(d);
[00000001] *** up
[00000001] *** down
[00000001] *** left
[00000001] *** right
for| (var d in Direction)
echo(d);
[00000001] *** up
[00000001] *** down
[00000001] *** left
[00000001] *** right
assert
{
Direction.any(closure (var v) { v == Direction.up });
};
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.
Throw a synchronized event. This call awaits that all functions that have to react to this event have returned. This function can have the same arguments as emit.
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.
//#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
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.
This class is used only as a common ancestor to Primitive (Section 23.47) and Code (Section 23.6).
There is no point in constructing an Executable.
Files may be created from a String (Section 23.62), or from a Path (Section 23.44). 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 (Section 23.27) and OutputStream (Section 23.42) to read or write to Files.
This feature is experimental. It might be changed in the future. Feedback on its use would be appreciated.
Copy file into dirname directory.
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 == "";
};
This feature is experimental. It might be changed in the future. Feedback on its use would be appreciated.
Return a Date (Section 23.10) object stating when the file was last modified.
This feature is experimental. It might be changed in the future. Feedback on its use would be appreciated.
Move file into dirname directory.
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.
It is reclaimed by the system when it is no longer referenced by any other object.
Here, the object is still alive, since alias references it. Once it no longer does, the object dies.
The constructor takes no argument.
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:
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
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:
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).
A null float can also be obtained with Float’s new method.
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.