Table Of Contents |
The agent system BORG is based on an educational language, called Pico.
The system itself supports location transparent routing, strong migration
(at any time can we move an agent, even if it's in the middle of the
execution of code) and a very suitable commuication paradigm.
More information can be found at
http://progwww.vub.ac.be/poolresearch/CBorg/.
PICO is a programming language developed on the Programming
Lab of the VUB. (PROG).
by Prof. Dr. Theo D'Hondt
as a simple programming language for the Science Students.
BORG was developed for research purposes, mainly because other languages did not support strong migration.
This tutorial will explain the basics of BORG, it will not give a total
introduction to PICO. For a tutorial about pico I refer you to the webpage
about pico. The knowledge of pico
is essential to use BORG
You can find the latest BORG executable at the BORG archive at :
ftp://progpc26.vub.ac.be/cborg/
Simple information about the language Pico is available at :
http://pico.vub.ac.be/
More information can be found at :
http://progwww.vub.ac.be/poolresearch/CBorg/.
This tutorial is online at :
http://borg.rave.org/
BORG code is written in Pico extended with
some primitive functions to alow communication between agents.
Agents can communicate with each other in 3 ways.
The Pico language is dynamically typed and a variable can contain values of the
following type: numbers, text, tables, functions and references to agents.
Variables can be defined using the ``:''-operator, assignment to a variable
is written down with a ``:=''. (``::'' is used to define constants ) |
|
|
This is just like in any other dynamically typed language. Actually the communication
model doesn't need a dynamical typing at all, so the base language might as well be
statically typed. Equivalent to variables, we can define tables and assign values to any cell of the table. |
|
|
Functions can also be defined using an equivalent intuitive syntax. |
|
|
We also need some kind of if-then-else construction. if(condition, then, else) while(condition, expression) until(condition, expression) for(initialization, step, condition, expression) |
|
This is like java RMI.
If we have 2 agents, we can use Remote function calls to allow the agents to communicate with each other.
The idea is to make a reference to the remote agent by calling the agent(String) primitive function.
When both agents have these references, they can call functions from the other agent by writing
REMARK : This was first called remotedict(String), so if agent(String) doesn't work try remotedict
agentname::agent(String) agentname->function(Variables...) |
Fig 3.1 Agent localnet/Alice and Agent localnet/Alice1 using agent |
Fig 3.2 Returning results... |
We extend this prototypical language with a pair of communication primitives,
send and receive. Send ensures the asynchronous delivery of a message from one
agent to another. Because the send command is asynchronous, execution of this
instruction results in putting the message in the message delivery system. The
call returns immediately and doesn't wait for the message to actually arrive,
speeding up program execution by avoiding large delays that can be possible in
wide area networks. The downside of asynchronous communication is of course
that errors are difficult to detect.
The two primitive functions used for sending and receiving messages are :
send(agent, message) recv(agent, pattern) |
Fig 3.3 Asynchronous sending and receiving (typo: pattren == pattern) (remotedict should be agent) |
To be able to send and receive Synchronously a third primitive was added the
language. It is called sync and synchronizes two or more agents.
Agent1 | Agent2 |
sync(agent2) …. Waiting for sync …. …. Execution continues |
…. …. …. …. sync(agent1) Excecution continues |
Agent1 | Agent2 |
Sync(any,'tag') ... Continues |
... Sync(any,'tag') Continues |
ssend(to,message): { send(to,message); sync(to,message) } |
srecv(from,pattern): { sync(from,pattern); recv(from,pattern) } |
We will start by making a small counter object, and then continue with a Stack-object
make_counter() :: { c:0; increment()::{c:=c+1}; get()::{display(c)}; clone() } |
c:make_counter() :<dictionary> d:make_counter() :<dictionary> c->increment() :1 c->increment() :2 c->increment() :3 d->get() :0 |
The objects can be called using Remote function calls. |
{ Stack(n): { T[n]: void; super: void; t: 0; empty():: t = 0; full():: t = n; push(x):: { T[t:= t+1]:= x; void }; pop():: { x: T[t]; t:= t-1; x }; makeProtected():: { push(x):: if(full(), error('overflow'), super.push(x)); pop():: if(empty(), error('underflow'), super.pop()); clone() }; super := clone() }; S: Stack(10); if(S->full(), void, S->push(123)); if(S->empty(), void, S->pop()); R: S->makeProtected(); R->push(1); R->pop() } |
One of the major reasons the Borg-system was built is because unlike in other
systems (like java RMI) here it is possible to move agents to other agent-systems.
There is a primitive operation where you provide a agent that shall be used as reference to the moved object.
agentmove(agent("Sub.Master")) |
make_counter() :: { c:0; increment()::{c:=c+1}; get()::{display(c)}; agentclone(clone(),"Sub1.Master/ses3") } |
The file borg.localhostname.ini can be found in the config directory.
You can find the latest information about configuring this file at
Borg Frontends