You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: notes/techreport.tex
+21-21Lines changed: 21 additions & 21 deletions
Original file line number
Diff line number
Diff line change
@@ -31,7 +31,7 @@ \section{Introduction}
31
31
32
32
Scala-gopher is a library-level implementation of process algebra [Communication Sequential Processes, see \cite{Hoare85communicatingsequential} as ususally enriched by $\pi$-calculus \cite{Milner:1992:CMP:162037.162038} naming primitives] in scala. In addition to support of a 'limbo/go-like'\cite{Inferno:Limbo} \cite{golang} channels/goroutine programming style scala-gopher provides a set of operations following typical idiomatic scala.
33
33
34
-
At first, let's remind the fundamentals of a CSP model. The primary entities of this model are channels, coroutines and selectors. Coroutines are lightweight threads of execution, which can communicate with each other by passing messages between channels. Channels can be viewed as blocked multiproducer/multiconsumer queues. Sending message to unbuffered channel suspends producing coroutines until the moment when this message will have been read by some consumer. Buffered channels transfer control flow between sinks not on each message, but when internal channel buffer is full.
34
+
At first, let's remind the fundamentals of a CSP model. The primary entities of this model are channels, coroutines and selectors. Coroutines are lightweight threads of execution, that can communicate with each other by passing messages between channels. Channels can be viewed as blocked multiproducer/multiconsumer queues. Sending message to unbuffered channel suspends producing coroutines until the moment when this message will have been read by some consumer. Buffered channels transfer control flow between sinks not on each message, but when internal channel buffer is full.
35
35
In such way, communication via channel implicitly provides flow control functionality. At last, a selector statement is a way of coordination of several communication activities: like Unix select(2) system call, select statement suspends current coroutines until one of the actions (reading/writing to one of the channels in selector) will be possible.
36
36
37
37
Let's look at the one simple example:
@@ -56,7 +56,7 @@ \section{Introduction}
56
56
}
57
57
}
58
58
\end{Verbatim}
59
-
Here two channels and three goroutines are created. The first coroutine just generates consecutive numbers and sends one to channel \verb|in|, second - accepts this sequence as the initial state and for each number which has been read from state channel, writes one to \verb|out| and produces next step by filtering previous. The result of the fold is the \verb|in| channel whith applied filters for each prime. The third coroutine just maps range to values to receive a list of first \verb|n| primes in Future.
59
+
Here two channels and three goroutines are created. The first coroutine just generates consecutive numbers and sends one to channel \verb|in|, second - accepts this sequence as the initial state and for each number that has been read from state channel, writes one to \verb|out| and produces next step by filtering previous. The result of the fold is the \verb|in| channel whith applied filters for each prime. The third coroutine just maps range to values to receive a list of first \verb|n| primes in Future.
60
60
61
61
If we look at the sequence of steps during code evaluation, we will see at first generation of
62
62
number, then checks in filters and then if a given number was prime - final output. Note, that goroutine is different from JVM thread of execution: sequential code chunks are executed in configurable executor service; switching between chunks does not use blocking operations.
@@ -66,18 +66,18 @@ \section{Implementation of base constructs }
66
66
67
67
\subsection{Go: Translations of hight-order functions to asynchronous form.}
68
68
69
-
The main entity of CSP is a 'process' which can be viewed as a block of code which handles specific events. In Go CSP processes are represented as goroutines (aka coroutines).
69
+
The main entity of CSP is a 'process' which can be viewed as a block of code that handles specific events. In Go CSP processes are represented as goroutines (aka coroutines).
70
70
71
-
\verb|go[X](x:X):Future[X]| is a thin wrapper arround SIP-22 async/await which does some preprocessing before async transformation:
71
+
\verb|go[X](x:X):Future[X]| is a thin wrapper arround SIP-22 async/await that does some preprocessing before async transformation:
72
72
\begin{itemize}
73
73
\item do transformation of hight-order function in async form.
74
74
75
75
76
-
Let $f(A \To B)\To C$ is a hight-order function, which accepts other function
76
+
Let $f(A \To B)\To C$ is a hight-order function, that accepts other function
77
77
$g:A \To B$ as parameter.
78
-
Let's say that $g$ in $f$ is {\i invocation-only } if $f$ does not store $g$ in memory outside of $f$ scope and doesn't return $g$ as part of return value. Only one action which $f$ can do with $g$ is invocation or passing as a parameter to other invocation-only function. If we look at Scala collection API, we will see, that near all hight-order functions there are invocation-only.
78
+
Let's say that $g$ in $f$ is {\i invocation-only } if $f$ does not store $g$ in memory outside of $f$ scope and doesn't return $g$ as part of return value. The only two things that $f$ can do with $g$ is an invocation or passing it as a parameter to other invocation-only function. If we look at Scala collection API, we will see, that near all hight-order functions there are invocation-only.
79
79
80
-
Now, if we have $g$ which is invocation-only in $f$, and if we have function $g' : (A \To Future[B])$ let build function $f':(A\To Future[B])\to Future[C]$ that if $await(g')==await(g)$ then $await(f'(g'))==f(g))$ in next way
80
+
Now, if we have $g$ which is invocation-only in $f$, and if we have a function $g' : (A \To Future[B])$ let's build function $f':(A\To Future[B])\to Future[C]$ that if $await(g')==await(g)$ then $await(f'(g'))==f(g))$ in the following way
81
81
\begin{itemize}
82
82
\item$f'$ translated to $await(\makebox{transformed-body}(f))$
83
83
\item$g(x)$ inside $f$ translated to $await(g'(x))$
@@ -100,7 +100,7 @@ \subsection{Go: Translations of hight-order functions to asynchronous form.}
100
100
} }
101
101
\end{Verbatim}
102
102
103
-
which after simplification step become
103
+
that after simplification step becomes
104
104
105
105
\begin{Verbatim}[fontsize=\small]
106
106
(1 to n).mapAsync(i => out.aread)
@@ -133,7 +133,7 @@ \subsection{Channels: callbacks organized as waits}
133
133
Here we can read argument type as protocol where each arrow is a step:
134
134
$f$ is called on opportunity to read and
135
135
$ContRead[A,B] \To Option[ContRead.In[A] \To Future[B]]$ means that when reading is
136
-
possible, we can ignore this opportunity (i.e. return None) or return handler which will
136
+
possible, we can ignore this opportunity (i.e. return None) or return handler that will
137
137
consume value (or \verb|end-of-input| or few other special cases) and return future to the next
138
138
computation state.
139
139
@@ -180,7 +180,7 @@ \subsection{Selectors: process composition as event generation}
180
180
181
181
Appropriative expression in CSP syntax: $*[(c_{1} ? x \to P)\square(c_{2} ! y \to Q)]$
182
182
183
-
Scala-gopher provides \verb|select| pseudo-object which provides set of high-order pseudo-functions over
183
+
Scala-gopher provides \verb|select| pseudo-object that provides a set of higher-order pseudo-functions over
184
184
channels, which accept syntax of partial function over channel events:
185
185
186
186
\begin{Verbatim}[fontsize=\small]
@@ -192,7 +192,7 @@ \subsection{Selectors: process composition as event generation}
192
192
}
193
193
\end{Verbatim}
194
194
195
-
or version which must not be wrapped by \verb|go| stamenet:
195
+
or version that must not be wrapped by \verb|go| stamenet:
196
196
197
197
\begin{Verbatim}[fontsize=\small]
198
198
select.aforever {
@@ -225,11 +225,11 @@ \subsection{Selectors: process composition as event generation}
225
225
226
226
Here we see the special syntax for tuple state. Also note, that \verb|afold| macro assumes that \verb|s match| must be the first statement in the argument pseudo-function. \verb|select.exit| is used for returning result from the flow.
227
227
228
-
Events which we can check in select match statement are reading and writing of channels and select timeouts. In future we will think about extending the set of notifications - i.e. adding channel closing and overflow notifications, which are needed in some rare scenarios.
228
+
Events that we can check in select match statement are reading and writing of channels and select timeouts. In future we will think about extending the set of notifications - i.e. adding channel closing and overflow notifications, which are needed in some rare scenarios.
229
229
230
-
\subsection{Transputer: an entity which encapsulates processing node. }
230
+
\subsection{Transputer: an entity that encapsulates processing node. }
231
231
232
-
The idea is to have an actor-like object, which encapsulates processing node: i.e., reads input data
232
+
The idea is to have an actor-like object, that encapsulates processing node: i.e., reads input data
233
233
from the set of input ports; writes a result to the set of output ports and maintaines a local
234
234
mutable state inside.
235
235
@@ -310,7 +310,7 @@ \subsection{ Programming Techniques based on dynamic channels }
310
310
311
311
\item{ Channel-based API where client supply channel where to pass reply }
312
312
313
-
Let we want provide API which must on request return some value to the caller. Instead of providing a method which will return a result on the stack we can provide endpoint channel, which will accept method arguments and channel where to return a result.
313
+
Let we want provide API that must on request return some value to the caller. Instead of providing a method that will return a result on the stack we can provide endpoint channel, that will accept method arguments and channel where to return a result.
314
314
315
315
Next example illustrates this idea:
316
316
@@ -355,7 +355,7 @@ \subsection{ Programming Techniques based on dynamic channels }
355
355
356
356
To register listener channel for receiving notification client sends this channel to newListener
357
357
358
-
The internal state contains message bus represented by a channel which is replaced during each new input message. Each listener spawns the process which reads messages from the current message bus.
358
+
The internal state contains message bus represented by a channel which is replaced during each new input message. Each listener spawns the process that reads messages from the current message bus.
359
359
360
360
361
361
\end{itemize}
@@ -368,26 +368,26 @@ \section{ Connection with other models }
368
368
of composable operations and clear high-level functionality but lack of flexibility,
369
369
at the other side - very flexible but low-level models like actors.
370
370
371
-
Scala-gopher provides uniform API which allows build systems from different parts of spectrum:
371
+
Scala-gopher provides uniform API that allows build systems from different parts of spectrum:
372
372
it is possible to build dataflow graph in a declarative manner and connect one with a dynamic part.
373
373
374
374
The reactive isolates model\cite{Prokopec:2015:ICE:2814228.2814245} is close to scala-gopher model with dynamically-grown channel buffer (except that reactive isolates support distributed case).
375
-
Isolate here corresponds to Transputer, Channel to Output and Events to gopher Input. Channels in reactive isolates are more limited: only one isolate which owns the channel can write to it when in the scala-gopher concept of channel ownership is absent.
375
+
Isolate here corresponds to Transputer, Channel to Output and Events to gopher Input. Channels in reactive isolates are more limited: only one isolate that owns the channel can write to it when in the scala-gopher concept of channel ownership is absent.
376
376
377
-
Communicating Scala Objects\cite{CSO} is a direct implementation of CSP model in Scala which allows
377
+
Communicating Scala Objects\cite{CSO} is a direct implementation of CSP model in Scala that allows
378
378
building expressions in internal Scala DSL, closed to original Hoar notation with some extensions, like extended rendezvous for mapping input streams. Processes in CSO are not lightweight: each process requires Java thread which limits the scalability of this library until lightweight threading will be implemented on JVM level.
379
379
380
380
Subscript\cite{vanDelft:2013:DCL:2489837.2489849} is a Scala extension which adds to language new constructions for building process algebra expressions. Although extending language can afford fine-grained interconnection of process-algebra and imperative language notation in far perspective, now it makes CPA constructs a second-class citizen because we have no direct representation of process and event types in Scala type system.
381
381
382
382
383
383
\section{ Conclusion and future directions }
384
384
385
-
Scala-gopher is a relatively new library which has not yet reached 1.0 state, but we have the early experience
385
+
Scala-gopher is a relatively new library that has not yet reached 1.0 state, but we have the early experience
386
386
reports from using the library for building some helper components in an industrial software project.
387
387
388
388
In general, feedback is positive: developers enjoy a relatively simple mental model and ability to freely use asynchronous operations inside higher-order functions. So, we can recommend to made conversion of invocation-only functions into async form to be available into the async library itself.
389
389
390
-
The area which needs more work: error handling in \verb|go| statements: now \verb|go| returns
390
+
The area that needs more work is an error handling in \verb|go| statements: now \verb|go| returns
391
391
\verb|Future| which can hold a result of the evaluation or an exception. If we ignore statement result then we miss handling of exception; from another side, it unlikely handle errors there, because we must allow a developer to implement own error processing. The workaround is to use different method name for calling statement in the context with ignored return value, but it is easy to mix-up this two names.
392
392
We think, that right solution can be built on language level: we can bind handling of ignored value to type by providing appropriative implicit conversion or use special syntax for functions which needs
0 commit comments