Hello BPjs World

Let’s start by writing the traditional hello, world! program. Instead of writing characters to the console, our program will generate two events, in the following order:

  1. A “Hello” event
  2. A “World” event

We assume you have downloaded and installed BPjs. This process is explained in Obtaining BPjs.

The Sequential Version

The “Hello, World” version below (source) contains a single b-thread, requesting the two events in sequence. Since it is the only b-thread in the program, these events are not blocked by anyone, and are the only available events. Thus, the arbiter select each one of them as they are requested.

1
2
3
4
bp.registerBThread(function(){
  bp.sync({request:bp.Event("hello")});
  bp.sync({request:bp.Event("world")});
})

This is not a very complicated example, but it does show a few basics worth mentioning. First, b-threads are normal javascript functions that take no parameters. They are added to the b-program using bp.registerBThread. Note that the b-program is never explicitly started by the client code. Starting the b-program is done by BPjs for you.

Lines 2 and 3 contain a very simple bp.sync statement, requesting an event. The events are created using the event factory bp.Event(...). This code uses the simple version of bp.Event, passing the event name only. We’ll see more of bp.XXX and bp.sync soon, but first let’s run this program and see what happens.

Running this example

Assuming bpjs.jar is the name of the BPjs jar, and that is it available at the system’s PATH, running the program is done like so:

 1 $ java -jar bpjs.jar hello-world-seq.js
 2 #  [READ] /path/to/hello-world-seq.js
 3 -:BPjs Added autoadded-1
 4 #  [ OK ] hello-world-seq.js
 5 ---:BPjs Started
 6  --:BPjs Event [BEvent name:hello]
 7  --:BPjs Event [BEvent name:world]
 8 ---:BPjs No Event Selected
 9 ---:BPjs Ended

Lines 2 and 4 logs the loading and successful execution of the source file hello-world-seq.js. Line 3 records the addition of a b-thread (done in line 1 of the source). Lines 5-9 follow the execution of our little program. It starts, then the events are selected (“hello” and “world”, as required). Then, no event is selected, so the program termintes.

Note the lifecycle of the program: files are first loaded and interpreted, and only then the b-program start all its b-threads. This will be important later, when we add b-threads dynamically. More on that later. Now, let’s create a more complex version of “hello, world!”.

Hello World with Wait

Below is an updated version (source), containing two b-threads. One b-thread, called bt-hi, requests the “hello” event and then terminates. The other b-thread, “bt-world”, waits for the first event (line 2), and then requests the “world” event. The b-threads are named using the two-argument version of bp.registerBThread, whose first parameter is the name of the b-thread, and second parameter is the b-thread itself.

The trace, or sequence of events generated by this program, is equivalent to that of The Sequential Version. The program structure, on the other hand, is very different, as each requested event is done by a specific b-thread. However, bt-world is quite coupled to bt-hi, as it waits for a specific event it emits. If the greeting would change to "shalom", "holà", or "goodbye", the program will break, unless bt-world is updated. This makes total sense in an eight-lines program, but in real world we would like to reduce coupling and increase cohesion. Let’s see BP’s take on this challenge.

1
2
3
4
5
6
7
8
bp.registerBThread("bt-world",function(){
  bp.sync({waitFor:bp.Event("hello")});
  bp.sync({request:bp.Event("world")});
})

bp.registerBThread("bt-hi", function(){
  bp.sync({request:bp.Event("hello")});
})

Hello Block World

Here is what we’d ideally like to have (source):

1
2
3
4
5
6
7
bp.registerBThread("bt-hi", function(){
  bp.sync({request:bp.Event("hello")});
})

bp.registerBThread("bt-world",function(){
  bp.sync({request:bp.Event("world")});
})

Each b-thread is responsible for requesting its event only, so the code is very cohesive. But alas, the program may generate the events in the wrong order. This is because the event arbiter can choose which event to select first. In the example below, we have two runs generating different traces.

 1 $ java -jar bpjs.jar hello-world-decoupled.js
 2 #  [READ] /path/to/hello-world-decoupled.js
 3   -:BPjs Added bt-hi
 4   -:BPjs Added bt-world
 5 #  [ OK ] hello-world-decoupled.js
 6 ---:BPjs Started
 7  --:BPjs Event [BEvent name:hello]
 8  --:BPjs Event [BEvent name:world]
 9 ---:BPjs No Event Selected
10 ---:BPjs Ended
11 
12 $ java -jar bpjs.jar hello-world-decoupled.js
13 ...
14 ---:BPjs Started
15  --:BPjs Event [BEvent name:world]
16  --:BPjs Event [BEvent name:hello]
17 ...

To prevent the wrong order of events, we can add this additional b-thread (source). It solves the “world before hello” issue by blocking the world event from being selecting, until the hello event is. This is done by passing bp.Event("world") as the block parameter of bp.sync.

1
2
3
bp.registerBThread("hello world Patch", function(){
  bp.sync({waitFor:bp.Event("hello"), block:bp.Event("world")});
})

We can now run both files in a single b-program, like so. Note that we are passing two files to the bpjs runtime:

 1 #  [READ] /Users/michael/Documents/PhD/Thesis/code/bThink-BGU/BPjs/docs/source/BPjsTutorial/code/hello-world-decoupled.js
 2 -:BPjs Added bt-hi
 3 -:BPjs Added bt-world
 4 #  [ OK ] hello-world-decoupled.js
 5 #  [READ] /Users/michael/Documents/PhD/Thesis/code/bThink-BGU/BPjs/docs/source/BPjsTutorial/code/hello-world-decoupled-patch.js
 6   -:BPjs Added hello world Patch
 7 #  [ OK ] hello-world-decoupled-patch.js
 8 ---:BPjs Started
 9  --:BPjs Event [BEvent name:hello]
10  --:BPjs Event [BEvent name:world]
11 ---:BPjs No Event Selected
12 ---:BPjs Ended

The last example demonstrate how BP is suited for incremental, modular software development. We have changed the overall behavior of our b-program by adding new code, rather than by changing existing one. This change can be pulled out with no change to the rest of the program, in case we decide the order of the events does not matter.

Hello BPjs World

Finally, let’s change the program such that its trace read “hello BPjs world”. Again, this can be done by adding the following b-thread (source).

1
2
3
4
bp.registerBThread("bpjs addition", function(){
  bp.sync({waitFor:bp.Event("hello")});
  bp.sync({request:bp.Event("BPjs"), block:bp.Event("world")});
})

Result:

 1 $ java -jar bpjs.jar hello-world-decoupled.js hello-world-decoupled-patch.js hello-world-bpjs.js
 2 #  [READ] /path/to/hello-world-decoupled.js
 3 -:BPjs Added bt-hi
 4 -:BPjs Added bt-world
 5 #  [ OK ] hello-world-decoupled.js
 6 #  [READ] /path/to/hello-world-decoupled-patch.js
 7 -:BPjs Added hello world Patch
 8 #  [ OK ] hello-world-decoupled-patch.js
 9 #  [READ] /path/to/hello-world-bpjs.js
10 -:BPjs Added bpjs addition
11 #  [ OK ] hello-world-bpjs.js
12 ---:BPjs Started
13 --:BPjs Event [BEvent name:hello]
14 --:BPjs Event [BEvent name:BPjs]
15 --:BPjs Event [BEvent name:world]
16 ---:BPjs No Event Selected
17 ---:BPjs Ended