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
Java/Scala Lab: Руслан Шевченко - Implementation of CSP (Communication Sequen...
GeeksLab Odessa
 
PDF
Csp scala wixmeetup2016
Ruslan Shevchenko
 
PDF
Ruslan.shevchenko: most functional-day-kiev 2014
Ruslan Shevchenko
 
PDF
N flavors of streaming
Ruslan Shevchenko
 
PPT
Implementation of 'go-like' language constructions in scala [english version]
Ruslan Shevchenko
 
PDF
pure-functional-programming.pdf
PuneetChaturvedi23
 
PDF
Coding in Style
scalaconfjp
 
PDF
Enterprise Algebras, Scala World 2016
Timothy Perrett
 
PDF
scalaliftoff2009.pdf
Hiroshi Ono
 
PDF
scalaliftoff2009.pdf
Hiroshi Ono
 
PDF
scalaliftoff2009.pdf
Hiroshi Ono
 
PDF
scalaliftoff2009.pdf
Hiroshi Ono
 
PDF
Scala.io
Steve Gury
 
PDF
Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Ruslan Shevchenko
 
PPTX
ZIO: Powerful and Principled Functional Programming in Scala
Wiem Zine Elabidine
 
PDF
Async Microservices with Twitter's Finagle
Vladimir Kostyukov
 
PPTX
A Brief Intro to Scala
Tim Underwood
 
PPT
Scala presentation by Aleksandar Prokopec
Loïc Descotte
 
PDF
From Java to Scala - advantages and possible risks
SeniorDevOnly
 
ODP
Scala ntnu
Alf Kristian Støyle
 
Java/Scala Lab: Руслан Шевченко - Implementation of CSP (Communication Sequen...
GeeksLab Odessa
 
Csp scala wixmeetup2016
Ruslan Shevchenko
 
Ruslan.shevchenko: most functional-day-kiev 2014
Ruslan Shevchenko
 
N flavors of streaming
Ruslan Shevchenko
 
Implementation of 'go-like' language constructions in scala [english version]
Ruslan Shevchenko
 
pure-functional-programming.pdf
PuneetChaturvedi23
 
Coding in Style
scalaconfjp
 
Enterprise Algebras, Scala World 2016
Timothy Perrett
 
scalaliftoff2009.pdf
Hiroshi Ono
 
scalaliftoff2009.pdf
Hiroshi Ono
 
scalaliftoff2009.pdf
Hiroshi Ono
 
scalaliftoff2009.pdf
Hiroshi Ono
 
Scala.io
Steve Gury
 
Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Ruslan Shevchenko
 
ZIO: Powerful and Principled Functional Programming in Scala
Wiem Zine Elabidine
 
Async Microservices with Twitter's Finagle
Vladimir Kostyukov
 
A Brief Intro to Scala
Tim Underwood
 
Scala presentation by Aleksandar Prokopec
Loïc Descotte
 
From Java to Scala - advantages and possible risks
SeniorDevOnly
 
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
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
 
ODP
Annotated imports
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
 
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
 
Annotated imports
Ruslan Shevchenko
 

Recently uploaded (20)

PDF
vMix Pro 28.0.0.42 Download vMix Registration key Bundle
kulindacore
 
PPTX
Migrating Millions of Users with Debezium, Apache Kafka, and an Acyclic Synch...
MD Sayem Ahmed
 
PPTX
Engineering the Java Web Application (MVC)
abhishekoza1981
 
PPTX
Tally software_Introduction_Presentation
AditiBansal54083
 
PDF
Digger Solo: Semantic search and maps for your local files
seanpedersen96
 
DOCX
Import Data Form Excel to Tally Services
Tally xperts
 
PDF
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pdf
Varsha Nayak
 
PDF
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
PDF
Beyond Binaries: Understanding Diversity and Allyship in a Global Workplace -...
Imma Valls Bernaus
 
PDF
Thread In Android-Mastering Concurrency for Responsive Apps.pdf
Nabin Dhakal
 
PPTX
Tally_Basic_Operations_Presentation.pptx
AditiBansal54083
 
PPTX
A Complete Guide to Salesforce SMS Integrations Build Scalable Messaging With...
360 SMS APP
 
PPTX
The Role of a PHP Development Company in Modern Web Development
SEO Company for School in Delhi NCR
 
PPTX
How Apagen Empowered an EPC Company with Engineering ERP Software
SatishKumar2651
 
PPTX
MailsDaddy Outlook OST to PST converter.pptx
abhishekdutt366
 
PPTX
Human Resources Information System (HRIS)
Amity University, Patna
 
PPTX
Platform for Enterprise Solution - Java EE5
abhishekoza1981
 
PDF
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
PPTX
Fundamentals_of_Microservices_Architecture.pptx
MuhammadUzair504018
 
PPTX
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 
vMix Pro 28.0.0.42 Download vMix Registration key Bundle
kulindacore
 
Migrating Millions of Users with Debezium, Apache Kafka, and an Acyclic Synch...
MD Sayem Ahmed
 
Engineering the Java Web Application (MVC)
abhishekoza1981
 
Tally software_Introduction_Presentation
AditiBansal54083
 
Digger Solo: Semantic search and maps for your local files
seanpedersen96
 
Import Data Form Excel to Tally Services
Tally xperts
 
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pdf
Varsha Nayak
 
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
Beyond Binaries: Understanding Diversity and Allyship in a Global Workplace -...
Imma Valls Bernaus
 
Thread In Android-Mastering Concurrency for Responsive Apps.pdf
Nabin Dhakal
 
Tally_Basic_Operations_Presentation.pptx
AditiBansal54083
 
A Complete Guide to Salesforce SMS Integrations Build Scalable Messaging With...
360 SMS APP
 
The Role of a PHP Development Company in Modern Web Development
SEO Company for School in Delhi NCR
 
How Apagen Empowered an EPC Company with Engineering ERP Software
SatishKumar2651
 
MailsDaddy Outlook OST to PST converter.pptx
abhishekdutt366
 
Human Resources Information System (HRIS)
Amity University, Patna
 
Platform for Enterprise Solution - Java EE5
abhishekoza1981
 
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
Fundamentals_of_Microservices_Architecture.pptx
MuhammadUzair504018
 
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 

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]