diff --git a/README.md b/README.md
index a536d8ad..ed338921 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ The initial code of `JoinRun` was based on previous work by Jiansen He (https://
The current implementation is tested under Oracle JDK 8 with Scala 2.11 and 2.12.
It also works with Scala 2.10 and with OpenJDK 7 (except for the new `LocalDateTime` functions used in tests, and some performance issues).
-# Overview of `JoinRun`
+# Overview of `JoinRun`/`Chymyst`
To get started, begin with this [tutorial introduction](https://chymyst.github.io/joinrun-scala/chymyst00.html).
@@ -141,7 +141,7 @@ Other than that, `JoinRun`'s syntax is closely modeled on that of `ScalaJoin` an
# Status
-Current version is `0.1.3`.
+Current released version is `0.1.3`.
The semantics of the chemical machine (restricted to single-host, multicore computations) is fully implemented and tested.
Unit tests include examples such as concurrent counters, parallel “or”, concurrent merge-sort, and “dining philosophers”.
diff --git a/benchmark/src/main/scala/code/chymyst/benchmark/JiansenJoin.scala b/benchmark/src/main/scala/code/chymyst/benchmark/JiansenJoin.scala
index 9fd3d1a6..24ded1d3 100644
--- a/benchmark/src/main/scala/code/chymyst/benchmark/JiansenJoin.scala
+++ b/benchmark/src/main/scala/code/chymyst/benchmark/JiansenJoin.scala
@@ -59,10 +59,12 @@ class AsyName[Arg](implicit owner: Join, argT:ClassTag[Arg]) extends NameBase{
override def pendArg(arg:Any):Unit = {
argQ += arg.asInstanceOf[Arg]
+ ()
}
override def popArg():Unit = {
argQ.dequeue()
+ ()
}
var argQ = new Queue[Arg] //queue of arguments pending on this name
@@ -71,13 +73,18 @@ class AsyName[Arg](implicit owner: Join, argT:ClassTag[Arg]) extends NameBase{
*
* @param a the message pending on this channel
*/
- def apply(a:Arg) :Unit = new Thread {synchronized{
- if(argQ.contains(a)){
- argQ += a
- }else {
- owner.trymatch(AsyName.this, a)// see if the new message will trigger any pattern
+ def apply(a:Arg) :Unit = {
+ new Thread {
+ synchronized {
+ if (argQ.contains(a)) {
+ argQ += a
+ } else {
+ owner.trymatch(AsyName.this, a) // see if the new message will trigger any pattern
+ }
+ }
}
- }}
+ ()
+ }
def unapply(attr:Any) : Option[Arg]= attr match { // for pattern matching
case (ch:NameBase, arg:Any) => {
@@ -143,6 +150,7 @@ class SynName[Arg, R](implicit owner: Join, argT:ClassTag[Arg], resT:ClassTag[R]
override def pendArg(arg:Any):Unit = {
argQ += arg.asInstanceOf[(Int,Arg)]
+ ()
}
override def popArg():Unit = synchronized {
@@ -202,11 +210,16 @@ class SynName[Arg, R](implicit owner: Join, argT:ClassTag[Arg], resT:ClassTag[R]
*
* @param r the reply value
*/
- def reply(r:R):Unit = new Thread {resultQ.synchronized {
- // println("reply "+r)
- resultQ.enqueue((msgTags.pop, r))
- resultQ.notifyAll()
- }}
+ def reply(r:R):Unit = {
+ new Thread {
+ resultQ.synchronized {
+ // println("reply "+r)
+ resultQ.enqueue((msgTags.pop, r))
+ resultQ.notifyAll()
+ }
+ }
+ ()
+ }
private def fetch(a:(Int,Arg)):R = resultQ.synchronized {
if (resultQ.isEmpty || resultQ.front._1 != a){
@@ -284,7 +297,7 @@ class Join {
private var joinPat: PartialFunction[Any, Any] = _
// private var joinPat: PartialFunction[(Set[NameBase], Queue[(NameBase, Any)], PartialFunction[Any, Any], Int), Unit] = _
// def join(joinPat: PartialFunction[(Set[NameBase], Queue[(NameBase, Any)], PartialFunction[Any, Any], Int), Unit]) {
- def join(joinPat: PartialFunction[Any, Any]) {
+ def join(joinPat: PartialFunction[Any, Any]): Unit = {
if(!hasDefined){
this.joinPat = joinPat
hasDefined = true
@@ -297,13 +310,13 @@ class Join {
val names: Set[NameBase] = new HashSet
//println(ch +" "+ arg)
try{
- if(ch.isInstanceOf[SynName[Any, Any]]) {ch.asInstanceOf[SynName[Any,Any]].pushMsgTag(arg)}
+ if(ch.isInstanceOf[SynName[_, _]]) {ch.asInstanceOf[SynName[_,_]].pushMsgTag(arg)}
if(joinPat.isDefinedAt((ch, arg))){// optimization for singleton pattern
joinPat((ch,arg))
}else{
- if(ch.isInstanceOf[SynName[Any, Any]]){
+ if(ch.isInstanceOf[SynName[_, _]]){
joinPat((names, this.joinPat, (new HashMap[NameBase, Any]+((ch, arg))), 1, new SynName))
- ch.asInstanceOf[SynName[Any,Any]].pushMsgTag(arg)
+ ch.asInstanceOf[SynName[_,_]].pushMsgTag(arg)
}else{
joinPat((names, this.joinPat, (new HashMap[NameBase, Any]+((ch, arg))), 1, new AsyName))
}
@@ -313,7 +326,7 @@ class Join {
}
}catch{
case e:MatchError => {// no pattern is matched
- if(ch.isInstanceOf[SynName[Any, Any]]) {ch.asInstanceOf[SynName[Any,Any]].popMsgTag}
+ if(ch.isInstanceOf[SynName[_, _]]) {ch.asInstanceOf[SynName[_,_]].popMsgTag}
ch.pendArg(arg)
}
}
diff --git a/benchmark/src/test/scala/code/chymyst/benchmark/MergesortSpec.scala b/benchmark/src/test/scala/code/chymyst/benchmark/MergesortSpec.scala
index 3cd8e3df..5583e3ee 100644
--- a/benchmark/src/test/scala/code/chymyst/benchmark/MergesortSpec.scala
+++ b/benchmark/src/test/scala/code/chymyst/benchmark/MergesortSpec.scala
@@ -5,7 +5,6 @@ import org.scalatest.{FlatSpec, Matchers}
import scala.annotation.tailrec
import scala.collection.mutable
-import scala.reflect.ClassTag
import Common._
@@ -23,7 +22,9 @@ class MergesortSpec extends FlatSpec with Matchers {
}
}
- def arrayMerge[T : Ordering : ClassTag](arr1: Array[T], arr2: Array[T]): Array[T] = {
+ type Coll[T] = IndexedSeq[T]
+
+ def arrayMerge[T : Ordering](arr1: Coll[T], arr2: Coll[T]): Coll[T] = {
val id = amCounter.c
// amCounter.inc() // avoid this for now - this is a debugging tool
val wantToLog = false // (arr1.length > 20000 && arr1.length < 41000)
@@ -46,54 +47,54 @@ class MergesortSpec extends FlatSpec with Matchers {
}
mergeRec(0,0,0)
if (wantToLog) println(s"${System.currentTimeMillis} finished merging #$id")
- result.toArray
+ result.toIndexedSeq
}
- def performMergeSort[T : Ordering : ClassTag](array: Array[T], threads: Int = 8): Array[T] = {
+ def performMergeSort[T : Ordering](array: Coll[T], threads: Int = 8): Coll[T] = {
- val finalResult = m[Array[T]]
- val getFinalResult = b[Unit, Array[T]]
- val tp = new FixedPool(threads)
- val jp = new FixedPool(3)
+ val finalResult = m[Coll[T]]
+ val getFinalResult = b[Unit, Coll[T]]
+ val reactionPool = new FixedPool(threads)
+ val sitePool = new FixedPool(3)
- site(jp,jp)(
+ site(sitePool,sitePool)(
go { case finalResult(arr) + getFinalResult(_, r) => r(arr) }
)
- // recursive molecule that will define the reactions at one level
+ // recursive molecule that will define the reactions at one level lower
- val mergesort = m[(Array[T], M[Array[T]])]
+ val mergesort = m[(Coll[T], M[Coll[T]])]
- site(tp,jp)(
+ site(reactionPool, sitePool)(
go {
case mergesort((arr, resultToYield)) =>
if (arr.length <= 1) resultToYield(arr)
else {
val (part1, part2) = arr.splitAt(arr.length/2)
- // "sorted1" and "sorted2" will be the sorted results from lower level
- val sorted1 = m[Array[T]]
- val sorted2 = m[Array[T]]
- site(tp,jp)(
+ // "sorted1" and "sorted2" will be the sorted results from the lower level
+ val sorted1 = m[Coll[T]]
+ val sorted2 = m[Coll[T]]
+ site(reactionPool, sitePool)(
go { case sorted1(x) + sorted2(y) =>
resultToYield(arrayMerge(x,y)) }
)
- // emit lower-level mergesort
+ // emit `mergesort` with the lower-level `sorted` result molecules
mergesort((part1, sorted1)) + mergesort((part2, sorted2))
}
}
)
- // sort our array at top level
+ // sort our array: emit `mergesort` at top level
mergesort((array, finalResult))
val result = getFinalResult()
- tp.shutdownNow()
- jp.shutdownNow()
+ reactionPool.shutdownNow()
+ sitePool.shutdownNow()
result
}
it should "merge arrays correctly" in {
- arrayMerge(Array(1,2,5), Array(3,6)) shouldEqual Array(1,2,3,5,6)
+ arrayMerge(IndexedSeq(1,2,5), IndexedSeq(3,6)) shouldEqual IndexedSeq(1,2,3,5,6)
}
it should "sort an array using concurrent merge-sort correctly with one thread" in {
diff --git a/docs/Boyle_Self-Flowing_Flask.png b/docs/Boyle_Self-Flowing_Flask.png
new file mode 100644
index 00000000..3548dda4
--- /dev/null
+++ b/docs/Boyle_Self-Flowing_Flask.png
@@ -0,0 +1,361 @@
+
+
+
The figure is sometimes called "Boyle's perpetual motion scheme" (in honor of Robert Boyle (1627-1691)), the "perpetual vase" or "perpetual goblet". It was discussed by Denis Papin (1647-1712) in the Philosophical Transactions for 1685. It was even accepted by Johann Bernoulli (1667-1748). Some commentators call it the "hydrostatic paradox". Some confuse the hydrostatic system with a capillary system.
Scanned without alteration from Fig. 54 in Arthur W.J.G. Ord-Hume's Perpetual Motion, the history of an obsession. Allen & Unwin, 1977, St. Martins Press, 1977. It also appears in Dirck's books and many other places.
+
Scan used with Simanek's permission.
+
+
+
+
Public domainPublic domainfalsefalse
+
+
+
+
+
+
+
This work is in the public domain in its country of origin and other countries and areas where the copyright term is the author's life plus 70 years or less.
+
+
You must also include a United States public domain tag to indicate why this work is in the public domain in the United States. Note that a few countries have copyright terms longer than 70 years: Mexico has 100 years, Jamaica has 95 years, Colombia has 80 years, and Guatemala and Samoa have 75 years. This image may not be in the public domain in these countries, which moreover do not implement the rule of the shorter term. Côte d'Ivoire has a general copyright term of 99 years and Honduras has 75 years, but they do implement the rule of the shorter term. Copyright may extend on works created by French who died for France in World War II (more information), Russians who served in the Eastern Front of World War II (known as the Great Patriotic War in Russia) and posthumously rehabilitated victims of Soviet repressions (more information).
+
+
+
+
diff --git a/docs/chymyst00.md b/docs/chymyst00.md
index a264c2fa..09e943aa 100644
--- a/docs/chymyst00.md
+++ b/docs/chymyst00.md
@@ -17,12 +17,22 @@ To understand this tutorial, the reader should have some familiarity with the `S
[Chapter 4: Map/Reduce and Merge-Sort](chymyst04.md)
-[Chapter 5: Further concurrency patterns](chymyst05.md)
+[Chapter 5: Reaction constructors](chymyst05.md)
[Previous work and other tutorials on Join Calculus](chymyst06.md)
+[Chapter 7: Concurrency patterns](chymyst07.md)
+
+[Chapter 8: Advanced examples](chymyst08.md)
+
+[Version history and roadmap](roadmap.md)
+
The source code repository for `JoinRun` is at [https://github.com/winitzki/joinrun-scala](https://github.com/winitzki/joinrun-scala).
Although this tutorial focuses on using `JoinRun`/`Chymyst` in Scala, one can similarly embed the chemical machine as a library on top of any programming language that has threads and semaphores.
The main concepts and techniques of the chemical machine paradigm are independent of the base programming language.
+[![Robert Boyle's self-flowing flask](Boyle_Self-Flowing_Flask.png)](https://en.wikipedia.org/wiki/Robert_Boyle#/media/File:Boyle%27sSelfFlowingFlask.png)
+
+This drawing is by [Robert Boyle](https://en.wikipedia.org/wiki/Robert_Boyle), one of the founders of the science of chemistry.
+In 1661 he published a treatise titled [The Sceptical Chymyst](https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Sceptical_chymist_1661_Boyle_Title_page_AQ18_%283%29.jpg/220px-Sceptical_chymist_1661_Boyle_Title_page_AQ18_%283%29.jpg), from which the `Chymyst` framework borrows its name.
diff --git a/docs/chymyst01.md b/docs/chymyst01.md
index 0d825b0d..d982065c 100644
--- a/docs/chymyst01.md
+++ b/docs/chymyst01.md
@@ -411,11 +411,27 @@ This limitation could be lifted in a later version of `JoinRun` if it proves use
When a reaction site has enough waiting molecules for several different reactions to start, the runtime engine will choose the reaction at random, giving each candidate reaction an equal chance of starting.
-TODO: Drawing of several possible reactions at a reaction site
+The next drawing shows a possibility of different reactions starting at a reaction site.
+In this example, the soup contains one copy of the `counter` molecule, one copy of `incr`, and one copy of `decr`.
+The `counter` molecule could either react with the `incr` molecule or with the `decr` molecule.
+One of these reactions (shown in solid lines) have been chosen to actually start, which leaves the second reaction (shown with a dashed line) without the input molecule `counter` and, therefore, the second reaction cannot start.
+
+![Reaction diagram counter + incr, counter + decr](https://chymyst.github.io/joinrun-scala/counter-multiple-reactions.svg)
Similarly, when there are several copies of the same molecule that can be consumed as input by a reaction, the runtime engine will make a choice of which copy of the molecule to consume.
-TODO: Drawing of several possible input molecules for a reaction
+The next drawing shows the choice of input molecules among the ones present at a reaction site.
+In this example, the soup contains one copy of the `counter` molecule and four copies of the `incr` molecule.
+Each of the four `incr` molecules can react with the one `counter` molecule.
+The runtime engine will choose which molecules actually react.
+One reaction (shown in solid lines) will start, consuming the `counter` and `incr` molecules, while other possible reactions (shown in dashed lines) will not start.
+
+![Reaction diagram counter + incr, counter + incr](https://chymyst.github.io/joinrun-scala/counter-multiple-molecules.svg)
+
+After this reaction, the contents of the soup is one copy of the `counter` molecule (with the updated value) and the three remaining `incr` molecules.
+At the next step, another one of the `incr` molecules will be chosen to start a reaction.
+
+![Reaction diagram counter + incr, counter + decr after reaction](https://chymyst.github.io/joinrun-scala/counter-multiple-reactions-after-reaction.svg)
Currently, `JoinRun` will _not_ fully randomize the input molecules but make an implementation-dependent choice.
A truly random selection of input molecules may be implemented in the future.
diff --git a/docs/chymyst02.md b/docs/chymyst02.md
index 3b710d62..3f2263ee 100644
--- a/docs/chymyst02.md
+++ b/docs/chymyst02.md
@@ -253,7 +253,7 @@ val result = firstResult()
### How to encapsulate the new chemistry
-The code as written works but is not encapsulated - we are defining new molecules and new chemistry inline.
+The code as written works but is not encapsulated -- in this code, we define new molecules and new chemistry inline.
There are two ways we could encapsulate this chemistry:
- create a function that will return the `firstResult` emitter, given the emitters `f` and `g`
@@ -291,11 +291,11 @@ def makeFirstResult[T](f: B[Unit, T], g: B[Unit, T]): B[Unit, T] = {
```
-The main advantage of this code is to encapsulate all the auxiliary molecule emitters within the local scope of the method `makeFirstResult`.
+The main advantage of this code is to encapsulate all the auxiliary molecule emitters within the local scope of the method `makeFirstResult()`.
Only the `firstResult` emitter is returned:
-This is the only emitter that the user of this library needs.
+This is the only emitter that the user of `makeFirstResult()` will need.
The other emitters (`c`, `d`, and `done`) are invisible to the user since they are local variables in the scope of `makeFirstResult`.
-The user of the library cannot break the chemistry by inadvertently emitting some further copies of `c`, `d`, or `done`.
+The user of `makeFirstResult()` cannot break the chemistry by inadvertently emitting some further copies of `c`, `d`, or `done`.
#### Refactoring as a molecule
@@ -426,7 +426,7 @@ site(
c() + d() + result(0)
```
-As an exercise, the reader should now try to encapsulate the `parallelOr` operation into a library function.
+As an exercise, the reader should now try to encapsulate the `parallelOr` operation into a function.
(This is done in the tests in `ParallelOrSpec.scala`.)
As another exercise: Revise these reactions to incorporate more than two blocking emitters (say, `f`, `g`, `h`, `i`, `j`).
diff --git a/docs/chymyst05.md b/docs/chymyst05.md
index c610babb..879ebbf3 100644
--- a/docs/chymyst05.md
+++ b/docs/chymyst05.md
@@ -2,7 +2,7 @@
# Limitations of the Chemical Machine (and how to overcome them)
-While designing the “abstract chemistry” for our application, we need to keep in mind certain limitations of the chemical paradigm.
+While designing the chemical laws for our application, we need to keep in mind that the chemical paradigm limits what we can do (for our own good).
1. We cannot detect the _absence_ of a given non-blocking molecule, say `a(1)`, in the soup.
This seems to be a genuine limitation of the chemical machine paradigm.
@@ -22,11 +22,16 @@ It could happen that `a()` was present but got involved in some other reactions
Another feature would be to introduce “inhibiting” conditions on reactions: a certain reaction can start when molecules `a` and `b` are present but no molecule `c` is present.
However, it is not clear that this extension of the chemical paradigm would be useful.
-The solution based on a “timeout” appears to be sufficient in practice.
+The solution based on a timeout appears to be sufficient in practice.
-2. “Chemical soups” running as different processes (either on the same computer or on different computers) are completely separate and cannot be “pooled”.
+It appears plausible that the chemical machine cannot detect the absence of a molecule.
+Since we can expect molecules to be emitted at random and unpredictable times by concurrently running processes, it is always possible that a certain molecule is, at a given time, not present in the soup but is about to be emitted by some reaction because the emitter has already been called and its task is already waiting in the queue.
-What we would like to do is to connect many chemical machines together, running perhaps on different computers, and to pool their individual “soups” into one large “common soup”.
+The chemical machine forces the programmer to design the chemical laws in such a way that the result of the execution of the program is the same even if random delays were inserted at any point when a molecule is emitted or a reaction needs to be started.
+
+2. Chemical soups running as different processes (either on the same computer or on different computers) are completely separate and cannot be pooled.
+
+What we would like to do is to connect many chemical machines together, running perhaps on different computers, and to pool their individual soups into one large “common soup”.
Our program should then be able to emit lots of molecules into the common pool and thus organize a massively parallel, distributed computation, without worrying about which CPU computes what reaction.
However, in order to organize a distributed computation, we would need to split the tasks explicitly between the participating soups.
The organization and supervision of distributed computations, the maintenance of connections between machines, the handling of disconnections - all this remains the responsibility of the programmer and is not handled automatically by the chemical machine.
@@ -35,13 +40,13 @@ In principle, a sufficiently sophisticated runtime engine could organize a distr
It remains to be seen whether it is feasible and/or useful to implement such a runtime engine.
3. Reactions are immutable: it is impossible to add more reactions at run time to an existing reaction site.
-(This limitation is enforced in `JoinRun` by making reaction sites immutable and invisible to the user.)
+(This limitation is enforced in `Chymyst` by making reaction sites immutable and invisible to the user.)
Once a reaction site declares a certain molecule as an input molecule for some reactions, it is impossible to add further reactions that consume this molecule.
-However, `JoinRun` gives users a different mechanism for writing a reaction site with reactions computed at run time.
-Since reactions are local values (as are molecule emitters), users can first create any number of reactions and store these reactions in an array, before writing a reaction site with these reactions.
-Once all desired reactions have been assembled, users can write a reaction site that uses all the reactions from the array.
+However, it is possible to declare a reaction site with reactions computed at run time.
+Since reactions are local values (as are molecule emitters), users can first create any number of reactions and store these reactions in an array, before declaring a reaction site with these reactions.
+Once all desired reactions have been assembled, users can declare a reaction site that uses all the reactions from the array.
As an (artificial) example, consider the following pattern of reactions:
@@ -63,11 +68,11 @@ a(10)
```
-When this is run, the reactions will cycle through the four molecules `a`, `b`, `c`, `d` while incrementing the value each time, until the value 100 is reached.
+When this is run, the reactions will cycle through the four molecules `a`, `b`, `c`, `d` while incrementing the value each time, until the value 100 or higher is reached by the molecule `d`.
Now, suppose we need to write a reaction site where we have `n` molecules and `n` reactions, instead of just four.
Suppose that `n` is a runtime parameter.
-Since reactions and molecule emitters are local values, we can simply create them and store in a data structure:
+Since molecule emitters and reactions are local values, we can simply create them and store in a data structure:
```scala
@@ -104,102 +109,7 @@ emitters(0)(10)
```
-# Some useful concurrency patterns
-
-## Background jobs
-
-A basic asynchronous task is to start a long background job and get notified when it is done.
-
-A chemical model is easy to invent: the reaction needs no data to start (the calculation can be inserted directly in the reaction body).
-So we define a reaction with a single non-blocking input molecule that carries a `Unit` value.
-The reaction will consume the molecule, do the long calculation, and then emit a `finished(...)` molecule that carries the result value on it.
-
-A convenient implementation is to define a function that will return an emitter that starts the job.
-
-```scala
-/**
-* Prepare reactions that will run a closure and emit a result upon its completion.
-*
-* @tparam R The type of result value
-* @param closure The closure to be run
-* @param finished A previously bound non-blocking molecule to be emitted when the calculation is done
-* @return A new non-blocking molecule that will start the job
-*/
-def submitJob[R](closure: Unit => R, finished: M[R]): M[R] = {
- val startJobMolecule = new M[Unit]
-
- site( go { case startJobMolecule(_) =>
- val result = closure()
- finished(result) }
- )
-
- startJobMolecule
-}
-
-```
-
-The `finished` molecule should be bound to another reaction site.
-
-Another implementation of the same idea will put the `finished` emitter into the molecule value, together with the closure that needs to be run.
-
-However, we lose some polymorphism since Scala values cannot be parameterized by types.
-The `startJobMolecule` cannot have type parameters and has to accept `Any` as a type:
-
-```scala
-val startJobMolecule = new M[(Unit => Any, M[Any])]
-
-site(
- go {
- case startJobMolecule(closure, finished) =>
- val result = closure()
- finished(result)
- }
-)
-
-```
-
-A solution to this difficulty is to create a method that is parameterized by type and returns a `startJobMolecule`:
-
-```scala
-def makeStartJobMolecule[R]: M[(Unit => R, M[R])] = {
- val startJobMolecule = new M[(Unit => R, M[R])]
-
- site(
- go {
- case startJobMolecule(closure, finished) =>
- val result = closure()
- finished(result)
- }
- )
- startJobMolecule
-}
-
-```
-
-## Waiting forever
-
-Suppose we want to implement a function `wait_forever()` that blocks indefinitely, never returning.
-
-The chemical model is that a blocking molecule `wait` reacts with another, non-blocking molecule `godot`; but `godot` never appears in the soup.
-
-We also need to make sure that the molecule `godot()` is never emitted into the soup.
-So we declare `godot` locally within the scope of `wait_forever`, where we'll emit nothing into the soup.
-
-```scala
-def wait_forever: B[Unit, Unit] = {
- val godot = m[Unit]
- val wait = b[Unit, Unit]
-
- site( go { case godot(_) + wait(_, r) => r() } )
- // forgot to emit `godot` here, which is key to starve this reaction.
- wait
-}
-
-```
-
-The function `wait_forever` will return a blocking molecule emitter that will block forever, never returning any value.
-
-## Reaction constructors
+# Reaction constructors
Chemical reactions are static - they must be specified at compile time and cannot be modified at runtime.
`JoinRun` goes beyond this limitation, since reactions in `JoinRun` are values created at run time.
@@ -310,6 +220,7 @@ val (result: M[String], fut: Future[String]) = moleculeFuture[String]
site( go { case a(x) => result(s"finished: $x") } ) // we define our reaction that will eventually emit "result(...)"
ExternalLibrary.consumeUserFuture(fut) // the external library takes our value "fut" and does something with it
-// Some chemistry code that eventually emits _a_ to resolve the result.
+
+// Here should be some chemistry code that eventually emits `a` to start the reaction above.
```
diff --git a/docs/chymyst06.md b/docs/chymyst06.md
index 266673e5..39785843 100644
--- a/docs/chymyst06.md
+++ b/docs/chymyst06.md
@@ -8,7 +8,7 @@ Here are previous implementations of Join Calculus that I was able to find.
- _Join Java_: [von Itzstein et al., 2001-2005](http://www.vonitzstein.com/Project_JoinJava.html). This was a modified Java language compiler, with support for certain Join Calculus constructions. The project is not maintained.
- The `JoCaml` language: [Official site](http://jocaml.inria.fr) and a publication about JoCaml: [Fournet et al. 2003](http://research.microsoft.com/en-us/um/people/fournet/papers/jocaml-afp4-summer-school-02.pdf). This is a dialect of OCaml implemented as a patch to the OCaml compiler. The project is still supported.
- “Join in Scala” compiler patch: [V. Cremet 2003](http://lampwww.epfl.ch/~cremet/misc/join_in_scala/index.html). The project is discontinued.
-- Joins library for .NET: [P. Crusso 2006](http://research.microsoft.com/en-us/um/people/crusso/joins/). The project is available as a binary .NET download from Microsoft Research.
+- Joins library for .NET: [P. Crusso 2006](http://research.microsoft.com/en-us/um/people/crusso/joins/). The project is available as a .NET binary download from Microsoft Research.
- `ScalaJoins`, a prototype implementation in Scala: [P. Haller 2008](http://lampwww.epfl.ch/~phaller/joins/index.html). The project is not maintained.
- `ScalaJoin`: an improvement over `ScalaJoins`, [J. He 2011](https://github.com/Jiansen/ScalaJoin). The project is not maintained.
- Joinads, a not-quite-Join-Calculus implementation in F# and Haskell: [Petricek and Syme 2011](https://www.microsoft.com/en-us/research/publication/joinads-a-retargetable-control-flow-construct-for-reactive-parallel-and-concurrent-programming/). The project is not maintained.
diff --git a/docs/chymyst07.md b/docs/chymyst07.md
new file mode 100644
index 00000000..4cf4dc68
--- /dev/null
+++ b/docs/chymyst07.md
@@ -0,0 +1,1043 @@
+# Patterns of concurrency
+
+To get more familiar with programming the chemical machine, let us now implement a number of simple concurrent programs.
+These programs are somewhat abstract and are chosen to illustrate various patterns of concurrency that are found in real software.
+
+Allen B. Downey's [The little book of semaphores](http://greenteapress.com/semaphores/LittleBookOfSemaphores.pdf) lists many concurrency "puzzles" that he solves in Python using semaphores.
+In this and following chapter, we will use the chemical machine to solve Downey's concurrency puzzles as well as some other problems.
+
+Our approach will be deductive: we start with the problem and reason logically about the molecules and reactions that are necessary to solve it.
+Eventually we deduce the required chemistry and implement it declaratively in `JoinRun`/`Chymyst`.
+
+## Waiting forever
+
+Suppose we want to implement a function `wait_forever()` that blocks indefinitely, never returning.
+
+The chemical machine can block something indefinitely only when we emit a blocking molecule whose consuming reaction never starts.
+We can prevent a reaction from starting only if some input molecule for that reaction is not present in the soup.
+Therefore we wil make a blocking molecule `waiting_for` that reacts with another, non-blocking molecule `godot`; but `godot` never appears.
+
+We also need to make sure that the molecule `godot()` is never emitted into the soup.
+To achieve this, we will declare `godot` locally within the scope of `wait_forever()`, where we _emit nothing_ into the soup.
+
+```scala
+def wait_forever(): B[Unit, Unit] = {
+ val godot = m[Unit]
+ val waiting_for = b[Unit, Unit]
+
+ site ( go { case waiting_for(_, r) + godot(_) => r() } )
+
+ // We do not emit `godot` here, which is the key to preventing this reaction from starting.
+
+ waiting_for // Return the emitter.
+}
+
+```
+
+The function `wait_forever()` will create and return a new blocking molecule emitter that, when called, will block forever, never returning any value.
+Here is example usage:
+
+```scala
+val never = wait_forever() // Declare a new blocking emitter of type B[Unit, Unit].
+
+never.timeout(1 second)() // this will time out in 1 seconds
+never() // this will never return
+
+```
+
+## Background jobs
+
+A basic asynchronous task is to start a long background job and get notified when it is done.
+
+A chemical model is easy to invent: the reaction needs no data to start (the calculation can be inserted directly in the reaction body).
+So we define a reaction with a single non-blocking input molecule that carries a `Unit` value.
+The reaction will consume the molecule, do the long calculation, and then emit a `finished(...)` molecule that carries the result value on it.
+
+A convenient implementation is to define a function that will return an emitter that starts the job.
+
+```scala
+/**
+* Prepare reactions that will run a closure and emit a result upon its completion.
+*
+* @tparam R The type of result value
+* @param closure The closure to be run
+* @param finished A previously bound non-blocking molecule to be emitted when the calculation is done
+* @return A new non-blocking molecule that will start the job
+*/
+def submitJob[R](closure: Unit => R, finished: M[R]): M[R] = {
+ val startJobMolecule = m[Unit] // Declare a new emitter.
+
+ site (
+ go { case startJobMolecule(_) =>
+ val result = closure()
+ finished(result)
+ }
+ )
+
+ startJobMolecule // Return the new emitter.
+}
+
+```
+
+The `finished` molecule should be bound to another reaction site.
+
+Another implementation of the same idea will put the `finished` emitter into the molecule value, together with the closure that needs to be run.
+
+However, we lose some polymorphism since Scala values cannot be parameterized by types.
+The `startJobMolecule` cannot have type parameters and has to accept `Any` as a type:
+
+```scala
+val startJobMolecule = new M[(Unit => Any, M[Any])]
+
+site (
+ go {
+ case startJobMolecule(closure, finished) =>
+ val result = closure()
+ finished(result)
+ }
+)
+
+```
+
+A solution to this difficulty is to create a method that is parameterized by type and returns a `startJobMolecule`:
+
+```scala
+def makeStartJobMolecule[R]: M[(Unit => R, M[R])] = {
+ val startJobMolecule = m[(Unit => R, M[R])]
+
+ site (
+ go {
+ case startJobMolecule(closure, finished) =>
+ val result = closure()
+ finished(result)
+ }
+ )
+ startJobMolecule
+}
+
+```
+
+## Waiting until `n` jobs are finished: non-blocking calls
+
+A frequently used pattern is to start `n` concurrent jobs and wait until all of them are finished.
+
+Suppose that we have started `n` jobs and each job, when done, will emit a _non-blocking_ molecule `done()`.
+We would like to implement a blocking molecule `all_done()` that will block until `n` molecules `done()` are emitted.
+
+To begin reasoning about the necessary molecules and reactions, consider that `done()` must react with some other molecule that keeps track of how many `done()` molecules remain to be seen.
+Call this other molecule `remaining(k)` where `k` is an integer value showing how many `done()` molecules were already seen.
+The reaction should have the form `done() + remaining(k) => ...`, and it is clear that the reaction should consume `done()`, otherwise the reaction will start with it again.
+So the reaction will look like this:
+
+```scala
+val done = m[Unit]
+val remaining = m[Int]
+
+site(
+ go { done(_) + remaining(k) => remaining(k-1) }
+)
+
+remaining(n) // Emit the molecule with value `n`,
+// which is the initial number of remaining `done()` molecules.
+
+```
+
+Now, it remains to implement waiting until all is done.
+The blocking molecule `all_done()` should start its reaction only when we have `remaining(0)` in the soup.
+Therefore, the reaction is
+
+```scala
+val all_done = b[Unit,Unit]
+
+go { all_done(_, reply) + remaining(0) => reply() }
+
+```
+
+Since this reaction consumes `remaining`, it should be declared at the same reaction site as the `done + remaining => ...` reaction.
+
+The complete code is
+
+```scala
+val done = m[Unit]
+val remaining = m[Int]
+val all_done = b[Unit,Unit]
+
+site(
+ go { done(_) + remaining(k) if k>0 => remaining(k-1) }, // Adding a guard to be safe.
+ go { all_done(_, reply) + remaining(0) => reply() }
+)
+
+remaining(n) // Emit the molecule with value `n`,
+// which is the initial number of remaining `done()` molecules.
+
+```
+
+Adding a guard `if k>0` will prevent the first reaction from running once we consume the expected number of `done()` molecules.
+This allows the user to emit more `done()` molecules than expected without disrupting the logic.
+
+### Example usage
+
+How would we use this code?
+Suppose we have `n` copies of a reaction whose completion we need to wait for.
+At the end of that reaction, we will now emit a `done()` molecule.
+After emitting the input molecules for these reactions to start, we call `all_done()` and wait for the completion of all jobs:
+
+```scala
+val begin = m[Int]
+
+site(
+ go { begin(x) => long_calculation(x); done() )}
+)
+val n = 10000
+(1 to n).foreach(begin) // Emit begin(1), begin(2), ..., begin(10000) now.
+
+all_done() // This will block until all reactions are finished.
+
+```
+
+### Refactoring into a function
+
+Consider what is required in order to refactor this functionality into a reusable library function.
+We would like to have a function call such as `make_all_done()` that creates the `all_done()` molecule for us.
+
+The function `make_all_done()` will need to declare a new reaction site.
+The `done()` molecule is an input molecule at the new reaction site.
+Therefore, this molecule cannot be already defined before we perform the call to `make_all_done()`.
+
+We see that the result of the call `make_all_done()` must be the creation of _two_ new molecules: a new `done()` molecule and a new `all_done()` molecule.
+
+The user will then need to make sure that every job emits the `done()` molecule at the end of the job,
+and arrange for all the jobs to start (in whatever way necessary).
+When it becomes necessary to wait until the completion of all jobs, the user code will simply emit the `all_done()` blocking molecule and wait until it returns.
+
+Refactoring an inline piece of chemistry into a reusablefunction is generally done in two steps:
+
+- declare the same molecules and reactions as in the previous code, but now everything is within the scope of a function
+- the function should then return just the new molecule emitters that the user will need to call, but no other molecule emitters
+
+Here is the result of this procedure for our previous code:
+
+```scala
+def make_all_done(n: Int): (E, EE) = {
+ val done = m[Unit]
+ val remaining = m[Int]
+ val all_done = b[Unit,Unit]
+
+ site(
+ go { done(_) + remaining(k) if k>0 => remaining(k-1) }, // Adding a guard to be safe.
+ go { all_done(_, reply) + remaining(0) => reply() }
+ )
+
+ remaining(n)
+
+ (done, all_done)
+}
+
+```
+
+Note that we declared the molecule types to be `E` and `EE`.
+These are the types created by the `m[Unit]` and `m[Unit,Unit]` macro calls.
+The class `E` is a refinement of the class `M[Unit]`, and `EE` is a refinement of `M[Unit,Unit]`.
+The refinements are pure syntactic sugar: they are needed in order to permit the syntax `done()` and `all_done()` without a compiler warning about the missing `Unit` arguments.
+Without them, we would have to write `done(())` and `all_done(())`.
+
+Let us now use the method `make_all_done()` to simplify the example usage code we had in the previous section:
+
+```scala
+val begin = m[Int]
+val n = 10000
+
+val (done, all_done) = make_all_done(n)
+
+site(
+ go { begin(x) => long_calculation(x); done() )}
+)
+
+(1 to n).foreach(begin) // Emit begin(1), begin(2), ..., begin(10000) now.
+
+all_done() // This will block until all reactions are finished.
+
+```
+
+### Waiting until `n` jobs are finished: blocking calls
+
+A variation on the same theme is to detect when `n` jobs are finished, given that each job will emit a _blocking_ molecule `done()` at the end.
+
+In the previous section, we encapsulated the functionality of waiting for `n` non-blocking molecules into a function `make_all_done()`.
+Let us take the code we just saw for `make_all_done()` and try to modify it for the case when `done()` is a blocking molecule.
+The key reaction
+
+```scala
+go { done(_) + remaining(k) if k>0 => remaining(k-1) }
+
+```
+
+now needs to be modified because we must reply to the `done()` molecule at some point in that reaction:
+
+```scala
+go { done(_, r) + remaining(k) if k>0 => r(); remaining(k-1) }
+
+```
+
+In this way, we unblock whatever final cleanup the job needs to do after it signals `done()`.
+All other code in `make_all_done()` remains unchanged.
+
+## Control over a shared resource (mutex, multiplex)
+
+### Single access
+
+Suppose we have an application with many concurrent processes and a shared resource _R_ (say, a database server) that should be only used by one process at a time.
+Let us assume that there is a certain function `doWork()` that will use the resource _R_ when called.
+Our goal is to make sure that `doWork()` is only called by at most one concurrent process at any time.
+While `doWork()` is being evaluated, we consider that the resource _R_ is not available.
+If `doWork()` is already being called by one process, all other processes trying to call `doWork()` should be blocked until the first `doWork()` is finished and the resource _R_ is again available.
+
+How would we solve this problem using the chemical machine?
+Since our only way to control concurrency is by manipulating molecules, we need to organize the chemistry such that `doWork()` is only called when certain molecules are available.
+In other words, `doWork()` must be called by a _reaction_ that consumes certain molecules whose presence or absence we will control.
+The reaction must be of the form `case [some molecules] => ... doWork() ...`.
+Let us call it the "worker reaction".
+There must be no other way to call `doWork()` except by starting this reaction.
+
+Processes that need to call `doWork()` will therefore need to emit a certain molecule that the worker reaction consumes.
+Let us call that molecule `request`.
+The `request` molecule must be a _blocking_ molecule because `doWork()` should be able to block the caller when the resource _R_ is not available.
+
+If the `request` molecule is the only input molecule of the worker reaction, we will be unable to prevent the reaction from starting whenever some process emits a `request` molecule.
+Therefore, we need a second input molecule in the worker reaction.
+Let us call that molecule `access`.
+The worker reaction will then look like this:
+
+```scala
+go { case access(_) + request(_, r) => ... doWork() ... }
+
+```
+
+Suppose some process emits a `request` molecule, and suppose this is the only process that does so at the moment.
+We should then allow the worker reaction to start and to complete `doWork()`.
+Therefore, `access()` must be present at the reaction site: we should have emitted it beforehand.
+
+While `doWork()` is evaluated, the `access()` molecule is absent, so no other copy of the worker reaction can start.
+This is precisely the exclusion behavior we need.
+
+When the `doWork()` function finishes, we need to unblock the calling process by replying to the `request` molecule.
+Perhaps `doWork()` will return a result value: in that case, we should pass this value as the reply value.
+We should also emit the `access()` molecule back into the soup, so that another process will be able to run `doWork`.
+
+After these considerations, the worker reaction becomes
+
+```scala
+site (
+ go { case access(_) + request(_, reply) => reply(doWork()); access() }
+)
+access() // Emit just one copy of `access`.
+
+```
+
+As long as we emit just one copy of the `access` molecule, and as long as `doWork()` is not used elsewhere in the code, we will guarantee that at most one process will call `doWork()` at any time.
+
+### Multiple access
+
+What if we now relax the requirement of single access for the resource _R_?
+Suppose that now, at most `n` concurrent processes should be able to call `doWork()`.
+
+This formulation of the shared resource problem will describe, for instance, the situation where a connection pool with a fixed number of connections should be used to access a database server.
+
+The effect of allowing `n` simultaneous reactions to access the resource _R_ can be achieved simply by emitting `n` copies of the `access()` molecule.
+The worker reaction remains unchanged.
+
+### Refactoring into a function
+
+The following code defines a convenience function that wraps `doWork()` and provides single-access or multiple-access restrictions.
+This illustrates how we can easily and safely package chemistry into a reusable function.
+
+```scala
+def wrapWithAccess[T](allowed: Int, doWork: () => T): () => T = {
+ val access = m[Unit]
+ val request = b[Unit, T]
+
+ site (
+ go { case access(_) + request(_, reply) => reply(doWork()); access() }
+ )
+
+ (1 to n).foreach(_ => access()) // Emit `n` copies of `access`.
+ val result: () => T = () => request()
+ result
+}
+// Example usage:
+val doWorkWithTwoAccesses = wrapWithAccess(2, () => println("do work"))
+// Now `doWork()` will be called by at most 2 processes at a time.
+
+// ... start a new process, in which:
+doWorkWithTwoAccesses()
+
+```
+
+### Providing access tokens
+
+It is often needed to regulate access to resource _R_ by tokens.
+We will now suppose that `doWork()` requires a token, and that we only have a limited set of tokens.
+Therefore, we need to make sure that
+
+- each process that wants to call `doWork()` receives a token from the token set;
+- if all tokens are taken, calls to `doWork()` by other processes are blocked until more tokens become available.
+
+To implement this, we can use the `n`-access restriction on the worker reaction.
+We just need to make sure that every worker reaction receives a token that enables it to `doWork()`, and that it returns the token when the access is no longer needed.
+
+Since the worker reaction already consumes the `access()` molecule, it is clear that we can easily pass the token as the value carried by `access()`.
+We just need to change the type of `access` from `M[Unit]` to `M[TokenType]`, where `TokenType` is the type of the value that we need (which could be a string, a thread, a resource handle, etc.).
+
+Here is the modified code:
+
+```scala
+def wrapWithAccessTokens[T, TokenType](tokens: Set[TokenType], doWork: TokenType => T): () => T = {
+ val access = m[TokenType]
+ val request = b[Unit, T]
+
+ site (
+ go { case access(token) + request(_, reply) => reply(doWork(token)); access(token) }
+ )
+
+ tokens.foreach(access) // Emit `tokens.size` copies of `access(...)`, putting a token on each molecule.
+ val result: () => T = () => request()
+ result
+}
+// Example usage:
+val doWorkWithTwoAccesses = wrapWithAccessTokens(Set("token1", "token2"), t => println(s"do work with token $t"))
+// Now `doWork()` will be called by at most 2 processes at a time.
+
+// ... start a new process, in which:
+doWorkWithTwoAccesses()
+
+```
+
+When concurrent processes emit `request()` molecules, only at most `n` processes will actually do work on the resource at any one time.
+Each process will be assigned a token out of the available set of tokens.
+
+## Concurrent critical sections, or `Object.synchronized`
+
+A "critical section" is a portion of code that cannot be safely called from different processes at the same time.
+We will now implement the following requirements:
+
+- The calls `beginCritical()` and `endCritical()` can be made in any reaction, in this order.
+- The code between these two calls can be executed only by one reaction at a time, among all reactions that call these functions.
+- A reaction that calls `beginCritical()` will be blocked if another reaction already called `beginCritical()` but did not yet call `endCritical()`, and will be unblocked only when that other reaction calls `endCritical`.
+
+This functionality is similar to `Object.synchronized`, which provides synchronized access to a block of reentrant code.
+In our case, the critical section is delimited by two function calls `beginCritical()` and `endCritical()` are separate function calls that can be made at any two points in the code -- including `if` expressions or inside closures -- which is impossible with `synchronized` blocks.
+Also, the `Object.synchronized` construction identifies the synchronized blocks by an `Object` reference: different objects will be responsible for synchronizing different blocks of reentrant code.
+What we would like to allow is _any_ code anywhere to contain any number of critical sections identified by the same `beginCritical()` call.
+
+How can we implement this functionality using the chemical machine?
+Since the only way to communicate between reactions is to emit molecules, `beginCritical()` and `endCritical()` must be molecules.
+Clearly, `beginCritical` must be blocking while `endCritical` does not have to be; so let us make `endCritical` a non-blocking molecule.
+
+What should happen when a process emits `beginCritical()`?
+We must enforce a single-process access to the critical section.
+In other words, a reaction that consumes `beginCritical()` should only start one at a time even if several `beginCritical` molecules are available.
+Therefore, this reaction must also require another input molecule, say `access()`, of which we will only have a single copy emitted into the soup:
+
+```scala
+val beginCritical = b[Unit, Unit]
+val access = m[Unit]
+
+site(
+ go { case beginCritical(_, reply) + access(_) => ???; reply(); ??? }
+)
+access() // Emit only one copy.
+
+```
+
+Just as in the case of single-access resource, we have guaranteed that `beginCritical()` blocks if called more than once.
+All we need to do is insure that there is initially a single copy of `access()` in the soup, and that no further copies of `access()` are ever emitted.
+
+Another requirement is that emitting `endCritical()` must end whatever `beginCritical()` began, but only if `endCritical()` is emitted by the _same reaction_.
+If a different reaction emits `endCritical()`, access to the critical section should not be granted.
+Somehow, the `endCritical()` molecules must be different when emitted by different reactions (however, `beginCritical()` must be the same for all reactions, or else there can't be any contention between them).
+
+Additionally, we would like it to be impossible for any reaction to call `endCritical()` without first calling `beginCritical()`.
+
+One way of achieving this is to make `beginCritical()` return a value that enables us to call `endCritical()`.
+
+When we will use this functionality, we will emit a `beginCritical()` molecule and, since this is a blocking molecule, its emitter will block and return a value, which is the `endCritical` emitter.
+This will enable us to emit `endCritical()` later.
+
+To achieve the uniqueness of `endCritical`, let us implement the call to `beginCritical()` in such a way that it creates each time a new, unique emitter for `endCritical()`, and returns that emitter:
+
+```scala
+val beginCritical = b[Unit, M[Unit]]
+val access = m[Unit]
+
+site (
+ go { case beginCritical(_, reply) + access(_) =>
+ val endCritical = m[Unit] // Declare a new emitter, unique for this call to `beginCritical`.
+ site (
+ go { case endCritical(_) => ??? }
+ )
+ reply(endCritical) // beginCritical() returns the new emitter.
+ }
+)
+access() // Emit only one copy.
+
+```
+
+Since `endCritical` and its reaction site are defined within the local scope of the reaction that consumes `beginCritical()`, each such reaction will create a _chemically unique_ new molecule that no other reactions can emit.
+This will guarantee that reactions cannot end the critical section for other reactions.
+
+Also, since the `endCritical` emitter is created by `beginCritical()`, we cannot possibly call `endCritical()` before calling `beginCritical()`!
+So far, so good.
+
+It remains to make `endCritical()` do something useful when called.
+The obvious thing is to make it emit `access()`.
+The presence of `access()` in the soup will restore the ability of other reactions to enter the critical section.
+
+The code then looks like this:
+
+```scala
+val beginCritical = b[Unit, M[Unit]]
+val access = m[Unit]
+
+site (
+ go { case beginCritical(_, reply) + access(_) =>
+ val endCritical = m[Unit] // Declare a new emitter.
+ site (
+ go { case endCritical(_) => access() }
+ )
+ reply(endCritical) // beginCritical() returns the new emitter.
+ }
+)
+access() // Emit only one copy.
+
+// Example usage:
+val endCritical = beginCritical()
+
+???... // The code of the critical section.
+
+endCritical() // End of the critical section.
+
+```
+
+This implementation works but has a drawback: the user can call `endCritical()` multiple times.
+This will emit multiple `access()` molecules and break the logic of the critical section functionality.
+
+To fix this problem, let us think about how we could prevent `endCritical()` from starting its reaction after the first time it did so.
+The only way to prevent a reaction from starting is to omit an input molecule.
+Therefore, we need to introduce another molecule (say, `beganOnce`) as input into that reaction.
+The reaction will consume that molecule and never emit it again.
+
+```scala
+val beginCritical = b[Unit, M[Unit]]
+val access = m[Unit]
+
+site (
+ go { case beginCritical(_, reply) + access(_) =>
+ val endCritical = m[Unit] // Declare a new emitter.
+ val beganOnce = m[Unit]
+ site (
+ go { case endCritical(_) + beganOnce(_) => access() }
+ )
+ beganOnce() // Emit only one copy.
+ reply(endCritical) // beginCritical() returns the new emitter.
+ }
+)
+access() // Emit only one copy.
+
+// Example usage:
+val endCritical = beginCritical()
+
+???... // The code of the critical section.
+
+endCritical() // End of the critical section.
+
+endCritical() // This has no effect because `beganOnce()` is not available any more.
+
+```
+
+As before, we can easily modify this code to support multiple (but limited) concurrent entry into critical sections or token-based access.
+
+### Refactoring into a function
+
+We would like to be able to create new, unique `beginCritical()` molecules on demand, so that we could have multiple distinct critical sections in our code.
+
+For instance, we could declare two critical sections and use them in three reactions that could run concurrently like this:
+
+```scala
+val beginCritical1 = newCriticalSectionMarker()
+val beginCritical2 = newCriticalSectionMarker()
+
+```
+
+| Reaction 1 | | Reaction 2 | | Reaction 3 |
+|---|---|---|---|---|
+| `beginCritical1()` | | ... | | `beginCritical2()` |
+| `beginCritical2()` | | ... | | ... |
+| (blocked by 3) | | `beginCritical1()` | | ... |
+| (starts running) | | (blocked by 1) | | `endCritical2()` |
+| ... | | (still blocked)| | `beginCritical2()` |
+| `endCritical1()` | | (starts running) | | (blocked by 1) |
+| `endCritical2()` | | ... | | (starts running) |
+| ... | | ... | | ... |
+| ... | | `endCritical1()` | | `endCritical2()` |
+
+The result should be that we can create any number of critical sections that work independently of each other.
+
+In order to package the implementation of the critical section into a function `newCriticalSectionMarker()`,
+we simply declare the chemistry in the local scope of that function and return the molecule emitter:
+
+```scala
+def newCriticalSectionMarker(): B[Unit, M[Unit]] = {
+
+ val beginCritical = b[Unit, M[Unit]]
+ val access = m[Unit]
+
+ site (
+ go { case beginCritical(_, reply) + access(_) =>
+ val endCritical = m[Unit] // Declare a new emitter.
+ val beganOnce = m[Unit]
+ site (
+ go { case endCritical(_) + beganOnce(_) => access() }
+ )
+ beganOnce() // Emit only one copy.
+ reply(endCritical) // beginCritical() returns the new emitter.
+ }
+ )
+ access() // Emit only one copy.
+
+ beginCritical // Return the new emitter.
+}
+
+// Example usage:
+val beginCritical1 = newCriticalSectionMarker()
+// Now we can pass the `beginCritical1` emitter value to several reactions.
+// Suppose we are in one of those reactions:
+val endCritical = beginCritical1()
+
+???... // The code of the critical section 1.
+
+endCritical() // End of the critical section.
+
+```
+
+## Rendezvous, or `java.concurrent.Exchanger`
+
+The "rendezvous" problem is to implement two concurrent processes that perform some computations and wait for each other like this:
+
+| Process 1 | | Process 2 |
+| --- | --- | --- |
+| `val x1 =` compute something | | `val x2 =` compute something |
+| send `x1` to Process 2, wait for reply | | send `x2` to Process 1, wait for reply |
+| `val y1 =` what Process 2 computed as its `x2` | | `val y2 =` what Process 1 computed as its `x1` |
+| `val z = further_computations_1(y1)` | | `val z = further_computations_2(y2)` |
+
+(This functionality is essentially that of `java.concurrent.Exchanger`.)
+
+Let us now figure out the chemistry that will solve this problem.
+
+The two processes must be reactions (since any computation that runs in the chemical machine is a reaction).
+These reactions must start by consuming some initial molecules.
+Let us start by defining these molecules and reactions, leaving undefined places for the next steps:
+
+```scala
+val begin1 = m[Unit]
+val begin2 = m[Unit]
+
+site(
+ go { case begin1(_) =>
+ val x1 = 123 // some computation
+ ??? // send x1 to Process 2 somehow
+ val y1 = ??? // receive value from Process 2
+ val z = further_computation_1(y1)
+ },
+ go { case begin2(_) =>
+ val x2 = 456 // some computation
+ ??? // send x2 to Process 1 somehow
+ val y2 = ??? // receive value from Process 1
+ val z = further_computation_2(y2)
+ }
+)
+begin1() + begin2() // emit both molecules to enable starting the two reactions
+
+```
+
+So far, so good.
+Look at what happens in in Process 1 after `x1` is computed.
+The next step is to send the value `x1` to Process 2.
+The only way we can send data to any other process is by emitting a molecule.
+Therefore, here we must be emitting _some molecule_.
+
+Now, either Process 1 or Process 2 is already running by this time, and so it won't help if we emit a molecule that Process 2 consumes as input.
+Therefore, we must emit a new molecule that neither Process 1 nor Process 2 consume as input.
+
+Also note that each process must wait until the other process sends back its value.
+Therefore, the new molecule must be a blocking molecule.
+
+Let's say that each process would emit its own blocking molecule at this point, and let's call these molecules `barrier1` and `barrier2`.
+The code will look like this:
+
+```scala
+val begin1 = m[Unit]
+val begin2 = m[Unit]
+
+val barrier1 = b[Unit,Unit]
+val barrier2 = b[Unit,Unit]
+
+site(
+ go { case begin1(_) =>
+ val x1 = 123 // some computation
+ barrier1(x1)
+ ??? // send x1 to Process 2 somehow
+ val y1 = ??? // receive value from Process 2
+ val z = further_computation_1(y1)
+ },
+ go { case begin2(_) =>
+ val x2 = 456 // some computation
+ barrier2(x2)
+ ??? // send x2 to Process 1 somehow
+ val y2 = ??? // receive value from Process 1
+ val z = further_computation_2(y2)
+ }
+)
+begin1() + begin2() // emit both molecules to enable starting the two reactions
+
+```
+
+Now we note that blocking molecules can receive reply values.
+Therefore, the call to `barrier1` may receive a reply value.
+This is exactly what we need!
+Let's make `barrier1` return the value that Process 2 sends, and vice versa.
+
+```scala
+val begin1 = m[Unit]
+val begin2 = m[Unit]
+
+val barrier1 = b[Int,Int]
+val barrier2 = b[Int,Int]
+
+site(
+ go { case begin1(_) =>
+ val x1 = 123 // some computation
+ val y1 = barrier1(x1) // receive value from Process 2
+ val z = further_computation_1(y1)
+ },
+ go { case begin2(_) =>
+ val x2 = 456 // some computation
+ val y2 = barrier2(x2) // receive value from Process 1
+ val z = further_computation_2(y2)
+ }
+)
+begin1() + begin2() // emit both molecules to enable starting the two reactions
+
+```
+
+At this point, the molecules `barrier1` and `barrier2` are not yet consumed by any reactions.
+We now need to define some reaction that consumes these molecules.
+It is clear that what we need is a reaction that exchanges the values these two molecules carry.
+The easiest solution is to just let these two molecules react with each other.
+The reaction will then reply to both of them, exchanging the reply values.
+
+```scala
+go { case barrier1(x1, reply1) + barrier2(x2, reply2) => reply1(x2); reply2(x1) }
+
+```
+
+This reaction could be defined at its own reaction site, since it is the only reaction that will consume `barrier1` and `barrier2`.
+(The same is true for the two `begin1` and `begin2` reactions.)
+For simplicity, we will keep all reactions in one reaction site.
+
+The final code looks like this:
+
+```scala
+val begin1 = m[Unit]
+val begin2 = m[Unit]
+
+val barrier1 = b[Int,Int]
+val barrier2 = b[Int,Int]
+
+site(
+ go { case begin1(_) =>
+ val x1 = 123 // some computation
+ val y1 = barrier1(x1) // receive value from Process 2
+ val z = further_computation_1(y1)
+ },
+ go { case begin2(_) =>
+ val x2 = 456 // some computation
+ val y2 = barrier2(x2) // receive value from Process 1
+ val z = further_computation_2(y2)
+ },
+ go { case barrier1(x1, reply1) + barrier2(x2, reply2) => reply1(x2); reply2(x1) }
+)
+begin1() + begin2() // emit both molecules to enable starting the two reactions
+
+```
+
+Working test code for the rendezvous problem is in `Patterns01Spec.scala`.
+
+## Rendezvous with `n` participants
+
+Suppose we need a rendezvous with `n` participants: there are `n` processes (where `n` is a run-time value, not known in advance), and each process would like to wait until all other processes reach the rendezvous point.
+After that, all `n` waiting processes become unblocked and proceed concurrently.
+
+This problem is similar to the rendezvous with two participants that we considered before.
+To simplify the problem, we assume that no data is exchanged -- this is a pure synchronization task.
+
+Let us try to generalize our previous implementation of the rendezvous from 2 participants to `n`.
+Since emitters are values, we could define `n` different emitters `begin1`, ..., `begin_n`, `barrier1`, ..., `barrier_n` and so on.
+We could store these emitters in an array and also define an array of corresponding reactions.
+
+However, we notice a problem in the reaction that performs the rendezvous:
+
+```scala
+go { case barrier1(x1, reply1) + barrier2(x2, reply2) => ... }
+
+```
+
+Generalizing this reaction straightforwardly to `n` participants would now require a reaction with `n` input molecules `barrier1`, ..., `barrier_n`.
+In the chemical machine, input molecules to each reaction must be defined statically.
+Since `n` is a run-time parameter, we cannot define a reaction with `n` input molecules.
+So we cannot generalize from 2 to `n` rendezvous participants in this way.
+
+What we need is to consume all `n` blocking molecules `barrier1`, ..., `barrier_n` and also reply to all of them at the time when we make sure we consumed exactly `n` of them.
+The only way to implement chemistry that consumes `n` molecules (where `n` is a runtime parameter) is to consume one molecule at a time while counting to `n`.
+The count value (showing the number of `barrier()` molecules already consumed) must be carried by another molecule, say `counter`.
+Therefore, we need a reaction like this:
+
+```scala
+go { case barrier(_, reply) + counter(k) => ???; if (k + 1 < n) counter(k + 1); ???; reply() }
+
+```
+
+This reaction should reply to the `barrier()` molecule (as should any reaction that consumes a blocking molecule).
+It is clear that `reply()` should come last: this is the reply to the `barrier()` molecule, which should be performed only after we counted up to `n`.
+Until then, this reaction must be blocked.
+
+The only way to block in the middle of a reaction is to emit a blocking molecule there.
+Therefore, some blocking molecule must be emitted in the reaction before replying to `barrier()`.
+Let us make `counter()` a blocking molecule:
+
+```scala
+go { case barrier(_, reply) + counter(k, replyCounter) => ???; if (k + 1 < n) counter(k + 1); ???; reply() }
+
+```
+
+What is still missing is the reply to the `counter(k)` molecule.
+Now we are faced with a question: at what point should we perform that reply, before emitting `counter(k + 1)` or after?
+We could write one of the two reactions:
+
+```scala
+val reaction1 = go { case barrier(_, reply) + counter(k, replyCounter) => replyCounter(); if (k + 1 < n) counter(k + 1); reply() }
+val reaction2 = go { case barrier(_, reply) + counter(k, replyCounter) => if (k + 1 < n) counter(k + 1); replyCounter(); reply() }
+
+```
+
+We now need to decide whether `reaction1` or `reaction2` works as we want.
+
+To resolve this question, let us visualize the molecules that we'd like to be present at different stages of running the program.
+Suppose that `n=10` and we have already consumed all `barrier` molecules except three.
+We presently have three `barrier()` molecules and one `counter(7)` molecule (which, as we decided, is a blocking molecule).
+
+Note that the `counter(7)` molecule was emitted by a previous reaction of the same kind,
+
+`barrier() + counter(6) => ... counter(7); ... }`
+
+So, this previous reaction is now blocked at the place where it emitted `counter(7)`.
+
+Next, the reaction `barrier() + counter(7) => ...` will start and consume its input molecules, leaving two `barrier()` molecules present.
+
+Now the reaction body of `barrier() + counter(7) => ...` will run and emit `counter(8)`.
+Then we will have the molecules `barrier(), barrier(), counter(8)` in the soup.
+This set of molecules will be the same whether we define `reaction1` or `reaction2`.
+However, in `reaction1` the reply is already sent to `counter(7)` before emitting `counter(8)`.
+This will unblock the previous reaction,
+
+```scala
+{ case barrier(_, reply) + counter(6, replyCounter) => replyCounter(); counter(7); reply() }
+
+```
+
+which was blocked at the call to `counter(7)`.
+Now this reaction can proceed to reply to `barrier()` using `reply()`.
+However, at this point it is too early to send a reply to `barrier()`, because we still have two `barrier()` molecules that we have not yet consumed!
+
+Therefore, `reaction1` is incorrect.
+On the other hand, `reaction2` works correctly.
+It will block at each emission of `counter(k + 1)` and unblock only when `k=n-1`.
+At that time, `reaction2` will reply to the `counter(n-1)` molecule and to the just consumed `barrier()` molecule.
+The reply to the `counter(n-1)` molecule will unblock the copy of `reaction2` that emitted it, which will unblock the next molecules.
+
+In this way, the `n`-rendezvous will require all `n` reactions to wait at the "barrier" until all participants reach the barrier, and then unblock all of them.
+
+It remains to see how the first reaction will start.
+We could emit a `counter(0)` molecule at the initial time.
+This molecule is blocking, so emitting it will block a reaction until the very end of the `n`-rendezvous.
+Alternatively, we can write a special initial reaction such as
+
+```scala
+go { case barrier(_, reply) + counterInit(_) => counter(1); reply() }
+
+```
+
+Then the complete code looks like this:
+
+```scala
+val barrier = b[Unit,Unit]
+val counterInit = m[Unit]
+val counter = b[Int,Unit]
+
+site(
+ go { case barrier(_, reply) + counterInit(_) => // this reaction will consume the very first barrier molecule emitted
+ counter(1) // one reaction has reached the rendezvous point
+ reply()
+ },
+ go { case barrier(_, reply) + counter(k, replyCounter) =>
+ if (k + 1 < n) counter(k + 1)
+ replyCounter()
+ reply()
+ }
+)
+counterInit() // This needs to be emitted initially.
+
+```
+
+Note that this chemistry will block `n` reactions that emit `barrier()` and another set of `n` copies of `reaction2`.
+In the current implementation of `JoinRun`, a blocked reaction will block a thread, so the`n`-rendezvous will require `2*n` new threads that remain blocked until the rendezvous is passed.
+(A future implementation of `JoinRun` might be able to perform a code transformation that never blocks any threads.)
+
+How do we use this `n`-rendezvous?
+Suppose we have a reaction where a certain processing step needs to wait for all other reactions to reach the same step.
+Then we emit the `barrier()` molecule at that step:
+
+```scala
+site (
+ go { case begin(_) =>
+ work()
+ barrier() // need to wait here for other reactions
+ more_work()
+ }
+)
+
+(1 to 1000).foreach (begin) // start 1000 copies of this reaction
+
+```
+
+### Refactoring into a function
+
+As usual when encapsulating some piece of chemistry into a reusable function, we first figure out what new molecule emitters are necessary for the users of the function to be able to run the encapsulated chemistry.
+These new emitters will be returned (say, as a tuple) by the function; all the other chemistry will remain encapsulated within the local scope of the function.
+
+In our case, the users of the function will only need the `barrier()` molecule emitter.
+In fact, users should _not_ have access to `counter` or `counterInit` emitters: if users emit more copies of these molecules, the encapsulated reactions will work incorrectly.
+
+We also note that the number `n` needs to be given in advance, before creating the reaction site for the `barrier` molecule.
+Therefore, we write a function with an integer argument `n`:
+
+```scala
+def makeRendezvous(n: Int): EE = { // We are returning EE, which is a subclass of B[Unit,Unit]
+ val barrier = b[Unit,Unit]
+ val counterInit = m[Unit]
+ val counter = b[Int,Unit]
+
+ site(
+ go { case barrier(_, reply) + counterInit(_) => // this reaction will consume the very first barrier molecule emitted
+ counter(1) // one reaction has reached the rendezvous point
+ reply()
+ },
+ go { case barrier(_, reply) + counter(k, replyCounter) =>
+ if (k + 1 < n) counter(k + 1)
+ replyCounter()
+ reply()
+ }
+ )
+ counterInit() // This needs to be emitted initially.
+
+ barrier // Return only this emitter.
+}
+
+```
+
+The usage example will then look like this:
+
+```scala
+val barrier = makeRendezvous(1000)
+
+site (
+ go { case begin(_) =>
+ work()
+ barrier() // need to wait here for other reactions
+ more_work()
+ }
+)
+
+(1 to 1000).foreach (begin) // start 1000 copies of this reaction
+
+```
+
+
+### Reusable `n`-rendezvous
+
+The `n`-rendezvous as implemented in the previous section has a drawback:
+After `n` reactions have passed the rendezvous point, emitting more `barrier()` molecules will have no effect.
+If another set of `n` reactions needs to participate in an `n`-rendezvous, a new call to `makeRendezvous()` needs to be made in order to produce a whole new reaction site with a new `barrier()` molecule.
+
+In a _reusable_ `n`-rendezvous,
+once a set of `n` participant reactions have passed the rendezvous point, the same `barrier` molecule should automatically become ready to be used again by another set of `n` reactions.
+This can be seen as a batching functionality:
+If reactions emit a large number of `barrier()` molecules, these molecules are split into batches of `n` and an `n`-rendezvous procedure is automatically performed for one batch after another.
+
+Let us see how we can revise the code of `makeRendezvous()` to implement this new requirement.
+We need to consider what molecules will be present after one rendezvous is complete.
+With our present implementation, the reaction site will have no molecules present because the `counter()` molecule will be consumed at the last iteration, and `counterInit()` was consumed at the very beginning.
+At that point, emitting more `barrier()` molecules will therefore not start any reactions.
+
+In order to allow starting the `n`-rendezvous again, we need to make sure that `counterInit()` is again present.
+Therefore, the only needed change is to emit `counterInit()` when the `n`-rendezvous is complete:
+
+```scala
+if (k + 1 < n) counter(k + 1) else counterInit()
+
+```
+
+After this single change, the `n`-rendezvous function becomes a reusable `n`-rendezvous.
+
+## Pair up for dance
+
+In the 18th century Paris, there are two doors that open to the dance floor where men must pair up with women to dance.
+At random intervals, men and women arrive to the dancing place.
+Men queue up at door A, women at door B.
+
+The first man waiting at door A and the first woman waiting at door B will then form a dance pair and go off to dance.
+If a man is first in the queue at door A but no woman is waiting at door B (that is, the other queue is empty), the man needs to wait until a woman arrives and goes off to dance with her.
+Similarly, when a woman is first in the queue at door B and no man is waiting, she needs to wait for the next man to arrive, and then go off to dance with him.
+
+(This problem is sometimes called "Leaders and Followers", but this name is misleading since the roles of the two dance partners are completely symmetric.)
+
+Let us implement a simulation of this problem in the chemical machine.
+
+The problem is about controlling the starting of a reaction (the "dancing" computation).
+The reaction can start when a man and a woman are present.
+It is clear that we can simulate this via two molecules, `man` and `woman`, whose presence is required to start the reaction.
+
+```scala
+go { case man(_) + woman(_) => begin_dancing() }
+
+```
+
+To simplify this example, let us assume that some other reactions will randomly emit `man()` and `woman()` molecules.
+
+The problem with the above reaction is that it does not respect the linear nature of the queue.
+If processes emit several `man()` and `woman()` molecules quickly enough, they will be paired up in random order, rather than in the order of arrival in the queue.
+Also, nothing prevents several pairs to begin dancing at once, regardless of the dancer's positions in the queues.
+
+TODO: expand
+
+## Choose and reply to one of many blocking calls (Unix `select`, Actor Model's `receive`)
+
+The task is to organize the processing of several blocking calls emitted by different concurrent reactions.
+One receiver is available to process one of these calls at a time.
+
+TODO
+
+## Concurrent recursive traversal
+
+TODO
+
diff --git a/docs/counter-incr-decr.svg b/docs/counter-incr-decr.svg
index a14d7589..ec94ec19 100644
--- a/docs/counter-incr-decr.svg
+++ b/docs/counter-incr-decr.svg
@@ -46,5 +46,6 @@
counterdecrn–1
+ counter
\ No newline at end of file
diff --git a/docs/counter-multiple-molecules-after-reaction.svg b/docs/counter-multiple-molecules-after-reaction.svg
new file mode 100644
index 00000000..62c570a4
--- /dev/null
+++ b/docs/counter-multiple-molecules-after-reaction.svg
@@ -0,0 +1,49 @@
+
\ No newline at end of file
diff --git a/docs/counter-multiple-molecules.svg b/docs/counter-multiple-molecules.svg
new file mode 100644
index 00000000..76891411
--- /dev/null
+++ b/docs/counter-multiple-molecules.svg
@@ -0,0 +1,65 @@
+
\ No newline at end of file
diff --git a/docs/counter-multiple-reactions.svg b/docs/counter-multiple-reactions.svg
new file mode 100644
index 00000000..fcb2649e
--- /dev/null
+++ b/docs/counter-multiple-reactions.svg
@@ -0,0 +1,49 @@
+
\ No newline at end of file
diff --git a/docs/joinrun.md b/docs/joinrun.md
index 57456054..ec741b52 100644
--- a/docs/joinrun.md
+++ b/docs/joinrun.md
@@ -487,105 +487,3 @@ val result = site( go { case x(_) => } )
result shouldEqual (())
```
-
-# Version history
-
-- 0.1.3 Major changes in the API ("site", "go" instead of "join", "run") and in the terminology used in the tutorial and in the code: we now use the chemical machine paradigm more consequently, and avoid using the vague term "join". The build system now checks test code coverage (currently at 96%) and uses Scala "wartremover" plugin to check for more possible errors.
-
-- 0.1.2 Bug fixes for singletons and for blocking molecules; benchmarks of blocking molecules.
-
-- 0.1.0 First alpha release of `JoinRun`. Changes: implementing singleton molecules and volatile readers; several important bugfixes.
-
-- 0.0.10 Static checks for livelock and deadlock in reactions, with both compile-time errors and run-time errors.
-
-- 0.0.9 Macros for static analysis of reactions; unrestricted pattern-matching now available for molecule values.
-
-- 0.0.8 Add a timeout option for blocking molecules. Tutorial text and ScalaDocs are almost finished. Minor cleanups and simplifications in the API.
-
-- 0.0.7 Refactor into proper library structure. Add tutorial text and start adding documentation. Minor cleanups. Add `Future`/molecule interface.
-
-- 0.0.6 Initial release on Github. Basic functionality, unit tests.
-
-# Roadmap for the future
-
-These features are considered for implementation in the next versions:
-
-Version 0.1: (Released.) Perform static analysis of reactions, and warn the user about certain situations with unavoidable livelock, deadlock, or nondeterminism.
-
-Version 0.2: Rework the decisions to start reactions.
-In particular, do not lock the entire molecule bag - only lock some groups of molecules that have contention on certain molecule inputs (decide this using static analysis information).
-This will allow us to implement interesting features such as:
-
-- fairness with respect to molecules (random choice of input molecules for reactions)
-- start many reactions at once when possible
-- emit many molecules at once, rather than one by one
-- allow nonlinear input patterns
-
-Version 0.3: Investigate interoperability with streaming frameworks such as Scala Streams, Scalaz Streams, FS2, Akka streams.
-
-Version 0.4: Enterprise readiness: fault tolerance, monitoring, flexible logging, assertions on singleton molecules and perhaps on some other situations, thread fusing for singleton molecule reactions.
-
-Version 0.5: Investigate an implicit distributed execution of chemical reactions ("soup pools").
-
-# Current To-Do List
-
- value * difficulty - description
-
- 2 * 3 - investigate using wait/notify instead of semaphore; does it give better performance? This depends on benchmarking of blocking molecules.
-
- 2 * 3 - support a fixed number of singleton copies; remove Molecule.isSingleton mutable field in favor of a function on getJoinDef
-
- 2 * 3 - detect livelock due to singleton emission (at the moment, they are not considered as present inputs)
-
- 3 * 3 - define a special "switch off" or "quiescence" molecule - per-join, with a callback parameter.
- Also define a "shut down" molecule which will enforce quiescence and then shut down the join pool and the reaction pool.
-
- 5 * 5 - implement fairness with respect to molecules
- * - go through possible values when matching (can do?) Important: reactions can get stuck when molecules are in different order. Or need to shuffle.
-
- 3 * 5 - create and use an RDLL (random doubly linked list) data structure for storing molecule values; benchmark. Or use Vector with tail-swapping?
-
- 2 * 2 - perhaps use separate molecule bags for molecules with unit value and with non-unit value? for Booleans? for blocking and non-blocking? for constants? for singletons?
-
- 4 * 5 - implement multiple emission construction a+b+c so that a+b-> and b+c-> reactions are equally likely to start. Implement starting many reactions concurrently at once, rather than one by one.
-
- 4 * 5 - allow several reactions to be scheduled *truly simultaneously* out of the same reaction site, when this is possible. Avoid locking the entire bag? - perhaps partition it and lock only some partitions, based on reaction site information gleaned using a macro.
-
- 4 * 5 - do not schedule reactions if queues are full. At the moment, RejectedExecutionException is thrown. It's best to avoid this. Molecules should be accumulated in the bag, to be inspected at a later time (e.g. when some tasks are finished). Insert a call at the end of each reaction, to re-inspect the bag.
-
- 3 * 3 - add logging of reactions currently in progress at a given RS. (Need a custom thread class, or a registry of reactions?)
-
- 2 * 2 - refactor ActorPool into a separate project with its own artifact and dependency. Similarly for interop with Akka Stream, Scalaz Task etc.
-
- 2 * 2 - maybe remove default pools altogether? It seems that every pool needs to be stopped.
-
- 3 * 4 - implement "thread fusion" like in iOS/Android: 1) when a blocking molecule is emitted from a thread T and the corresponding reaction site runs on the same thread T, do not schedule a task but simply run the reaction site synchronously (non-blocking molecules still require a scheduled task? not sure); 2) when a reaction is scheduled from a reaction site that runs on thread T and the reaction is configured to run on the same thread, do not schedule a task but simply run the reaction synchronously.
-
- 5 * 5 - is it possible to implement distributed execution by sharing the join pool with another machine (but running the reaction sites only on the master node)?
-
- 3 * 4 - LAZY values on molecules? By default? What about pattern-matching then? Probably need to refactor SyncMol and AsyncMol into non-case classes and change some other logic.
-
- 3 * 5 - Can we implement JoinRun using Future / Promise and remove all blocking and all semaphores?
-
- 2 * 2 - Detect this condition at the reaction site time:
- A cycle of input molecules being subset of output molecules, possibly spanning several reaction sites (a->b+..., b->c+..., c-> a+...). This is a warning if there are nontrivial matchers and an error otherwise.
-
- 2 * 3 - understand the "reader-writer" example; implement it as a unit test
-
- 3 * 2 - add per-molecule logging; log to file or to logger function
-
- 5 * 5 - implement "progress and safety" assertions so that we could prevent deadlock in more cases
- and be able to better reason about our declarative reactions. First, need to understand what is to be asserted.
- Can we assert non-contention on certain molecules? Can we assert deterministic choice of some reactions? Should we assert the number of certain molecules present (precisely N`, or at most N)?
-
- 2 * 4 - allow molecule values to be parameterized types or even higher-kinded types? Need to test this.
-
- 2 * 2 - make memory profiling / benchmarking; how many molecules can we have per 1 GB of RAM?
-
- 3 * 4 - implement nonlinear input patterns
-
- 2 * 2 - annotate join pools with names. Make a macro for auto-naming join pools of various kinds.
-
- 2 * 2 - add tests for Pool such that we submit a closure that sleeps and then submit another closure. Should get / or not get the RejectedExecutionException
-
- 3 * 5 - implement "singleton" molecules with automatic detection of possible singletons; implement automatic thread fusion for singletons
diff --git a/docs/roadmap.md b/docs/roadmap.md
new file mode 100644
index 00000000..7c62ed76
--- /dev/null
+++ b/docs/roadmap.md
@@ -0,0 +1,106 @@
+
+# Version history
+
+- 0.1.4 Simplify API: now users need only one package import. Many more tutorial examples of chemical machine concurrency. Test code coverage is 97%. More compiler warnings enabled (including deprecation warnings). There are now more intelligent "whitebox" macros that generate different subclasses of `M[T]` and `B[T,R]` when `T` or `R` are the `Unit` type, to avoid deprecation warnings with the syntax `f()`.
+
+- 0.1.3 Major changes in the API ("site", "go" instead of "join", "run") and in the terminology used in the tutorial and in the code: we now use the chemical machine paradigm more consistently, and avoid using the vague term "join". The build system now uses the "wartremover" SBT plugin to check for more possible errors. Test code coverage is at 96%.
+
+- 0.1.2 Bug fixes for singletons and for blocking molecules. Documentation revised with help of Philippe Derome. Started to track test code coverage (currently at 95%). New PR builds will not pass if code coverage decreases.
+
+- 0.1.1 Bug fixes for blocking replies; new benchmarks for blocking molecules.
+
+- 0.1.0 First alpha release of `JoinRun`. Changes: implementing singleton molecules and volatile readers; several important bugfixes.
+
+- 0.0.10 Static checks for livelock and deadlock in reactions, with both compile-time errors and run-time errors.
+
+- 0.0.9 Macros for static analysis of reactions; unrestricted pattern-matching now available for molecule values.
+
+- 0.0.8 Add a timeout option for blocking molecules. Tutorial text and ScalaDocs are almost finished. Minor cleanups and simplifications in the API.
+
+- 0.0.7 Refactor into proper library structure. Add tutorial text and start adding documentation. Minor cleanups. Add `Future`/molecule interface.
+
+- 0.0.6 Initial release on Github. Basic functionality, unit tests.
+
+# Roadmap for the future
+
+These features are considered for implementation in the next versions:
+
+Version 0.1: (Released.) Perform static analysis of reactions, and warn the user about certain situations with unavoidable livelock, deadlock, or nondeterminism.
+
+Version 0.2: Rework the decisions to start reactions.
+In particular, do not lock the entire molecule bag - only lock some groups of molecules that have contention on certain molecule inputs (decide this using static analysis information).
+This will allow us to implement interesting features such as:
+
+- fairness with respect to molecules (random choice of input molecules for reactions)
+- start many reactions at once when possible
+- emit many molecules at once, rather than one by one
+- allow nonlinear input patterns
+
+Version 0.3: Investigate interoperability with streaming frameworks such as Scala Streams, Scalaz Streams, FS2, Akka streams.
+
+Version 0.4: Enterprise readiness: fault tolerance, monitoring, flexible logging, assertions on singleton molecules and perhaps on some other situations, thread fusing for singleton molecule reactions.
+
+Version 0.5: Investigate an implicit distributed execution of chemical reactions ("soup pools").
+
+# Current To-Do List
+
+ value * difficulty - description
+
+ 2 * 3 - investigate using wait/notify instead of semaphore; does it give better performance? This depends on benchmarking of blocking molecules.
+
+ 2 * 3 - support a fixed number of singleton copies; remove Molecule.isSingleton mutable field in favor of a function on getJoinDef
+
+ 2 * 3 - detect livelock due to singleton emission (at the moment, they are not considered as present inputs)
+
+ 3 * 3 - define a special "switch off" or "quiescence" molecule - per-join, with a callback parameter.
+ Also define a "shut down" molecule which will enforce quiescence and then shut down the join pool and the reaction pool.
+
+ 5 * 5 - implement fairness with respect to molecules
+ * - go through possible values when matching (can do?) Important: reactions can get stuck when molecules are in different order. Or need to shuffle.
+
+ 3 * 5 - create and use an RDLL (random doubly linked list) data structure for storing molecule values; benchmark. Or use Vector with tail-swapping?
+
+ 2 * 2 - perhaps use separate molecule bags for molecules with unit value and with non-unit value? for Booleans? for blocking and non-blocking? for constants? for singletons?
+
+ 4 * 5 - implement multiple emission construction a+b+c so that a+b-> and b+c-> reactions are equally likely to start. Implement starting many reactions concurrently at once, rather than one by one.
+
+ 4 * 5 - allow several reactions to be scheduled *truly simultaneously* out of the same reaction site, when this is possible. Avoid locking the entire bag? - perhaps partition it and lock only some partitions, based on reaction site information gleaned using a macro.
+
+ 4 * 5 - do not schedule reactions if queues are full. At the moment, RejectedExecutionException is thrown. It's best to avoid this. Molecules should be accumulated in the bag, to be inspected at a later time (e.g. when some tasks are finished). Insert a call at the end of each reaction, to re-inspect the bag.
+
+ 3 * 3 - add logging of reactions currently in progress at a given RS. (Need a custom thread class, or a registry of reactions?)
+
+ 2 * 2 - refactor ActorPool into a separate project with its own artifact and dependency. Similarly for interop with Akka Stream, Scalaz Task etc.
+
+ 2 * 2 - maybe remove default pools altogether? It seems that every pool needs to be stopped.
+
+ 3 * 4 - implement "thread fusion" like in iOS/Android: 1) when a blocking molecule is emitted from a thread T and the corresponding reaction site runs on the same thread T, do not schedule a task but simply run the reaction site synchronously (non-blocking molecules still require a scheduled task? not sure); 2) when a reaction is scheduled from a reaction site that runs on thread T and the reaction is configured to run on the same thread, do not schedule a task but simply run the reaction synchronously.
+
+ 5 * 5 - is it possible to implement distributed execution by sharing the join pool with another machine (but running the reaction sites only on the master node)?
+
+ 3 * 4 - LAZY values on molecules? By default? What about pattern-matching then? Probably need to refactor SyncMol and AsyncMol into non-case classes and change some other logic.
+
+ 3 * 5 - Can we implement JoinRun using Future / Promise and remove all blocking and all semaphores?
+
+ 2 * 2 - Detect this condition at the reaction site time:
+ A cycle of input molecules being subset of output molecules, possibly spanning several reaction sites (a->b+..., b->c+..., c-> a+...). This is a warning if there are nontrivial matchers and an error otherwise.
+
+ 2 * 3 - understand the "reader-writer" example; implement it as a unit test
+
+ 3 * 2 - add per-molecule logging; log to file or to logger function
+
+ 5 * 5 - implement "progress and safety" assertions so that we could prevent deadlock in more cases
+ and be able to better reason about our declarative reactions. First, need to understand what is to be asserted.
+ Can we assert non-contention on certain molecules? Can we assert deterministic choice of some reactions? Should we assert the number of certain molecules present (precisely N`, or at most N)?
+
+ 2 * 4 - allow molecule values to be parameterized types or even higher-kinded types? Need to test this.
+
+ 2 * 2 - make memory profiling / benchmarking; how many molecules can we have per 1 GB of RAM?
+
+ 3 * 4 - implement nonlinear input patterns
+
+ 2 * 2 - annotate join pools with names. Make a macro for auto-naming join pools of various kinds.
+
+ 2 * 2 - add tests for Pool such that we submit a closure that sleeps and then submit another closure. Should get / or not get the RejectedExecutionException
+
+ 3 * 5 - implement "singleton" molecules with automatic detection of possible singletons; implement automatic thread fusion for singletons
diff --git a/joinrun/src/test/scala/code/chymyst/test/Patterns01Spec.scala b/joinrun/src/test/scala/code/chymyst/test/Patterns01Spec.scala
new file mode 100644
index 00000000..18011caa
--- /dev/null
+++ b/joinrun/src/test/scala/code/chymyst/test/Patterns01Spec.scala
@@ -0,0 +1,211 @@
+package code.chymyst.test
+
+import java.util.concurrent.ConcurrentLinkedQueue
+
+import code.chymyst.jc._
+import org.scalatest.{BeforeAndAfterEach, FlatSpec, Matchers}
+import scala.collection.JavaConverters.asScalaIteratorConverter
+import scala.concurrent.duration._
+import scala.language.postfixOps
+
+class Patterns01Spec extends FlatSpec with Matchers with BeforeAndAfterEach {
+
+ var tp: Pool = _
+
+ override def beforeEach(): Unit = {
+ tp = new SmartPool(4)
+ }
+
+ override def afterEach(): Unit = {
+ tp.shutdownNow()
+ }
+
+ behavior of "Chymyst"
+
+ it should "implement barrier (rendezvous without data exchange) for two processes" in {
+ val barrier1 = b[Unit,Unit]
+ val barrier2 = b[Unit,Unit]
+
+ val begin1 = m[Unit]
+ val begin2 = m[Unit]
+
+ val end1 = m[Unit]
+ val end2 = m[Unit]
+ val done = b[Unit, Unit]
+
+ val logFile = new ConcurrentLinkedQueue[String]
+
+ def f1() = logFile.add("f1")
+ def f2() = logFile.add("f2")
+ def g1() = logFile.add("g1")
+ def g2() = logFile.add("g2")
+
+ site(tp)(
+ go { case begin1(_) => f1(); barrier1(); g1(); end1() },
+ go { case begin2(_) => f2(); barrier2(); g2(); end2() },
+ go { case barrier1(_, r1) + barrier2(_, r2) => r1(); r2() },
+ go { case end1(_) + end2(_) + done(_, r) => r() }
+ )
+
+ begin1() + begin2()
+ done()
+ val result: Seq[String] = logFile.iterator().asScala.toSeq
+ // Now, there must be f1 and f2 (in any order) before g1 and g2 (also in any order).
+ // We use `Set` to verify this.
+ result.size shouldEqual 4
+ Set(result(0), result(1)) shouldEqual Set("f1", "f2")
+ Set(result(2), result(3)) shouldEqual Set("g1", "g2")
+ }
+
+ it should "implement exchanger (rendezvous with data exchange) for two processes" in {
+ val barrier1 = b[Int,Int]
+ val barrier2 = b[Int,Int]
+
+ val begin1 = m[Unit]
+ val begin2 = m[Unit]
+
+ val end1 = m[Int]
+ val end2 = m[Int]
+ val done = b[Unit,(Int,Int)]
+
+ site(tp)(
+ go { case begin1(_) =>
+ val x1 = 123 // some computation
+ val y1 = barrier1(x1) // receive value from Process 2
+ val z = y1 * y1 // further computation
+ end1(z)
+ }
+ )
+
+ site(tp)(
+ go { case begin2(_) =>
+ val x2 = 456 // some computation
+ val y2 = barrier2(x2) // receive value from Process 1
+ val z = y2 * y2 // further computation
+ end2(z)
+ }
+ )
+
+ site(tp)(
+ // The values are exchanged in this reaction.
+ go { case barrier1(x1, r1) + barrier2(x2, r2) => r1(x2); r2(x1) }
+ )
+
+ site(tp)(
+ go { case end1(x1) + end2(x2) + done(_, r) => r((x1,x2))}
+ )
+
+ begin1() + begin2() // emit both molecules to enable starting the two reactions
+
+ val result = done()
+ result shouldEqual ((456*456,123*123))
+ }
+
+ it should "implement barrier (rendezvous without data exchange) with 4 processes" in {
+ val barrier1 = b[Unit,Unit]
+ val barrier2 = b[Unit,Unit]
+ val barrier3 = b[Unit,Unit]
+ val barrier4 = b[Unit,Unit]
+
+ val begin1 = m[Unit]
+ val begin2 = m[Unit]
+ val begin3 = m[Unit]
+ val begin4 = m[Unit]
+
+ val end1 = m[Unit]
+ val end2 = m[Unit]
+ val end3 = m[Unit]
+ val end4 = m[Unit]
+ val done = b[Unit, Unit]
+
+ val logFile = new ConcurrentLinkedQueue[String]
+
+ def f1() = logFile.add("f1")
+ def f2() = logFile.add("f2")
+ def f3() = logFile.add("f4")
+ def f4() = logFile.add("f3")
+ def g1() = logFile.add("g1")
+ def g2() = logFile.add("g2")
+ def g3() = logFile.add("g4")
+ def g4() = logFile.add("g3")
+
+ site(tp)(
+ go { case begin1(_) => f1(); barrier1(); g1(); end1() },
+ go { case begin2(_) => f2(); barrier2(); g2(); end2() },
+ go { case begin3(_) => f3(); barrier3(); g3(); end3() },
+ go { case begin4(_) => f4(); barrier4(); g4(); end4() },
+ go { case barrier1(_, r1) + barrier2(_, r2) + barrier3(_, r3) + barrier4(_, r4) => r1(); r2(); r3(); r4() },
+ go { case end1(_) + end2(_) + end3(_) + end4(_) + done(_, r) => r() }
+ )
+
+ begin1() + begin2() + begin3() + begin4()
+ done()
+ val result: Seq[String] = logFile.iterator().asScala.toSeq
+ // Now, there must be f1 and f2 (in any order) before g1 and g2 (also in any order).
+ // We use `Set` to verify this.
+ result.size shouldEqual 8
+ (0 to 3).map(result).toSet shouldEqual Set("f1", "f2", "f3", "f4")
+ (4 to 7).map(result).toSet shouldEqual Set("g1", "g2", "g3", "g4")
+ }
+
+ it should "implement barrier (rendezvous without data exchange) with n processes" in {
+
+ val n = 100 // The number of rendezvous participants needs to be known in advance, or else we don't know how long still to wait for rendezvous.
+
+ // There will be 2*n blocked threads; the test will fail with FixedPool(2*n-1).
+ val pool = new FixedPool(2*n)
+
+ val barrier = b[Unit,Unit]
+ val counterInit = m[Unit]
+ val counter = b[Int,Unit]
+ val endCounter = m[Int]
+ val begin = m[(()=>Unit, ()=>Unit)]
+ val end = m[Unit]
+ val done = b[Unit, Unit]
+
+ val logFile = new ConcurrentLinkedQueue[String]
+
+ def f(n: Int)(): Unit = { logFile.add(s"f$n"); () }
+ def g(n: Int)(): Unit = { logFile.add(s"g$n"); () }
+
+ site(pool)(
+ go { case begin((f,g)) => f(); barrier(); g(); end() }, // this reaction will be run n times because we emit n molecules `begin` with various `f` and `g`
+ go { case barrier(_, replyB) + counterInit(_) => // this reaction will consume the very first barrier molecule emitted
+ counter(1) // one reaction has reached the rendezvous point
+ replyB()
+ },
+ go { case barrier(_, replyB) + counter(k, replyC) => // the `counter` molecule holds the number (k) of the reactions that have reached the rendezvous before this reaction started.
+ if (k + 1 < n) counter(k+1); else println(s"rendezvous passed by $n reactions")
+ replyC() // `replyC()` must be here. Doing `replyC()` before emitting `counter(k+1)` would have unblocked some reactions and allowed them to proceed beyond the rendezvous point without waiting for all others.
+ replyB()
+ },
+ go { case end(_) + endCounter(k) => endCounter(k-1) },
+ go { case endCounter(0) + done(_, r) => r()}
+ )
+
+ (1 to n).foreach(i => begin((f(i),g(i))))
+ counterInit()
+ endCounter(n)
+ done.timeout(1000 millis)() shouldEqual Some(())
+
+ val result: Seq[String] = logFile.iterator().asScala.toSeq
+ result.size shouldEqual 2*n
+ // Now, there must be f_1, ..., f_n (in any order) before g_1, ..., g_n (also in any order).
+ // We use sets to verify this.
+
+ val setF = (0 to n-1).map(result.apply).toSet
+ val setG = (n to 2*n-1).map(result.apply).toSet
+
+ val expectedSetF = (1 to n).map(i => s"f$i").toSet
+ val expectedSetG = (1 to n).map(i => s"g$i").toSet
+
+ setF diff expectedSetF shouldEqual Set()
+ setG diff expectedSetG shouldEqual Set()
+
+ expectedSetF diff setF shouldEqual Set()
+ expectedSetG diff setG shouldEqual Set()
+
+ pool.shutdownNow()
+ }
+
+}
diff --git a/joinrun/src/test/scala/code/chymyst/test/Patterns02Spec.scala b/joinrun/src/test/scala/code/chymyst/test/Patterns02Spec.scala
index ad952a0a..e266f5bf 100644
--- a/joinrun/src/test/scala/code/chymyst/test/Patterns02Spec.scala
+++ b/joinrun/src/test/scala/code/chymyst/test/Patterns02Spec.scala
@@ -6,7 +6,6 @@ import code.chymyst.jc._
import org.scalatest.{BeforeAndAfterEach, FlatSpec, Matchers}
import scala.collection.JavaConverters.asScalaIteratorConverter
-import scala.language.postfixOps
class Patterns02Spec extends FlatSpec with Matchers with BeforeAndAfterEach {
diff --git a/lib/src/main/scala/code/chymyst/jc/Chymyst.scala b/lib/src/main/scala/code/chymyst/jc/Chymyst.scala
index 15072890..f82b05a6 100644
--- a/lib/src/main/scala/code/chymyst/jc/Chymyst.scala
+++ b/lib/src/main/scala/code/chymyst/jc/Chymyst.scala
@@ -3,7 +3,6 @@ package code.chymyst.jc
import Core._
import scala.concurrent.{ExecutionContext, Future, Promise}
-import scala.reflect.ClassTag
import scala.util.{Try, Success, Failure}
object Chymyst {
@@ -14,7 +13,7 @@ object Chymyst {
* @tparam T Type of value carried by the molecule and by the future.
* @return Tuple consisting of new molecule emitter and the new future.
*/
- def moleculeFuture[T : ClassTag](pool: Pool = defaultReactionPool): (M[T], Future[T]) = {
+ def moleculeFuture[T](pool: Pool = defaultReactionPool): (M[T], Future[T]) = {
val f = new M[T]("future")
val p = Promise[T]()
diff --git a/lib/src/main/scala/code/chymyst/jc/Core.scala b/lib/src/main/scala/code/chymyst/jc/Core.scala
index 2e7fcd2a..1d1eadf8 100644
--- a/lib/src/main/scala/code/chymyst/jc/Core.scala
+++ b/lib/src/main/scala/code/chymyst/jc/Core.scala
@@ -3,7 +3,7 @@ package code.chymyst.jc
import java.util.UUID
import java.util.concurrent.ConcurrentLinkedQueue
-import scala.collection.JavaConverters._
+import scala.collection.JavaConverters.asScalaIteratorConverter
import scala.collection.mutable
object Core {
@@ -137,7 +137,7 @@ object Core {
}
- private val errorLog: ConcurrentLinkedQueue[String] = new ConcurrentLinkedQueue[String]()
+ private val errorLog = new ConcurrentLinkedQueue[String]
private[jc] def reportError(message: String): Unit = {
errorLog.add(message)
diff --git a/lib/src/main/scala/code/chymyst/jc/ReactionSite.scala b/lib/src/main/scala/code/chymyst/jc/ReactionSite.scala
index df9aef8f..53f69998 100644
--- a/lib/src/main/scala/code/chymyst/jc/ReactionSite.scala
+++ b/lib/src/main/scala/code/chymyst/jc/ReactionSite.scala
@@ -43,7 +43,7 @@ private[jc] final class ReactionSite(reactions: Seq[Reaction], reactionPool: Poo
/** Complete information about reactions declared in this reaction site.
* Singleton-declaring reactions are not included here.
*/
- private[jc] val reactionInfos: Map[Reaction, List[InputMoleculeInfo]] = nonSingletonReactions.map { r => (r, r.info.inputs) }.toMap
+ private[jc] val reactionInfos: Map[Reaction, List[InputMoleculeInfo]] = nonSingletonReactions.map { r => (r, r.info.inputs) }(scala.collection.breakOut)
// TODO: implement
private val quiescenceCallbacks: mutable.Set[E] = mutable.Set.empty
diff --git a/lib/src/main/scala/code/chymyst/jc/StaticAnalysis.scala b/lib/src/main/scala/code/chymyst/jc/StaticAnalysis.scala
index 819944aa..f26795e2 100644
--- a/lib/src/main/scala/code/chymyst/jc/StaticAnalysis.scala
+++ b/lib/src/main/scala/code/chymyst/jc/StaticAnalysis.scala
@@ -89,9 +89,7 @@ private[jc] object StaticAnalysis {
r1 <- reactions.withFilter(_.info.hasGuard.knownFalse)
r2 <- reactions.withFilter(_ =!= r1)
if allMatchersAreWeakerThan(r1.info.inputsSorted, r2.info.inputsSorted)
- } yield {
- (r1, r2)
- }
+ } yield (r1, r2)
if (suspiciousReactions.nonEmpty) {
val errorList = suspiciousReactions.map{ case (r1, r2) =>
diff --git a/macros/src/test/scala/code/chymyst/jc/MacrosSpec.scala b/macros/src/test/scala/code/chymyst/jc/MacrosSpec.scala
index 2ef46688..65fdbdd0 100644
--- a/macros/src/test/scala/code/chymyst/jc/MacrosSpec.scala
+++ b/macros/src/test/scala/code/chymyst/jc/MacrosSpec.scala
@@ -25,13 +25,19 @@ class MacrosSpec extends FlatSpec with Matchers with BeforeAndAfterEach {
behavior of "macros for defining new molecule emitters"
- it should "compute invocation names for molecule emitters" in {
- val a = m[Int]
+ it should "compute correct names and classes for molecule emitters" in {
+ val a = m[Option[(Int,Int,Map[String,Boolean])]] // complicated type
+ a.isInstanceOf[M[_]] shouldEqual true
+ a.isInstanceOf[E] shouldEqual false
a.toString shouldEqual "a"
val s = b[Map[(Boolean, Unit), Seq[Int]], Option[List[(Int, Option[Map[Int, String]])]]] // complicated type
+ s.isInstanceOf[B[_,_]] shouldEqual true
+ s.isInstanceOf[EB[_]] shouldEqual false
+ s.isInstanceOf[BE[_]] shouldEqual false
+ s.isInstanceOf[EE] shouldEqual false
s.toString shouldEqual "s/B"
}
diff --git a/update_version.sh b/update_version.sh
new file mode 100755
index 00000000..1fd1df12
--- /dev/null
+++ b/update_version.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+VERSION=`git tag --sort=-taggerdate|head -1`
+
+function safe_move {
+ local file1="$1" file2="$2"
+
+ local new_lines=`wc -l < "$file1"`
+ local old_lines=`wc -l < "$file2"`
+ if [ $old_lines -eq $new_lines ]
+ then
+ mv "$file1" "$file2"
+ else
+ echo "Error: '$file1' is somehow corrupt"
+ fi
+}
+
+# README has version at two places
+
+sed -e 's|\(img.shields.io/badge/version-\)[v.0-9]*\(-blue.svg\)|\1'$VERSION'\2|; s|^\(Current released* version is `\)[v.0-9]*\(`.\)$|\1'$VERSION'\2|' < README.md > README.md.new
+
+safe_move README.md.new README.md
+
+# build.sbt has version := "0.1.3",
+
+sed -e 's|^\( * version := "\)[.0-9]*\(", *\)$|\1'$VERSION'\2|' < build.sbt > build.sbt.new
+
+safe_move build.sbt.new build.sbt
+
+# Check whether the version history has been updated, warn otherwise.
+
+grep -q "^- $VERSION " docs/joinrun.md || echo "Warning: docs/joinrun.md does not seem to have information about the current version $VERSION."