SlideShare a Scribd company logo
CSCSP WITH IDIOMATIC SCALA
SCALA-GOPHER
https://github.com/rssh/scala-gopher
goo.gl/dbT3P7
Ruslan Shevchenko
VertaMedia
scala-gopher
❖ Akka extension + Macros on top of SIP22-async
❖ Integrate CSP Algebra and scala concurrency primitives
❖ Provides:
❖ asynchronous API inside general control-flow
❖ pseudo-synchronous API inside go{ .. } or async{ ..}
blocks
❖ Techreport: goo.gl/dbT3P7
def nPrimes(n:Int):Future[List[Int]]= {
val in = makeChannel[Int]()
val out = makeChannel[Int]()
go {
for(i <- 1 to Int.MaxValue) in.write(i)
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
go {
for(i <- 1 to n) yield out.read
}
}
def nPrimes(n:Int):Future[List[Int]]= {
val in = makeChannel[Int]()
val out = makeChannel[Int]()
go {
for(i <- 1 to n*n) out.write(i)
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
go {
for(i <- 1 to n) yield out.read
}
}
go {
for(i <- 1 to Int.MaxValue)
in.write(i)
}
def nPrimes(n:Int):Future[List[Int]]= {
val in = makeChannel[Int]()
val out = makeChannel[Int]()
go {
for(i <- 1 to Int.MaxValue) in.write(i)
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
go {
for(i <- 1 to n) yield out.read
}
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
def nPrimes(n:Int):Future[List[Int]]= {
val in = makeChannel[Int]()
val out = makeChannel[Int]()
go {
for(i <- 1 to Int.MaxValue) in.write(i)
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
go {
for(i <- 1 to n) yield out.read
}
}
go {
for(i <- 1 to n) yield out.read
}
def nPrimes(n:Int):Future[List[Int]]= {
val in = makeChannel[Int]()
val out = makeChannel[Int]()
go {
for(i <- 1 to Int.MaxValue) in.write(i)
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
go {
for(i <- 1 to n) yield out.read
}
}
Goroutines
❖ go[X](body: X):Future[X]
❖ Wrapper around async +
❖ translation of high-order functions into async form
❖ handling of defer statement
Goroutines
❖ translation of hight-order functions into async form
❖ f(g): f: (A=>B)=>C in g: A=>B,
❖ g is invocation-only in f iff
❖ g called in f or in some h inside f : g invocation-only in h
❖ g is
❖ not stored in memory behind f
❖ not returned from f as return value
❖ Collection API high-order methods are invocation-only
Translation of invocation-only functions
❖ f: ((A=>B)=>C), g: (A=>B), g invocation-only in f
❖ f’: ((A=>Future[B])=>Future[C]) g’: (A=>Future[B])
❖ await(g’) == g => await(f’) == f
❖ f’ => await[translate(f)]
❖ g(x) => await(g’(x))
❖ h(g) => await(h’(g’)) iff g is invocation-only in h
❖ That’s all
❖ (implemented for specific shapes and parts of scala collection
API)
def nPrimes(n:Int):Future[List[Int]]= {
val in = makeChannel[Int]()
val out = makeChannel[Int]()
go {
for(i <- 1 to n*n) in.write(i)
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
go {
for(i <- 1 to n) yield out.read
}
}
go {
for(i <- 1 to n) yield out.read
}
go {
(1 to n).map(i => out.read)
}
async{
await(t[(1 to n).map(i => out.read)])
}
async{
await((1 to n).mapAsync(t[i => async(out.read)]))
}
async{
await((1 to n).mapAsync(i => async(await(out.aread)))
}
mapAsync(i => out.aread)
Channels
❖ Channel[A] <: Input[A] + Output[A]
❖ Unbuffered
❖ Buffered
❖ Dynamically growing buffers [a-la actor mailbox]
❖ One-time channels [Underlaying promise/Future]
❖ Custom
CSP
Input[A] - internal API
trait Input[A]
{
type read = A
def cbread(f: ContRead[A,B]=>Option[
ContRead.In[A] => Future[Continuated[B]])
…..
}
case class ContRead[A,B](
function: F,
channel: Channel[A],
flowTermination: FlowTermination[B]
)
// in ConRead companion object
sealed trait In[+A]
case class Value(a:A) extends In[A]
case class Failure(ex: Throwable] extends In[Nothing]
case object Skip extends In[Nothing]
case object ChannelClosed extends In[Nothing]
ContRead[A,B].F
Continuated[B]
• ContRead
• ContWrite
• Skip
• Done
• Never
Input[A] - external API
trait Input[A]
{
……
def aread: Future[A] = <implementation…>
def read: A = macro <implementation … >
….
def map[B](f: A=>B): Input[B] = ….
// or, zip, filter, … etc
await(aread)
+ usual operations on streams in functional language
Output[A] - API
trait Output[A]
{
type write = A
def cbwrite(f: ContWrite[A,B]=>Option[
(A,Future[Continuated[B]])],
ft: FlowTermination[B])
…..
def awrite(a:A): Future[A] = ….
def write(a:A): A = …. << await(awrite)
….
ContWrite[A,B].F
case class ContWrite[A,B](
function: F,
channel: Channel[A],
flowTermination: FlowTermination[B]
)
Selector ss
go {
for{
select{
case c1 -> x : … // P
case c2 <- y : … // Q
}
}
Go language:
go {
select.forever {
case x : c1.read => … // P
case y : c2.write => … // Q
}
}
Scala:
Provide set of flow combinators:
forever, once, fold
select.aforever {
case x : c1.read => … // P
case y : c2.write => … // Q
}
select: fold API
def fibonacci(c: Output[Long], quit: Input[Boolean]): Future[(Long,Long)] =
select.afold((0L,1L)) { case ((x,y),s) =>
s match {
case x: c.write => (y, x+y)
case q: quit.read =>
select.exit((x,y))
}
}
fold/afold:
• special syntax for tuple support
• ’s’: selector pseudoobject
• s match must be the first statement
• select.exit((..)) to return value from flow
Transputer
❖ Actor-like object with set of input/output ports, which
can be connected by channels
❖ Participate in actor systems supervisors hierarchy
❖ SelectStatement
❖ A+B (parallel execution, common restart)
❖ replicate
Transputer: select
class Zipper[T] extends SelectTransputer
{
val inX: InPort[T]
val inY: InPort[T]
val out: OutPort[(T,T)]
loop {
case x: inX.read => val y = inY.read
out write (x,y)
case y: inY.read => val x = inX.read
out.write((x,y))
}
}
inX
inY
out
Transputer: replicate
val r = gopherApi.replicate[SMTTransputer](10)
( r.dataInput.distribute( (_.hashCode % 10 ) ).
.controlInput.duplicate().
out.share()
)
dataInput
controlInput
share
Programming techniques
❖ Dynamic recursive dataflow schemas
❖ configuration in state
❖ Channel-based two-wave generic API
❖ expect channels for reply
Dynamic recursive dataflow
select.fold(output){ (out, s) => s match {
case x:input.read => select.once {
case x:out.write =>
case select.timeout => control.distributeBandwidth match {
case Some(newOut) => newOut.write(x)
out | newOut
case None => control.report("Can't increase bandwidth")
out
}
}
case select.timeout => out match {
case OrOutput(frs,snd) => snd.close
frs
case _ => out
}
}
dynamically increase and decrease bandwidth in dependency from load
Dynamic recursive dataflow
select.fold(output){ (out, s) => s match {
case x:input.read => select.once {
case x:out.write =>
case select.timeout => control.distributeBandwidth match {
case Some(newOut) => newOut.write(x)
out | newOut
case None => control.report("Can't increase bandwidth")
out
}
}
case select.timeout => out match {
case OrOutput(frs,snd) => snd.close
frs
case _ => out
}
}
dynamically increase and decrease bandwidth in dependency from load
case select.timeout =>
control.distributeBandwidth match {
case Some(newOut) => newOut.write(x)
out | newOut
case None =>
control.report("Can't increase bandwidth")
out
Dynamic recursive dataflow
select.fold(output){ (out, s) => s match {
case x:input.read => select.once {
case x:out.write =>
case select.timeout => control.distributeBandwidth match {
case Some(newOut) => newOut.write(x)
out | newOut
case None => control.report("Can't increase bandwidth")
out
}
}
case select.timeout => out match {
case OrOutput(frs,snd) => snd.close
frs
case _ => out
}
}
dynamically increase and decrease bandwidth in dependency from load
case select.timeout => out match {
case OrOutput(frs,snd) => snd.close
frs
case _ => out
}
Channel-based generic API
❖ Endpoint instead function call
❖ f: A=>B
❖ endpoint: Channel[A,Channel[B]]
❖ Recursive
❖ case class M(A,Channel[M])
❖ f: (A,M) => M (dataflow configured by input)
Channel-based generic API
trait Broadcast[T]
{
val listeners: Output[Channel[T]]
val messages: Output[T]
def send(v:T):Unit = { messages.write(v) }
….
• message will received by all listeners
Channel-based generic API
class BroadcastImpl[T]
{
val listeners: Channel[Channel[T]]
val messages: Channel[T] = makeChannel[Channel[T]]
def send(v:T):Unit = { messages.write(v) }
….
}
// private part
case class Message(next:Channel[Message],value:T)
select.afold(makeChannel[Message]) { (bus, s) =>
s match {
case v: messages.read => val newBus = makeChannel[Message]
current.write(Message(newBus,v))
newBus
case ch: listeners.read => select.afold(bus) { (current,s) =>
s match {
case msg:current.read => ch.awrite(msg.value)
current.write(msg)
msg.next
}
}
current
Channel-based generic API
val listeners: Channel[Channel[T]]
val messages: Channel[T] = makeChannel[]
// private part
case class Message(next:Channel[Message],value:T)
select.afold(makeChannel[Message]) { (bus, s) =>
s match {
case v: message.read => val newBus = makeChannel[Message]
current.write(Message(newBus,v))
newBus
case ch: listener.read => select.afold(bus) { (current,s) =>
s match {
case msg:current.read => ch.awrite(msg.value)
current.write(msg)
msg.next
}
}
• state - channel [bus], for which all listeners are subscribed
• on new message - send one to bus with pointer to the next bus state
• listener on new message in bus - handle, change current and send again
• on new listener - propagate
Channel-based generic API
val listener: Channel[Channel[T]]
val message: Channel[T] = makeChannel[]
// private part
case class Message(next:Channel[Message],value:T)
select.afold(makeChannel[Message]) { (bus, s) =>
s match {
case v: message.read => val newBus = makeChannel[Message]
current.write(Message(newBus,v))
newBus
case ch: listener.read => select.afold(bus) { (current,s) =>
s match {
case msg:current.read => ch.awrite(msg.value)
msg.next
}
}
current
• state - channel [bus], for which all listeners are subscribed
• on new message - send one to bus with pointer to the next bus state
• listener on new message in bus - handle, change current and send again
• on new listener - propagate
s match {
case msg:current.read => ch.awrite(msg.value)
current.write(msg)
msg.next
}
Channel-based generic API
val listener: Channel[Channel[T]]
val message: Channel[T] = makeChannel[]
// private part
case class Message(next:Channel[Message],value:T)
select.afold(makeChannel[Message]) { (bus, s) =>
s match {
case v: message.read => val newBus = makeChannel[Message]
current.write(Message(newBus,v))
newBus
case ch: listener.read => select.afold(bus) { (current,s) =>
s match {
case msg:current.read => ch.awrite(msg.value)
current.write(msg)
msg.next
}
}
current
• state - channel [bus], for which all listeners are subscribed
• on new message - send one to bus with pointer to the next bus state
• listener on new message in bus - handle, change current and send again
•
val newBus = makeChannel[Message]
current.write(Message(newBus,v))
newBus
Scala concurrency libraries
Flexibility
Scalability
Level
Actors
• Actors
• low level,
• great flexibility and scalability
• Akka-Streams
• low flexibility
• hight-level, scalable
• SCO
• low scalability
• hight-level, flexible
• Reactive Isolated
• hight-level, scalable,
• allows delegation
• Gopher
• can emulate each style
Streams
SCO
Subscript
Language
Gopher vs Reactive Isolates
• Isolate
• Events
• Channel
• Transputer/fold
• Input
• Output
Gopher Isolates
One writerMany writers
Channel must have owner
Local Distributed
Loosely coupled (growing buffer)CSP + growing buffer
Scala-gopher: early experience reports
❖ Not 1.0 yet
❖ Helper functionality in industrial software projects.
(utilities, small team)
❖ Generally: positive
❖ transformation of invocation-only hight-order methods
into async form
❖ recursive dynamic data flows
❖ Error handling needs some boilerplate
Error handling: language level issue
val future = go {
………
throw some exception
}
go {
……….
throw some exception
}
Go {
…………
throw some exception
}
Core scala library:
Future.apply
(same issue)
Error is ignored
Developers miss-up Go/go
Errors in ignored value: possible language changes.
❖ Possible solutions:
❖ Optional implicit conversion for ignored value
❖ Special optional method name for calling with ignored value
❖ Special return type
trait Ignored[F]
object Future
{
implicit def toIgnored(f:Future):Ignored[Future] =
….
def go[X](f: X): Future[X]
def go_ignored[X](f:X): Unit
def go(f:X): Ignored[Future[X]] =
Scala-Gopher: Future directions
❖ More experience reports (try to use)
❖ Extended set of notifications
❖ channel.close, overflow
❖ Distributed case
❖ new channel types with explicit distributed semantics
Scala-Gopher: Conclusion
❖ Native integration of CSP into Scala is possible
❖ have a place in a Scala concurrency model zoo
❖ Bring well-established techniques to Scala world
❖ (recursive dataflow schemas; channel API)
❖ Translation of invocation-only high-order functions into
async form can be generally recommended.
❖ (with TASTY transformation inside libraries can be done
automatically)
Thanks for attention
❖ Questions ?
❖ https://github.com/rssh/scala-gopher
❖ ruslan shevchenko: ruslan@shevchenko.kiev.ua

More Related Content

What's hot (20)

PDF
Programming Languages: some news for the last N years
Ruslan Shevchenko
 
PDF
JDK8 Functional API
Justin Lin
 
PDF
Scala introduction
vito jeng
 
KEY
Scala: functional programming for the imperative mind
Sander Mak (@Sander_Mak)
 
PPTX
Fun with Lambdas: C++14 Style (part 2)
Sumant Tambe
 
KEY
Scala clojure techday_2011
Thadeu Russo
 
PDF
Introduction to kotlin for android app development gdg ahmedabad dev fest 2017
Hardik Trivedi
 
PPTX
Compile time polymorphism
ForwardBlog Enewzletter
 
PDF
Lego: A brick system build by scala
lunfu zhong
 
PDF
Fun with Lambdas: C++14 Style (part 1)
Sumant Tambe
 
PDF
Introduction to D programming language at Weka.IO
Liran Zvibel
 
PDF
Introduction to kotlin
NAVER Engineering
 
PPTX
C++ overview
Prem Ranjan
 
PDF
Swift and Kotlin Presentation
Andrzej Sitek
 
PDF
Introduction To Lisp
kyleburton
 
PDF
Kotlin boost yourproductivity
nklmish
 
PPT
Gentle introduction to modern C++
Mihai Todor
 
PDF
Scalaz Stream: Rebirth
John De Goes
 
PDF
C++11 Idioms @ Silicon Valley Code Camp 2012
Sumant Tambe
 
PDF
The Kotlin Programming Language, Svetlana Isakova
Vasil Remeniuk
 
Programming Languages: some news for the last N years
Ruslan Shevchenko
 
JDK8 Functional API
Justin Lin
 
Scala introduction
vito jeng
 
Scala: functional programming for the imperative mind
Sander Mak (@Sander_Mak)
 
Fun with Lambdas: C++14 Style (part 2)
Sumant Tambe
 
Scala clojure techday_2011
Thadeu Russo
 
Introduction to kotlin for android app development gdg ahmedabad dev fest 2017
Hardik Trivedi
 
Compile time polymorphism
ForwardBlog Enewzletter
 
Lego: A brick system build by scala
lunfu zhong
 
Fun with Lambdas: C++14 Style (part 1)
Sumant Tambe
 
Introduction to D programming language at Weka.IO
Liran Zvibel
 
Introduction to kotlin
NAVER Engineering
 
C++ overview
Prem Ranjan
 
Swift and Kotlin Presentation
Andrzej Sitek
 
Introduction To Lisp
kyleburton
 
Kotlin boost yourproductivity
nklmish
 
Gentle introduction to modern C++
Mihai Todor
 
Scalaz Stream: Rebirth
John De Goes
 
C++11 Idioms @ Silicon Valley Code Camp 2012
Sumant Tambe
 
The Kotlin Programming Language, Svetlana Isakova
Vasil Remeniuk
 

Viewers also liked (20)

PDF
8 minutes of functional primitives
Arthur Kushka
 
PDF
scala-gopher: async implementation of CSP for scala
Ruslan Shevchenko
 
PPTX
Karylronco
Angelyn Lingatong
 
PDF
Openstack 101 by Jason Kalai
MyNOG
 
PDF
dgdgdgdgd
Thiago Sturmer
 
PPTX
Mig gig first draft
alabamabirdman
 
PDF
D11jl
maximocotele
 
PDF
Khoa van-tay-kaba-u10-fingerprint-doorlock-signed
Protocol Corporation
 
PDF
X2 t08 04 inequality techniques (2012)
Nigel Simmons
 
PDF
PMD PMP DIPLOMA
Sultan El Sherbiny
 
PDF
0721
wzsse
 
PDF
Karmapa visit singapore 1999 magazine 噶瑪巴駕臨新加坡特刊
Lin Zhang Sheng
 
PPTX
Student Facilitator Presentation
Zoe Christo
 
PPTX
对Cite space生成的kml文件进行可视化
cueb
 
PPT
Versos
guest3dd12d
 
PDF
Zhao_Work samples
Yajing Zhao
 
PDF
Reference: Mobile payment industry in china 2012-2015
C. Keiko Funahashi
 
PPT
Building A Social Network Waa 1 17 07 V2 Draft
Marshall Sponder
 
PDF
INGLES A1
Johanna Parra Avila
 
PPTX
Example of arrogance in quran the story of qarun and haman
Amel Hope
 
8 minutes of functional primitives
Arthur Kushka
 
scala-gopher: async implementation of CSP for scala
Ruslan Shevchenko
 
Karylronco
Angelyn Lingatong
 
Openstack 101 by Jason Kalai
MyNOG
 
dgdgdgdgd
Thiago Sturmer
 
Mig gig first draft
alabamabirdman
 
Khoa van-tay-kaba-u10-fingerprint-doorlock-signed
Protocol Corporation
 
X2 t08 04 inequality techniques (2012)
Nigel Simmons
 
PMD PMP DIPLOMA
Sultan El Sherbiny
 
0721
wzsse
 
Karmapa visit singapore 1999 magazine 噶瑪巴駕臨新加坡特刊
Lin Zhang Sheng
 
Student Facilitator Presentation
Zoe Christo
 
对Cite space生成的kml文件进行可视化
cueb
 
Versos
guest3dd12d
 
Zhao_Work samples
Yajing Zhao
 
Reference: Mobile payment industry in china 2012-2015
C. Keiko Funahashi
 
Building A Social Network Waa 1 17 07 V2 Draft
Marshall Sponder
 
Example of arrogance in quran the story of qarun and haman
Amel Hope
 
Ad

Similar to Scala-Gopher: CSP-style programming techniques with idiomatic Scala. (20)

PDF
Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Ruslan Shevchenko
 
PDF
Go a crash course
Eleanor McHugh
 
PDF
Java/Scala Lab: Руслан Шевченко - Implementation of CSP (Communication Sequen...
GeeksLab Odessa
 
PDF
N flavors of streaming
Ruslan Shevchenko
 
PDF
Csp scala wixmeetup2016
Ruslan Shevchenko
 
PDF
Generic Functional Programming with Type Classes
Tapio Rautonen
 
PDF
Scala Functional Patterns
league
 
PDF
Fp in scala with adts part 2
Hang Zhao
 
PDF
Fs2 - Crash Course
Lukasz Byczynski
 
PPT
Unit 5 Foc
JAYA
 
PPTX
functions
Makwana Bhavesh
 
PDF
46630497 fun-pointer-1
AmIt Prasad
 
PDF
Clojure+ClojureScript Webapps
Falko Riemenschneider
 
PDF
Делаем пользовательское Api на базе Shapeless
Вадим Челышов
 
PPTX
function in c
subam3
 
PPT
Implementation of 'go-like' language constructions in scala [english version]
Ruslan Shevchenko
 
PPT
Functions and pointers_unit_4
MKalpanaDevi
 
PPTX
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...
Data Con LA
 
PDF
Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]
Chris Adamson
 
Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Ruslan Shevchenko
 
Go a crash course
Eleanor McHugh
 
Java/Scala Lab: Руслан Шевченко - Implementation of CSP (Communication Sequen...
GeeksLab Odessa
 
N flavors of streaming
Ruslan Shevchenko
 
Csp scala wixmeetup2016
Ruslan Shevchenko
 
Generic Functional Programming with Type Classes
Tapio Rautonen
 
Scala Functional Patterns
league
 
Fp in scala with adts part 2
Hang Zhao
 
Fs2 - Crash Course
Lukasz Byczynski
 
Unit 5 Foc
JAYA
 
functions
Makwana Bhavesh
 
46630497 fun-pointer-1
AmIt Prasad
 
Clojure+ClojureScript Webapps
Falko Riemenschneider
 
Делаем пользовательское Api на базе Shapeless
Вадим Челышов
 
function in c
subam3
 
Implementation of 'go-like' language constructions in scala [english version]
Ruslan Shevchenko
 
Functions and pointers_unit_4
MKalpanaDevi
 
Big Data Day LA 2016/ Hadoop/ Spark/ Kafka track - Iterative Spark Developmen...
Data Con LA
 
Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]
Chris Adamson
 
Ad

More from Ruslan Shevchenko (20)

PDF
Svitla talks 2021_03_25
Ruslan Shevchenko
 
PDF
Akka / Lts behavior
Ruslan Shevchenko
 
PDF
Papers We Love / Kyiv : PAXOS (and little about other consensuses )
Ruslan Shevchenko
 
PDF
Scala / Technology evolution
Ruslan Shevchenko
 
PDF
{co/contr} variance from LSP
Ruslan Shevchenko
 
PDF
Scala jargon cheatsheet
Ruslan Shevchenko
 
PDF
Java & low latency applications
Ruslan Shevchenko
 
PDF
R ext world/ useR! Kiev
Ruslan Shevchenko
 
PDF
Jslab rssh: JS as language platform
Ruslan Shevchenko
 
PDF
Behind OOD: domain modelling in post-OO world.
Ruslan Shevchenko
 
PDF
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
Ruslan Shevchenko
 
PDF
Ruslan.shevchenko: most functional-day-kiev 2014
Ruslan Shevchenko
 
PDF
Web architecture - overview of techniques.
Ruslan Shevchenko
 
PDF
R scala 17_05_2014
Ruslan Shevchenko
 
ODP
Javascript in modern scala backend. [russian]
Ruslan Shevchenko
 
PDF
Osdn2013 rssh
Ruslan Shevchenko
 
ODP
implementation of 'go'-like language constructions in scala (russian)
Ruslan Shevchenko
 
ODP
Play/Scala as application platform (for http://wbcamp.in.ua 2013)
Ruslan Shevchenko
 
ODP
Iteratee explained.
Ruslan Shevchenko
 
Svitla talks 2021_03_25
Ruslan Shevchenko
 
Akka / Lts behavior
Ruslan Shevchenko
 
Papers We Love / Kyiv : PAXOS (and little about other consensuses )
Ruslan Shevchenko
 
Scala / Technology evolution
Ruslan Shevchenko
 
{co/contr} variance from LSP
Ruslan Shevchenko
 
Scala jargon cheatsheet
Ruslan Shevchenko
 
Java & low latency applications
Ruslan Shevchenko
 
R ext world/ useR! Kiev
Ruslan Shevchenko
 
Jslab rssh: JS as language platform
Ruslan Shevchenko
 
Behind OOD: domain modelling in post-OO world.
Ruslan Shevchenko
 
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
Ruslan Shevchenko
 
Ruslan.shevchenko: most functional-day-kiev 2014
Ruslan Shevchenko
 
Web architecture - overview of techniques.
Ruslan Shevchenko
 
R scala 17_05_2014
Ruslan Shevchenko
 
Javascript in modern scala backend. [russian]
Ruslan Shevchenko
 
Osdn2013 rssh
Ruslan Shevchenko
 
implementation of 'go'-like language constructions in scala (russian)
Ruslan Shevchenko
 
Play/Scala as application platform (for http://wbcamp.in.ua 2013)
Ruslan Shevchenko
 
Iteratee explained.
Ruslan Shevchenko
 

Recently uploaded (20)

PDF
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
PDF
Powering GIS with FME and VertiGIS - Peak of Data & AI 2025
Safe Software
 
PDF
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
PDF
Salesforce CRM Services.VALiNTRY360
VALiNTRY360
 
PPTX
Java Native Memory Leaks: The Hidden Villain Behind JVM Performance Issues
Tier1 app
 
PDF
HiHelloHR – Simplify HR Operations for Modern Workplaces
HiHelloHR
 
PPTX
The Role of a PHP Development Company in Modern Web Development
SEO Company for School in Delhi NCR
 
PPT
MergeSortfbsjbjsfk sdfik k
RafishaikIT02044
 
PPTX
Writing Better Code - Helping Developers make Decisions.pptx
Lorraine Steyn
 
PDF
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
PPTX
An Introduction to ZAP by Checkmarx - Official Version
Simon Bennetts
 
PDF
Executive Business Intelligence Dashboards
vandeslie24
 
PPTX
MiniTool Power Data Recovery Full Crack Latest 2025
muhammadgurbazkhan
 
PDF
Revenue streams of the Wazirx clone script.pdf
aaronjeffray
 
PPTX
Tally software_Introduction_Presentation
AditiBansal54083
 
PDF
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
PDF
Understanding the Need for Systemic Change in Open Source Through Intersectio...
Imma Valls Bernaus
 
PPTX
Fundamentals_of_Microservices_Architecture.pptx
MuhammadUzair504018
 
PPTX
Migrating Millions of Users with Debezium, Apache Kafka, and an Acyclic Synch...
MD Sayem Ahmed
 
PPTX
A Complete Guide to Salesforce SMS Integrations Build Scalable Messaging With...
360 SMS APP
 
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
Powering GIS with FME and VertiGIS - Peak of Data & AI 2025
Safe Software
 
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
Salesforce CRM Services.VALiNTRY360
VALiNTRY360
 
Java Native Memory Leaks: The Hidden Villain Behind JVM Performance Issues
Tier1 app
 
HiHelloHR – Simplify HR Operations for Modern Workplaces
HiHelloHR
 
The Role of a PHP Development Company in Modern Web Development
SEO Company for School in Delhi NCR
 
MergeSortfbsjbjsfk sdfik k
RafishaikIT02044
 
Writing Better Code - Helping Developers make Decisions.pptx
Lorraine Steyn
 
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
An Introduction to ZAP by Checkmarx - Official Version
Simon Bennetts
 
Executive Business Intelligence Dashboards
vandeslie24
 
MiniTool Power Data Recovery Full Crack Latest 2025
muhammadgurbazkhan
 
Revenue streams of the Wazirx clone script.pdf
aaronjeffray
 
Tally software_Introduction_Presentation
AditiBansal54083
 
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
Understanding the Need for Systemic Change in Open Source Through Intersectio...
Imma Valls Bernaus
 
Fundamentals_of_Microservices_Architecture.pptx
MuhammadUzair504018
 
Migrating Millions of Users with Debezium, Apache Kafka, and an Acyclic Synch...
MD Sayem Ahmed
 
A Complete Guide to Salesforce SMS Integrations Build Scalable Messaging With...
360 SMS APP
 

Scala-Gopher: CSP-style programming techniques with idiomatic Scala.

  • 1. CSCSP WITH IDIOMATIC SCALA SCALA-GOPHER https://github.com/rssh/scala-gopher goo.gl/dbT3P7 Ruslan Shevchenko VertaMedia
  • 2. scala-gopher ❖ Akka extension + Macros on top of SIP22-async ❖ Integrate CSP Algebra and scala concurrency primitives ❖ Provides: ❖ asynchronous API inside general control-flow ❖ pseudo-synchronous API inside go{ .. } or async{ ..} blocks ❖ Techreport: goo.gl/dbT3P7
  • 3. def nPrimes(n:Int):Future[List[Int]]= { val in = makeChannel[Int]() val out = makeChannel[Int]() go { for(i <- 1 to Int.MaxValue) in.write(i) } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } } go { for(i <- 1 to n) yield out.read } }
  • 4. def nPrimes(n:Int):Future[List[Int]]= { val in = makeChannel[Int]() val out = makeChannel[Int]() go { for(i <- 1 to n*n) out.write(i) } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } } go { for(i <- 1 to n) yield out.read } } go { for(i <- 1 to Int.MaxValue) in.write(i) }
  • 5. def nPrimes(n:Int):Future[List[Int]]= { val in = makeChannel[Int]() val out = makeChannel[Int]() go { for(i <- 1 to Int.MaxValue) in.write(i) } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } } go { for(i <- 1 to n) yield out.read } } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } }
  • 6. def nPrimes(n:Int):Future[List[Int]]= { val in = makeChannel[Int]() val out = makeChannel[Int]() go { for(i <- 1 to Int.MaxValue) in.write(i) } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } } go { for(i <- 1 to n) yield out.read } } go { for(i <- 1 to n) yield out.read }
  • 7. def nPrimes(n:Int):Future[List[Int]]= { val in = makeChannel[Int]() val out = makeChannel[Int]() go { for(i <- 1 to Int.MaxValue) in.write(i) } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } } go { for(i <- 1 to n) yield out.read } }
  • 8. Goroutines ❖ go[X](body: X):Future[X] ❖ Wrapper around async + ❖ translation of high-order functions into async form ❖ handling of defer statement
  • 9. Goroutines ❖ translation of hight-order functions into async form ❖ f(g): f: (A=>B)=>C in g: A=>B, ❖ g is invocation-only in f iff ❖ g called in f or in some h inside f : g invocation-only in h ❖ g is ❖ not stored in memory behind f ❖ not returned from f as return value ❖ Collection API high-order methods are invocation-only
  • 10. Translation of invocation-only functions ❖ f: ((A=>B)=>C), g: (A=>B), g invocation-only in f ❖ f’: ((A=>Future[B])=>Future[C]) g’: (A=>Future[B]) ❖ await(g’) == g => await(f’) == f ❖ f’ => await[translate(f)] ❖ g(x) => await(g’(x)) ❖ h(g) => await(h’(g’)) iff g is invocation-only in h ❖ That’s all ❖ (implemented for specific shapes and parts of scala collection API)
  • 11. def nPrimes(n:Int):Future[List[Int]]= { val in = makeChannel[Int]() val out = makeChannel[Int]() go { for(i <- 1 to n*n) in.write(i) } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } } go { for(i <- 1 to n) yield out.read } } go { for(i <- 1 to n) yield out.read }
  • 12. go { (1 to n).map(i => out.read) } async{ await(t[(1 to n).map(i => out.read)]) } async{ await((1 to n).mapAsync(t[i => async(out.read)])) } async{ await((1 to n).mapAsync(i => async(await(out.aread))) } mapAsync(i => out.aread)
  • 13. Channels ❖ Channel[A] <: Input[A] + Output[A] ❖ Unbuffered ❖ Buffered ❖ Dynamically growing buffers [a-la actor mailbox] ❖ One-time channels [Underlaying promise/Future] ❖ Custom CSP
  • 14. Input[A] - internal API trait Input[A] { type read = A def cbread(f: ContRead[A,B]=>Option[ ContRead.In[A] => Future[Continuated[B]]) ….. } case class ContRead[A,B]( function: F, channel: Channel[A], flowTermination: FlowTermination[B] ) // in ConRead companion object sealed trait In[+A] case class Value(a:A) extends In[A] case class Failure(ex: Throwable] extends In[Nothing] case object Skip extends In[Nothing] case object ChannelClosed extends In[Nothing] ContRead[A,B].F Continuated[B] • ContRead • ContWrite • Skip • Done • Never
  • 15. Input[A] - external API trait Input[A] { …… def aread: Future[A] = <implementation…> def read: A = macro <implementation … > …. def map[B](f: A=>B): Input[B] = …. // or, zip, filter, … etc await(aread) + usual operations on streams in functional language
  • 16. Output[A] - API trait Output[A] { type write = A def cbwrite(f: ContWrite[A,B]=>Option[ (A,Future[Continuated[B]])], ft: FlowTermination[B]) ….. def awrite(a:A): Future[A] = …. def write(a:A): A = …. << await(awrite) …. ContWrite[A,B].F case class ContWrite[A,B]( function: F, channel: Channel[A], flowTermination: FlowTermination[B] )
  • 17. Selector ss go { for{ select{ case c1 -> x : … // P case c2 <- y : … // Q } } Go language: go { select.forever { case x : c1.read => … // P case y : c2.write => … // Q } } Scala: Provide set of flow combinators: forever, once, fold select.aforever { case x : c1.read => … // P case y : c2.write => … // Q }
  • 18. select: fold API def fibonacci(c: Output[Long], quit: Input[Boolean]): Future[(Long,Long)] = select.afold((0L,1L)) { case ((x,y),s) => s match { case x: c.write => (y, x+y) case q: quit.read => select.exit((x,y)) } } fold/afold: • special syntax for tuple support • ’s’: selector pseudoobject • s match must be the first statement • select.exit((..)) to return value from flow
  • 19. Transputer ❖ Actor-like object with set of input/output ports, which can be connected by channels ❖ Participate in actor systems supervisors hierarchy ❖ SelectStatement ❖ A+B (parallel execution, common restart) ❖ replicate
  • 20. Transputer: select class Zipper[T] extends SelectTransputer { val inX: InPort[T] val inY: InPort[T] val out: OutPort[(T,T)] loop { case x: inX.read => val y = inY.read out write (x,y) case y: inY.read => val x = inX.read out.write((x,y)) } } inX inY out
  • 21. Transputer: replicate val r = gopherApi.replicate[SMTTransputer](10) ( r.dataInput.distribute( (_.hashCode % 10 ) ). .controlInput.duplicate(). out.share() ) dataInput controlInput share
  • 22. Programming techniques ❖ Dynamic recursive dataflow schemas ❖ configuration in state ❖ Channel-based two-wave generic API ❖ expect channels for reply
  • 23. Dynamic recursive dataflow select.fold(output){ (out, s) => s match { case x:input.read => select.once { case x:out.write => case select.timeout => control.distributeBandwidth match { case Some(newOut) => newOut.write(x) out | newOut case None => control.report("Can't increase bandwidth") out } } case select.timeout => out match { case OrOutput(frs,snd) => snd.close frs case _ => out } } dynamically increase and decrease bandwidth in dependency from load
  • 24. Dynamic recursive dataflow select.fold(output){ (out, s) => s match { case x:input.read => select.once { case x:out.write => case select.timeout => control.distributeBandwidth match { case Some(newOut) => newOut.write(x) out | newOut case None => control.report("Can't increase bandwidth") out } } case select.timeout => out match { case OrOutput(frs,snd) => snd.close frs case _ => out } } dynamically increase and decrease bandwidth in dependency from load case select.timeout => control.distributeBandwidth match { case Some(newOut) => newOut.write(x) out | newOut case None => control.report("Can't increase bandwidth") out
  • 25. Dynamic recursive dataflow select.fold(output){ (out, s) => s match { case x:input.read => select.once { case x:out.write => case select.timeout => control.distributeBandwidth match { case Some(newOut) => newOut.write(x) out | newOut case None => control.report("Can't increase bandwidth") out } } case select.timeout => out match { case OrOutput(frs,snd) => snd.close frs case _ => out } } dynamically increase and decrease bandwidth in dependency from load case select.timeout => out match { case OrOutput(frs,snd) => snd.close frs case _ => out }
  • 26. Channel-based generic API ❖ Endpoint instead function call ❖ f: A=>B ❖ endpoint: Channel[A,Channel[B]] ❖ Recursive ❖ case class M(A,Channel[M]) ❖ f: (A,M) => M (dataflow configured by input)
  • 27. Channel-based generic API trait Broadcast[T] { val listeners: Output[Channel[T]] val messages: Output[T] def send(v:T):Unit = { messages.write(v) } …. • message will received by all listeners
  • 28. Channel-based generic API class BroadcastImpl[T] { val listeners: Channel[Channel[T]] val messages: Channel[T] = makeChannel[Channel[T]] def send(v:T):Unit = { messages.write(v) } …. } // private part case class Message(next:Channel[Message],value:T) select.afold(makeChannel[Message]) { (bus, s) => s match { case v: messages.read => val newBus = makeChannel[Message] current.write(Message(newBus,v)) newBus case ch: listeners.read => select.afold(bus) { (current,s) => s match { case msg:current.read => ch.awrite(msg.value) current.write(msg) msg.next } } current
  • 29. Channel-based generic API val listeners: Channel[Channel[T]] val messages: Channel[T] = makeChannel[] // private part case class Message(next:Channel[Message],value:T) select.afold(makeChannel[Message]) { (bus, s) => s match { case v: message.read => val newBus = makeChannel[Message] current.write(Message(newBus,v)) newBus case ch: listener.read => select.afold(bus) { (current,s) => s match { case msg:current.read => ch.awrite(msg.value) current.write(msg) msg.next } } • state - channel [bus], for which all listeners are subscribed • on new message - send one to bus with pointer to the next bus state • listener on new message in bus - handle, change current and send again • on new listener - propagate
  • 30. Channel-based generic API val listener: Channel[Channel[T]] val message: Channel[T] = makeChannel[] // private part case class Message(next:Channel[Message],value:T) select.afold(makeChannel[Message]) { (bus, s) => s match { case v: message.read => val newBus = makeChannel[Message] current.write(Message(newBus,v)) newBus case ch: listener.read => select.afold(bus) { (current,s) => s match { case msg:current.read => ch.awrite(msg.value) msg.next } } current • state - channel [bus], for which all listeners are subscribed • on new message - send one to bus with pointer to the next bus state • listener on new message in bus - handle, change current and send again • on new listener - propagate s match { case msg:current.read => ch.awrite(msg.value) current.write(msg) msg.next }
  • 31. Channel-based generic API val listener: Channel[Channel[T]] val message: Channel[T] = makeChannel[] // private part case class Message(next:Channel[Message],value:T) select.afold(makeChannel[Message]) { (bus, s) => s match { case v: message.read => val newBus = makeChannel[Message] current.write(Message(newBus,v)) newBus case ch: listener.read => select.afold(bus) { (current,s) => s match { case msg:current.read => ch.awrite(msg.value) current.write(msg) msg.next } } current • state - channel [bus], for which all listeners are subscribed • on new message - send one to bus with pointer to the next bus state • listener on new message in bus - handle, change current and send again • val newBus = makeChannel[Message] current.write(Message(newBus,v)) newBus
  • 32. Scala concurrency libraries Flexibility Scalability Level Actors • Actors • low level, • great flexibility and scalability • Akka-Streams • low flexibility • hight-level, scalable • SCO • low scalability • hight-level, flexible • Reactive Isolated • hight-level, scalable, • allows delegation • Gopher • can emulate each style Streams SCO Subscript Language
  • 33. Gopher vs Reactive Isolates • Isolate • Events • Channel • Transputer/fold • Input • Output Gopher Isolates One writerMany writers Channel must have owner Local Distributed Loosely coupled (growing buffer)CSP + growing buffer
  • 34. Scala-gopher: early experience reports ❖ Not 1.0 yet ❖ Helper functionality in industrial software projects. (utilities, small team) ❖ Generally: positive ❖ transformation of invocation-only hight-order methods into async form ❖ recursive dynamic data flows ❖ Error handling needs some boilerplate
  • 35. Error handling: language level issue val future = go { ……… throw some exception } go { ………. throw some exception } Go { ………… throw some exception } Core scala library: Future.apply (same issue) Error is ignored Developers miss-up Go/go
  • 36. Errors in ignored value: possible language changes. ❖ Possible solutions: ❖ Optional implicit conversion for ignored value ❖ Special optional method name for calling with ignored value ❖ Special return type trait Ignored[F] object Future { implicit def toIgnored(f:Future):Ignored[Future] = …. def go[X](f: X): Future[X] def go_ignored[X](f:X): Unit def go(f:X): Ignored[Future[X]] =
  • 37. Scala-Gopher: Future directions ❖ More experience reports (try to use) ❖ Extended set of notifications ❖ channel.close, overflow ❖ Distributed case ❖ new channel types with explicit distributed semantics
  • 38. Scala-Gopher: Conclusion ❖ Native integration of CSP into Scala is possible ❖ have a place in a Scala concurrency model zoo ❖ Bring well-established techniques to Scala world ❖ (recursive dataflow schemas; channel API) ❖ Translation of invocation-only high-order functions into async form can be generally recommended. ❖ (with TASTY transformation inside libraries can be done automatically)
  • 39. Thanks for attention ❖ Questions ? ❖ https://github.com/rssh/scala-gopher ❖ ruslan shevchenko: [email protected]