SlideShare a Scribd company logo
Thefutureinmobile
Bartosz Polaczyk
Actor based approach in
practice for Swift
developers
Bartosz Polaczyk
Senior iOS Developer 
Grand Parade part of William Hill
norapsi
polac24
bartosz@polaczyk.com@
Theory
What actor is
Benefits
iOS Actors
Use cases
Solution
Benefits
Future
Swift language
support
Implementation
Mini framework
Actor sample
Unit tests
Challenges
Proposed in 1973 by Carl Hewitt
Used in distributed, high reliability systems,
telecommunication industry
Successful in Scala (framework Akka)
and C#/F# (Akka.NET)
Intro
Actor
Actor
principles
Has unique address
Receives messages from different sources
Processes one message a time
Reacts by:
Reading/writing local state (memory)
Creating new actor(s)
Sending message(s) to other actors
Actor 

limits
Unidirectional - fire and forget
No global state manipulation
No concurrency within Actor
Messages carry only information
Order of messages is indeterministic
Mail example
Actor
”Bartosz Polaczyk, Street 1, Krakow”
Mail example
Actor
”Bartosz Polaczyk, Street 1, Krakow”
Mail example
Actor
”Bartosz Polaczyk, Street 1, Krakow”
Mail example
Actor
”Bartosz Polaczyk, Street 1, Krakow”
Mail example
Actor
”Bartosz Polaczyk, Street 1, Krakow”
Mail example
Actor
”Bartosz Polaczyk, Street 1, Krakow”
”Bartosz Polaczyk
secretary”
Mail example
Actor
”Bartosz Polaczyk, Street 1, Krakow”
”Bartosz Polaczyk
secretary”
Mail example
Actor
”Bartosz Polaczyk, Street 1, Krakow”
”Bartosz Polaczyk
secretary”
Mail example
Actor
”Bartosz Polaczyk, Street 1, Krakow”
”Bartosz Polaczyk
secretary”
Mail example
Actor
”Bartosz Polaczyk, Street 1, Krakow”
”Bartosz Polaczyk
secretary”
Scaling by distribution
Modularization by design
Efficient concurrency -
no locks
Fault tolerance
Benefits
Actors in mobile world
Asynchronous
problems
[Actor] provides an "island of serialization in a
sea of concurrency".
Chris Lattner, Concurrency in Swift: One approach
class Counter{
private var value = 0
public func add(){
value += 1
}
...
}
class Counter{
private var value = 0
private let queue = DispatchQueue()
public func add(){
queue.async{
value += 1
}
}
...
}
class Counter{
private var value = 0
private let queue = DispatchQueue()
public func add(){
queue.async{
value += 1
}
}
public func addTwice() {
queue.async{
value += 2
}
}
public func add(from:TimesProvider){
queue.async{
value += from.value
}
}
Traditional thread-safety API
Developer’s responsibility for
exclusive critical sections calls
#1 Manual queuing
class Counter{
private var value = 0
private let queue = DispatchQueue()
public func add(){
queue.async{
value += 1
}
}
public func addTwice() {
queue.async{
value += 2
}
}
public func add(from:TimesProvider){
queue.async{
value += from.value
}
}
}
External dependencies (e.g.
arguments) may be thread-unsafe
#2 Dependencies thread-safety
Pitfalls
Traditional way // nonatomic
Actor
A
B
Actor
A
B
Actor
A
B
Actor
A
#1 Manual queuing
B
Calling a function
Swift
Sending a message
Actor
class Counter{
func add(_ value:Int){…}
func subtract(_ value:Int){…}
}
counter.add(1)
class CounterActor {
func send(_ message:CounterMessage){…}
}
enum CounterMessage {
case add(Int)
case subtract(Int)
}
counterActor.send(.add(1))
ActorSwift
• Message may not contain any shared state
• Serialization/deserialization possible
Full value semantics
Actor message
“Codable”
“Codable”
#2 Dependencies thread-safety
Actor
Actors Swift implementation
Actor
A
Driver
Message
[Command]
Driver
Message
[Command]
class ActorDriver<Actor:Actorable>{
private let queue:DispatchQueue
private var actor:Actor
private let externals:Actor.Command.Externals
fileprivate init(actor:Actor, externals: Actor.Command.Externals, queue:
DispatchQueue){
self.actor = actor
self.externals = externals
self.queue = queue
}
public func send(_ message:Actor.Message){
queue.async{
self.actor.onReceive(message).forEach{$0.interpret(externals:
self.externals)}
}
}
convenience init(actor:Actor, externals: Actor.Command.Externals){
self.init(actor: actor, externals: externals, queue:
DispatchQueue(label:String(describing:ActorDriver<Actor>.self)))
}
}
• Single function (send)
• Statically typed message
Input
ActorDriver
01
protocol Actorable {
associatedtype Message
associatedtype Command:Commandable where Command.Message ==
Message
mutating func onReceive(_ : Message) -> [Command]
}
protocol Commandable{
associatedtype Message:Messagable
associatedtype Externals
func interpret(externals: Externals, feedback:
@escaping AnyActorDriver<Message> )
}
03
protocol Messagable {}

02
typealias AnyActorDriver<Message:Messagable> =
(Message) -> ()04
Input + Logic + Output
Actor core logic
typealias AnyActorDriver<Message:Messagable> = (Message) -> ()
Actor Driver type erasure
class ActorDriver<Actor:Actorable>{
private let queue:DispatchQueue
private var actor:Actor
private let externals:Actor.Command.Externals
fileprivate init(actor:Actor, externals: Actor.Command.Externals, queue: DispatchQueue){
self.actor = actor
self.externals = externals
self.queue = queue
}
func send(_ message:Actor.Message){
queue.async{
self.actor.onReceive(message).forEach{$0.interpret(externals: self.externals)}
}
}
convenience init(actor:Actor, externals: Actor.Command.Externals){
self.init(actor: actor, externals: externals, queue:
DispatchQueue(label:String(describing:ActorDriver<Actor>.self)))
}
}
protocol Messagable {}
protocol Actorable {
associatedtype Message
associatedtype Command:Commandable where Command.Message == Message
mutating func onReceive(_ : Message) -> [Command]
}
protocol Commandable{
associatedtype Message:Messagable
associatedtype Externals
func interpret(externals: Externals, feedback: @escaping AnyActorDriver<Message> )
}
Actor framework
snippet
Actor sample
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
.initial
.reloadIntent
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
.initial
.reloadIntent
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
.reloadIntent
.loading
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
.loading
.loadElements
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
.loading
Network
Actor
.loadElements
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
.loading
Network
Actor
.loadElements
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
.loading
Network
Actor
.resultsReady
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
.loading
Network
Actor
.resultsReady
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
.loading
Network
Actor
.resultsReady
.reloadIntent
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
.loading
Network
Actor
.resultsReady
.reloadIntent
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
.loading
Network
Actor
.resultsReady
.reloadIntent
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
Network
Actor
.resultsReady
.reloadIntent
.presenting
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
Network
Actor
.reloadIntent
.presentElements
.presenting
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
Network
Actor
.reloadIntent
.presenting
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
`
UI
Network
Actor
.reloadIntent
.presenting
enum Message{
case reloadIntent
case resultsReady(elements:[Element])
}
enum Command {
case loadElements
case presentElements(elements:[Element])
}
enum ListScreenActor: Actorable {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.reloadIntent, .presenting(let elements)):
self = .refreshing(elements: elements)
return [.loadElements]
case (.resultsReady(let elements), .loading),
(.resultsReady(let elements), .refreshing):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
default:
return []
}
}
}
Output
Logic
ListScreenActor
Input
UI
Network
Actor
.reloadIntent
.presenting
Actors unit testing
Actor A
Driver
Actor B
Non actor C
Actor
Actors unit testing
From async to sync state machine
Actor
enum ListScreenActor {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.resultsReady(let elements), .presenting):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
...
}
}
}
Actor tests
Initialize an actor
Send message/
messages
Observe commands
func testFirstReload_startsLoading(){
var actor = ListScreenActor.initial
let commands = actor.onReceive(.reloadIntent)
XCTAssertEqual(commands, [.loadElements])
}
enum ListScreenActor {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.resultsReady(let elements), .presenting):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
...
}
}
}
Actor tests
Initialize an actor
Send message/
messages
Observe commands
func testLoadedResults_presentElements(){
var actor = ListScreenActor.initial
_ = actor.onReceive(.reloadIntent)
let commands = actor.onReceive(.resultsReady(elements: ["1", "2"]))
XCTAssertEqual(commands, [.presentElements(elements: [“1”,”2”])])
}
func testMultiplereloads_loadOnce(){
var actor = ListScreenActor.initial
let commands1 = actor.onReceive(.reloadIntent)
let commands2 = actor.onReceive(.reloadIntent)
let commands = actor.onReceive(.resultsReady(elements: ["1", “2"]))
let commands3 = actor.onReceive(.reloadIntent)
XCTAssertEqual(commands1.onReceive(), ...)
XCTAssertEqual(commands2.onReceive(), ...)
XCTAssertEqual(commands3.onReceive(), ...)
XCTAssertEqual(commands.onReceive(), ...)
}
enum ListScreenActor {
case initial
case loading
case presenting(elements:[Element])
case refreshing(elements:[Element])
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self) {
case (.reloadIntent,.initial):
self = .loading
return [.loadElements]
case (.resultsReady(let elements), .presenting):
self = .presenting(elements: elements)
return [.presentElements(elements: elements)]
...
}
}
}
Actor tests
Initialize an actor
Send message/
messages
Observe commands
Swift actors challenges
enum Message:Messagable{
case retrievePath(path:String, id: UUID)
...
}
enum Message:Messagable{
case retrievePath(path:String, completion:(Int)->())
...
}
#1 Completion handlers
• Limitation:
• No reference types in a message
• Solution:
• unique identifier
• Limitation:
• Actor reacts only for messages
• Solution:
• Separate object for sending
message with timer events
enum ScreenActor{
...
mutating func onReceive(_ message: Message) -> [Command] {
switch (message, self){
case (.reloadIntent,.initial):
self = .loading
Timer.scheduledTimer(withTimeInterval: 60 , repeats: false) {_ in
self = .initial
}
return [.loadElements]
...
#2 Timers
enum Message:Messagable{
…
case timerEvent
…
}
struct Actor:Actorable {
mutating func onReceive(_ message: Message) -> [Command] {
switch message{
...
case .contentError(_):
...
}
}
throw
#3 Error handling
• Limitation:
• No automatic thrown Errors
propagation
• Solution:
• Manual propagation
Swift actors future
Chris Lattner Concurrency in Swift: One approach
https://gist.github.com/lattner/31ed37682ef1576b16bca1432ea9f782
Concurrency in Swift:
One approach
actor keyword
reference type
actor Counter{
private var value = 0
private let otherActor:OtherActor
actor func add(){
// queue.async{
value += 1
//}
}
actor func addTwice() {
// queue.async{
value += 2
//}
}
public func add(from:TimesProvider){
value += 2
}
}
Compiler’s addition
// Swift
actor MainActor{
actor private init() {}
}
// App
Extension MainActor{
// App logic
}
Concurrency in Swift:
One approach
support for MainActor
ValueSemantical
protocol
protocol ValueSemantical{
...
}
struct State: ValueSemantical{
let some: SomeType
}
Summary
Actor systems
Swift implementation
Address concurrency issues
Potential Swift actor support
Actors
Recap
Thank you
https://github.com/polac24/ActorRecordings

More Related Content

What's hot

Core Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug HuntCore Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug Hunt
CodeOps Technologies LLP
 
Oop2010 Scala Presentation Stal
Oop2010 Scala Presentation StalOop2010 Scala Presentation Stal
Oop2010 Scala Presentation Stal
Michael Stal
 
Functional Thinking - Programming with Lambdas in Java 8
Functional Thinking - Programming with Lambdas in Java 8Functional Thinking - Programming with Lambdas in Java 8
Functional Thinking - Programming with Lambdas in Java 8
Ganesh Samarthyam
 
Sailing with Java 8 Streams
Sailing with Java 8 StreamsSailing with Java 8 Streams
Sailing with Java 8 Streams
Ganesh Samarthyam
 
Java 8 Feature Preview
Java 8 Feature PreviewJava 8 Feature Preview
Java 8 Feature Preview
Jim Bethancourt
 
Apache Velocity
Apache Velocity Apache Velocity
Apache Velocity
yesprakash
 
Functions1
Functions1Functions1
Functions1
DrUjwala1
 
Qcon2011 functions rockpresentation_scala
Qcon2011 functions rockpresentation_scalaQcon2011 functions rockpresentation_scala
Qcon2011 functions rockpresentation_scala
Michael Stal
 
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript...Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript...
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
Tim Chaplin
 
Java 8 streams
Java 8 streamsJava 8 streams
Java 8 streams
Manav Prasad
 
Akka Futures and Akka Remoting
Akka Futures  and Akka RemotingAkka Futures  and Akka Remoting
Akka Futures and Akka Remoting
Knoldus Inc.
 
Java8
Java8Java8
Wien15 java8
Wien15 java8Wien15 java8
Wien15 java8
Jaanus Pöial
 
Java rmi example program with code
Java rmi example program with codeJava rmi example program with code
Java rmi example program with code
kamal kotecha
 
Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)
Trisha Gee
 
Getting Started With Kotlin
Getting Started With KotlinGetting Started With Kotlin
Getting Started With Kotlin
Gaurav sharma
 
Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...
Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...
Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...
Knoldus Inc.
 
Alteryx SDK
Alteryx SDKAlteryx SDK
Alteryx SDK
James Dunkerley
 
Back to the futures, actors and pipes: using Akka for large-scale data migration
Back to the futures, actors and pipes: using Akka for large-scale data migrationBack to the futures, actors and pipes: using Akka for large-scale data migration
Back to the futures, actors and pipes: using Akka for large-scale data migration
Manuel Bernhardt
 
Recipes to build Code Generators for Non-Xtext Models with Xtend
Recipes to build Code Generators for Non-Xtext Models with XtendRecipes to build Code Generators for Non-Xtext Models with Xtend
Recipes to build Code Generators for Non-Xtext Models with Xtend
Karsten Thoms
 

What's hot (20)

Core Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug HuntCore Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug Hunt
 
Oop2010 Scala Presentation Stal
Oop2010 Scala Presentation StalOop2010 Scala Presentation Stal
Oop2010 Scala Presentation Stal
 
Functional Thinking - Programming with Lambdas in Java 8
Functional Thinking - Programming with Lambdas in Java 8Functional Thinking - Programming with Lambdas in Java 8
Functional Thinking - Programming with Lambdas in Java 8
 
Sailing with Java 8 Streams
Sailing with Java 8 StreamsSailing with Java 8 Streams
Sailing with Java 8 Streams
 
Java 8 Feature Preview
Java 8 Feature PreviewJava 8 Feature Preview
Java 8 Feature Preview
 
Apache Velocity
Apache Velocity Apache Velocity
Apache Velocity
 
Functions1
Functions1Functions1
Functions1
 
Qcon2011 functions rockpresentation_scala
Qcon2011 functions rockpresentation_scalaQcon2011 functions rockpresentation_scala
Qcon2011 functions rockpresentation_scala
 
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript...Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript...
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
 
Java 8 streams
Java 8 streamsJava 8 streams
Java 8 streams
 
Akka Futures and Akka Remoting
Akka Futures  and Akka RemotingAkka Futures  and Akka Remoting
Akka Futures and Akka Remoting
 
Java8
Java8Java8
Java8
 
Wien15 java8
Wien15 java8Wien15 java8
Wien15 java8
 
Java rmi example program with code
Java rmi example program with codeJava rmi example program with code
Java rmi example program with code
 
Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)
 
Getting Started With Kotlin
Getting Started With KotlinGetting Started With Kotlin
Getting Started With Kotlin
 
Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...
Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...
Play framework training by Neelkanth Sachdeva @ Scala traits event , New Delh...
 
Alteryx SDK
Alteryx SDKAlteryx SDK
Alteryx SDK
 
Back to the futures, actors and pipes: using Akka for large-scale data migration
Back to the futures, actors and pipes: using Akka for large-scale data migrationBack to the futures, actors and pipes: using Akka for large-scale data migration
Back to the futures, actors and pipes: using Akka for large-scale data migration
 
Recipes to build Code Generators for Non-Xtext Models with Xtend
Recipes to build Code Generators for Non-Xtext Models with XtendRecipes to build Code Generators for Non-Xtext Models with Xtend
Recipes to build Code Generators for Non-Xtext Models with Xtend
 

Similar to Actor based approach in practice for Swift developers

Scalaz 8 vs Akka Actors
Scalaz 8 vs Akka ActorsScalaz 8 vs Akka Actors
Scalaz 8 vs Akka Actors
John De Goes
 
Improving Correctness with Types Kats Conf
Improving Correctness with Types Kats ConfImproving Correctness with Types Kats Conf
Improving Correctness with Types Kats Conf
Iain Hull
 
Akka
AkkaAkka
Concurrency on the JVM
Concurrency on the JVMConcurrency on the JVM
Concurrency on the JVM
Vaclav Pech
 
Akka introtalk HyScala DEC 2016
Akka introtalk HyScala DEC 2016Akka introtalk HyScala DEC 2016
Akka introtalk HyScala DEC 2016
PrasannaKumar Sathyanarayanan
 
Software Transactioneel Geheugen
Software Transactioneel GeheugenSoftware Transactioneel Geheugen
Software Transactioneel Geheugen
Devnology
 
Improving Correctness with Types
Improving Correctness with TypesImproving Correctness with Types
Improving Correctness with Types
Iain Hull
 
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
STX Next
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projects
Bartosz Kosarzycki
 
Scaling Web Apps with Akka
Scaling Web Apps with AkkaScaling Web Apps with Akka
Scaling Web Apps with Akka
Maciej Matyjas
 
Akka lsug skills matter
Akka lsug skills matterAkka lsug skills matter
Akka lsug skills matter
Skills Matter
 
Akka and futures
Akka and futuresAkka and futures
Akka and futures
Knoldus Inc.
 
Module design pattern i.e. express js
Module design pattern i.e. express jsModule design pattern i.e. express js
Module design pattern i.e. express js
Ahmed Assaf
 
Introduction to clojure
Introduction to clojureIntroduction to clojure
Introduction to clojure
Abbas Raza
 
Prompt engineering for iOS developers (How LLMs and GenAI work)
Prompt engineering for iOS developers (How LLMs and GenAI work)Prompt engineering for iOS developers (How LLMs and GenAI work)
Prompt engineering for iOS developers (How LLMs and GenAI work)
Andrey Volobuev
 
Let'swift "Concurrency in swift"
Let'swift "Concurrency in swift"Let'swift "Concurrency in swift"
Let'swift "Concurrency in swift"
Hyuk Hur
 
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STMConcurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Mario Fusco
 
A Survey of Concurrency Constructs
A Survey of Concurrency ConstructsA Survey of Concurrency Constructs
A Survey of Concurrency Constructs
Ted Leung
 
Message-based communication patterns in distributed Akka applications
Message-based communication patterns in distributed Akka applicationsMessage-based communication patterns in distributed Akka applications
Message-based communication patterns in distributed Akka applications
Andrii Lashchenko
 
Pick up the low-hanging concurrency fruit
Pick up the low-hanging concurrency fruitPick up the low-hanging concurrency fruit
Pick up the low-hanging concurrency fruit
Vaclav Pech
 

Similar to Actor based approach in practice for Swift developers (20)

Scalaz 8 vs Akka Actors
Scalaz 8 vs Akka ActorsScalaz 8 vs Akka Actors
Scalaz 8 vs Akka Actors
 
Improving Correctness with Types Kats Conf
Improving Correctness with Types Kats ConfImproving Correctness with Types Kats Conf
Improving Correctness with Types Kats Conf
 
Akka
AkkaAkka
Akka
 
Concurrency on the JVM
Concurrency on the JVMConcurrency on the JVM
Concurrency on the JVM
 
Akka introtalk HyScala DEC 2016
Akka introtalk HyScala DEC 2016Akka introtalk HyScala DEC 2016
Akka introtalk HyScala DEC 2016
 
Software Transactioneel Geheugen
Software Transactioneel GeheugenSoftware Transactioneel Geheugen
Software Transactioneel Geheugen
 
Improving Correctness with Types
Improving Correctness with TypesImproving Correctness with Types
Improving Correctness with Types
 
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projects
 
Scaling Web Apps with Akka
Scaling Web Apps with AkkaScaling Web Apps with Akka
Scaling Web Apps with Akka
 
Akka lsug skills matter
Akka lsug skills matterAkka lsug skills matter
Akka lsug skills matter
 
Akka and futures
Akka and futuresAkka and futures
Akka and futures
 
Module design pattern i.e. express js
Module design pattern i.e. express jsModule design pattern i.e. express js
Module design pattern i.e. express js
 
Introduction to clojure
Introduction to clojureIntroduction to clojure
Introduction to clojure
 
Prompt engineering for iOS developers (How LLMs and GenAI work)
Prompt engineering for iOS developers (How LLMs and GenAI work)Prompt engineering for iOS developers (How LLMs and GenAI work)
Prompt engineering for iOS developers (How LLMs and GenAI work)
 
Let'swift "Concurrency in swift"
Let'swift "Concurrency in swift"Let'swift "Concurrency in swift"
Let'swift "Concurrency in swift"
 
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STMConcurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
 
A Survey of Concurrency Constructs
A Survey of Concurrency ConstructsA Survey of Concurrency Constructs
A Survey of Concurrency Constructs
 
Message-based communication patterns in distributed Akka applications
Message-based communication patterns in distributed Akka applicationsMessage-based communication patterns in distributed Akka applications
Message-based communication patterns in distributed Akka applications
 
Pick up the low-hanging concurrency fruit
Pick up the low-hanging concurrency fruitPick up the low-hanging concurrency fruit
Pick up the low-hanging concurrency fruit
 

Recently uploaded

System Design Case Study: Building a Scalable E-Commerce Platform - Hiike
System Design Case Study: Building a Scalable E-Commerce Platform - HiikeSystem Design Case Study: Building a Scalable E-Commerce Platform - Hiike
System Design Case Study: Building a Scalable E-Commerce Platform - Hiike
Hiike
 
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success StoryDriving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Safe Software
 
Presentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of GermanyPresentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of Germany
innovationoecd
 
Introduction of Cybersecurity with OSS at Code Europe 2024
Introduction of Cybersecurity with OSS  at Code Europe 2024Introduction of Cybersecurity with OSS  at Code Europe 2024
Introduction of Cybersecurity with OSS at Code Europe 2024
Hiroshi SHIBATA
 
SAP S/4 HANA sourcing and procurement to Public cloud
SAP S/4 HANA sourcing and procurement to Public cloudSAP S/4 HANA sourcing and procurement to Public cloud
SAP S/4 HANA sourcing and procurement to Public cloud
maazsz111
 
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying AheadDigital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Wask
 
Taking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdfTaking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdf
ssuserfac0301
 
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdfMonitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Tosin Akinosho
 
Trusted Execution Environment for Decentralized Process Mining
Trusted Execution Environment for Decentralized Process MiningTrusted Execution Environment for Decentralized Process Mining
Trusted Execution Environment for Decentralized Process Mining
LucaBarbaro3
 
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAUHCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
panagenda
 
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with SlackLet's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
shyamraj55
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
Zilliz
 
GraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracyGraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracy
Tomaz Bratanic
 
June Patch Tuesday
June Patch TuesdayJune Patch Tuesday
June Patch Tuesday
Ivanti
 
Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |
AstuteBusiness
 
A Comprehensive Guide to DeFi Development Services in 2024
A Comprehensive Guide to DeFi Development Services in 2024A Comprehensive Guide to DeFi Development Services in 2024
A Comprehensive Guide to DeFi Development Services in 2024
Intelisync
 
Skybuffer AI: Advanced Conversational and Generative AI Solution on SAP Busin...
Skybuffer AI: Advanced Conversational and Generative AI Solution on SAP Busin...Skybuffer AI: Advanced Conversational and Generative AI Solution on SAP Busin...
Skybuffer AI: Advanced Conversational and Generative AI Solution on SAP Busin...
Tatiana Kojar
 
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Jeffrey Haguewood
 
TrustArc Webinar - 2024 Global Privacy Survey
TrustArc Webinar - 2024 Global Privacy SurveyTrustArc Webinar - 2024 Global Privacy Survey
TrustArc Webinar - 2024 Global Privacy Survey
TrustArc
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
Tatiana Kojar
 

Recently uploaded (20)

System Design Case Study: Building a Scalable E-Commerce Platform - Hiike
System Design Case Study: Building a Scalable E-Commerce Platform - HiikeSystem Design Case Study: Building a Scalable E-Commerce Platform - Hiike
System Design Case Study: Building a Scalable E-Commerce Platform - Hiike
 
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success StoryDriving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success Story
 
Presentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of GermanyPresentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of Germany
 
Introduction of Cybersecurity with OSS at Code Europe 2024
Introduction of Cybersecurity with OSS  at Code Europe 2024Introduction of Cybersecurity with OSS  at Code Europe 2024
Introduction of Cybersecurity with OSS at Code Europe 2024
 
SAP S/4 HANA sourcing and procurement to Public cloud
SAP S/4 HANA sourcing and procurement to Public cloudSAP S/4 HANA sourcing and procurement to Public cloud
SAP S/4 HANA sourcing and procurement to Public cloud
 
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying AheadDigital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying Ahead
 
Taking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdfTaking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdf
 
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdfMonitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdf
 
Trusted Execution Environment for Decentralized Process Mining
Trusted Execution Environment for Decentralized Process MiningTrusted Execution Environment for Decentralized Process Mining
Trusted Execution Environment for Decentralized Process Mining
 
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAUHCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
 
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with SlackLet's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
 
GraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracyGraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracy
 
June Patch Tuesday
June Patch TuesdayJune Patch Tuesday
June Patch Tuesday
 
Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |
 
A Comprehensive Guide to DeFi Development Services in 2024
A Comprehensive Guide to DeFi Development Services in 2024A Comprehensive Guide to DeFi Development Services in 2024
A Comprehensive Guide to DeFi Development Services in 2024
 
Skybuffer AI: Advanced Conversational and Generative AI Solution on SAP Busin...
Skybuffer AI: Advanced Conversational and Generative AI Solution on SAP Busin...Skybuffer AI: Advanced Conversational and Generative AI Solution on SAP Busin...
Skybuffer AI: Advanced Conversational and Generative AI Solution on SAP Busin...
 
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
 
TrustArc Webinar - 2024 Global Privacy Survey
TrustArc Webinar - 2024 Global Privacy SurveyTrustArc Webinar - 2024 Global Privacy Survey
TrustArc Webinar - 2024 Global Privacy Survey
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
 

Actor based approach in practice for Swift developers

  • 1. Thefutureinmobile Bartosz Polaczyk Actor based approach in practice for Swift developers
  • 2. Bartosz Polaczyk Senior iOS Developer  Grand Parade part of William Hill norapsi polac24 bartosz@polaczyk.com@
  • 3. Theory What actor is Benefits iOS Actors Use cases Solution Benefits Future Swift language support Implementation Mini framework Actor sample Unit tests Challenges
  • 4. Proposed in 1973 by Carl Hewitt Used in distributed, high reliability systems, telecommunication industry Successful in Scala (framework Akka) and C#/F# (Akka.NET) Intro Actor
  • 5. Actor principles Has unique address Receives messages from different sources Processes one message a time Reacts by: Reading/writing local state (memory) Creating new actor(s) Sending message(s) to other actors
  • 6. Actor 
 limits Unidirectional - fire and forget No global state manipulation No concurrency within Actor Messages carry only information Order of messages is indeterministic
  • 12. Mail example Actor ”Bartosz Polaczyk, Street 1, Krakow” ”Bartosz Polaczyk secretary”
  • 13. Mail example Actor ”Bartosz Polaczyk, Street 1, Krakow” ”Bartosz Polaczyk secretary”
  • 14. Mail example Actor ”Bartosz Polaczyk, Street 1, Krakow” ”Bartosz Polaczyk secretary”
  • 15. Mail example Actor ”Bartosz Polaczyk, Street 1, Krakow” ”Bartosz Polaczyk secretary”
  • 16. Mail example Actor ”Bartosz Polaczyk, Street 1, Krakow” ”Bartosz Polaczyk secretary”
  • 17. Scaling by distribution Modularization by design Efficient concurrency - no locks Fault tolerance Benefits
  • 19. Asynchronous problems [Actor] provides an "island of serialization in a sea of concurrency". Chris Lattner, Concurrency in Swift: One approach
  • 20. class Counter{ private var value = 0 public func add(){ value += 1 } ... } class Counter{ private var value = 0 private let queue = DispatchQueue() public func add(){ queue.async{ value += 1 } } ... } class Counter{ private var value = 0 private let queue = DispatchQueue() public func add(){ queue.async{ value += 1 } } public func addTwice() { queue.async{ value += 2 } } public func add(from:TimesProvider){ queue.async{ value += from.value } } Traditional thread-safety API
  • 21. Developer’s responsibility for exclusive critical sections calls #1 Manual queuing class Counter{ private var value = 0 private let queue = DispatchQueue() public func add(){ queue.async{ value += 1 } } public func addTwice() { queue.async{ value += 2 } } public func add(from:TimesProvider){ queue.async{ value += from.value } } } External dependencies (e.g. arguments) may be thread-unsafe #2 Dependencies thread-safety Pitfalls Traditional way // nonatomic
  • 27. class Counter{ func add(_ value:Int){…} func subtract(_ value:Int){…} } counter.add(1) class CounterActor { func send(_ message:CounterMessage){…} } enum CounterMessage { case add(Int) case subtract(Int) } counterActor.send(.add(1)) ActorSwift
  • 28. • Message may not contain any shared state • Serialization/deserialization possible Full value semantics Actor message “Codable” “Codable” #2 Dependencies thread-safety Actor
  • 32. class ActorDriver<Actor:Actorable>{ private let queue:DispatchQueue private var actor:Actor private let externals:Actor.Command.Externals fileprivate init(actor:Actor, externals: Actor.Command.Externals, queue: DispatchQueue){ self.actor = actor self.externals = externals self.queue = queue } public func send(_ message:Actor.Message){ queue.async{ self.actor.onReceive(message).forEach{$0.interpret(externals: self.externals)} } } convenience init(actor:Actor, externals: Actor.Command.Externals){ self.init(actor: actor, externals: externals, queue: DispatchQueue(label:String(describing:ActorDriver<Actor>.self))) } } • Single function (send) • Statically typed message Input ActorDriver
  • 33. 01 protocol Actorable { associatedtype Message associatedtype Command:Commandable where Command.Message == Message mutating func onReceive(_ : Message) -> [Command] } protocol Commandable{ associatedtype Message:Messagable associatedtype Externals func interpret(externals: Externals, feedback: @escaping AnyActorDriver<Message> ) } 03 protocol Messagable {}
 02 typealias AnyActorDriver<Message:Messagable> = (Message) -> ()04 Input + Logic + Output Actor core logic
  • 34.
  • 35. typealias AnyActorDriver<Message:Messagable> = (Message) -> () Actor Driver type erasure
  • 36. class ActorDriver<Actor:Actorable>{ private let queue:DispatchQueue private var actor:Actor private let externals:Actor.Command.Externals fileprivate init(actor:Actor, externals: Actor.Command.Externals, queue: DispatchQueue){ self.actor = actor self.externals = externals self.queue = queue } func send(_ message:Actor.Message){ queue.async{ self.actor.onReceive(message).forEach{$0.interpret(externals: self.externals)} } } convenience init(actor:Actor, externals: Actor.Command.Externals){ self.init(actor: actor, externals: externals, queue: DispatchQueue(label:String(describing:ActorDriver<Actor>.self))) } } protocol Messagable {} protocol Actorable { associatedtype Message associatedtype Command:Commandable where Command.Message == Message mutating func onReceive(_ : Message) -> [Command] } protocol Commandable{ associatedtype Message:Messagable associatedtype Externals func interpret(externals: Externals, feedback: @escaping AnyActorDriver<Message> ) } Actor framework snippet
  • 38. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI .initial .reloadIntent
  • 39. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI .initial .reloadIntent
  • 40. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI .reloadIntent .loading
  • 41. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI .loading .loadElements
  • 42. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI .loading Network Actor .loadElements
  • 43. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI .loading Network Actor .loadElements
  • 44. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI .loading Network Actor .resultsReady
  • 45. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI .loading Network Actor .resultsReady
  • 46. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI .loading Network Actor .resultsReady .reloadIntent
  • 47. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI .loading Network Actor .resultsReady .reloadIntent
  • 48. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI .loading Network Actor .resultsReady .reloadIntent
  • 49. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI Network Actor .resultsReady .reloadIntent .presenting
  • 50. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI Network Actor .reloadIntent .presentElements .presenting
  • 51. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI Network Actor .reloadIntent .presenting
  • 52. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input ` UI Network Actor .reloadIntent .presenting
  • 53. enum Message{ case reloadIntent case resultsReady(elements:[Element]) } enum Command { case loadElements case presentElements(elements:[Element]) } enum ListScreenActor: Actorable { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.reloadIntent, .presenting(let elements)): self = .refreshing(elements: elements) return [.loadElements] case (.resultsReady(let elements), .loading), (.resultsReady(let elements), .refreshing): self = .presenting(elements: elements) return [.presentElements(elements: elements)] default: return [] } } } Output Logic ListScreenActor Input UI Network Actor .reloadIntent .presenting
  • 55. Actor A Driver Actor B Non actor C Actor
  • 56. Actors unit testing From async to sync state machine Actor
  • 57. enum ListScreenActor { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.resultsReady(let elements), .presenting): self = .presenting(elements: elements) return [.presentElements(elements: elements)] ... } } } Actor tests Initialize an actor Send message/ messages Observe commands func testFirstReload_startsLoading(){ var actor = ListScreenActor.initial let commands = actor.onReceive(.reloadIntent) XCTAssertEqual(commands, [.loadElements]) }
  • 58. enum ListScreenActor { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.resultsReady(let elements), .presenting): self = .presenting(elements: elements) return [.presentElements(elements: elements)] ... } } } Actor tests Initialize an actor Send message/ messages Observe commands func testLoadedResults_presentElements(){ var actor = ListScreenActor.initial _ = actor.onReceive(.reloadIntent) let commands = actor.onReceive(.resultsReady(elements: ["1", "2"])) XCTAssertEqual(commands, [.presentElements(elements: [“1”,”2”])]) }
  • 59. func testMultiplereloads_loadOnce(){ var actor = ListScreenActor.initial let commands1 = actor.onReceive(.reloadIntent) let commands2 = actor.onReceive(.reloadIntent) let commands = actor.onReceive(.resultsReady(elements: ["1", “2"])) let commands3 = actor.onReceive(.reloadIntent) XCTAssertEqual(commands1.onReceive(), ...) XCTAssertEqual(commands2.onReceive(), ...) XCTAssertEqual(commands3.onReceive(), ...) XCTAssertEqual(commands.onReceive(), ...) } enum ListScreenActor { case initial case loading case presenting(elements:[Element]) case refreshing(elements:[Element]) mutating func onReceive(_ message: Message) -> [Command] { switch (message, self) { case (.reloadIntent,.initial): self = .loading return [.loadElements] case (.resultsReady(let elements), .presenting): self = .presenting(elements: elements) return [.presentElements(elements: elements)] ... } } } Actor tests Initialize an actor Send message/ messages Observe commands
  • 61. enum Message:Messagable{ case retrievePath(path:String, id: UUID) ... } enum Message:Messagable{ case retrievePath(path:String, completion:(Int)->()) ... } #1 Completion handlers • Limitation: • No reference types in a message • Solution: • unique identifier
  • 62. • Limitation: • Actor reacts only for messages • Solution: • Separate object for sending message with timer events enum ScreenActor{ ... mutating func onReceive(_ message: Message) -> [Command] { switch (message, self){ case (.reloadIntent,.initial): self = .loading Timer.scheduledTimer(withTimeInterval: 60 , repeats: false) {_ in self = .initial } return [.loadElements] ... #2 Timers enum Message:Messagable{ … case timerEvent … }
  • 63. struct Actor:Actorable { mutating func onReceive(_ message: Message) -> [Command] { switch message{ ... case .contentError(_): ... } } throw #3 Error handling • Limitation: • No automatic thrown Errors propagation • Solution: • Manual propagation
  • 65. Chris Lattner Concurrency in Swift: One approach https://gist.github.com/lattner/31ed37682ef1576b16bca1432ea9f782
  • 66. Concurrency in Swift: One approach actor keyword reference type actor Counter{ private var value = 0 private let otherActor:OtherActor actor func add(){ // queue.async{ value += 1 //} } actor func addTwice() { // queue.async{ value += 2 //} } public func add(from:TimesProvider){ value += 2 } } Compiler’s addition
  • 67. // Swift actor MainActor{ actor private init() {} } // App Extension MainActor{ // App logic } Concurrency in Swift: One approach support for MainActor ValueSemantical protocol protocol ValueSemantical{ ... } struct State: ValueSemantical{ let some: SomeType }
  • 69. Actor systems Swift implementation Address concurrency issues Potential Swift actor support Actors Recap