[swift-evolution] [Concurrency] Actors + Behaviors + Signals

Marc Schlichte marc.schlichte at googlemail.com
Sun Aug 20 14:43:41 CDT 2017


Hi,

here are some high-level thoughts on extending Actors with Behaviors and Signals.

Actors + Behaviors:

The set of messages an Actor might handle at a time is defined by the current behavior which can be changed with the `become` instruction:

```
behavior B1 {
  message m1()
  message m2() -> Int
}

behavior B2 {
  message m3(str: String)
}

actor A1: B1, B2 {
  init() {
    become B1
  }
  message m1() {
    print(„m1“)
    become B2
  }
  message m2() -> Int {
    print(„m2“)
    return 1
  }
  message m3(str: String) {
    print(„m3\(str)“)
    become B1
  }
}
```

`behavior` is a kind of `protocol` which contains only actor functions.

BTW, to allow for some bikeshed discussions here - I propose to use `message` instead of `actor func` - like preferring `actor`  to `actor class`.

Behaviors are optional - if you don’t define/adopt behaviors, all messages in an actor are part of an implicit behavior.

If a message arrives, which is not part of the current behavior, it will stay in the message queue but ignored until a supporting behavior becomes current again.

To allow the reception of another message while a message handler is currently suspended in some async call - maybe communicating with another actor - an `interleaved` modifier for messages might be introduced. These interleaved messages are not allowed to change the current behavior though.

Actors + Signals:

Like classes, which often provide reactive APIs (via `delegates`, `KVO`, `NotificationCenter`, `Observables`, …) for unsolicited events, Actors will need a way to send messages to unknown other Actors.

I thus propose the introduction of Signals:

```
actor A2 {
  signal s1(val: Int)

  message m1(val: Int) {
    print(„m1“)
    s1(val)
  }
}

actor A3 {
  message m1(val: Int) { … }
  message m2(str: String) { … }
}

let a2 = A2()
let a3 = A3()
a2.s1.connect(to: a3.m1)
```

Signals might also support stream functions like `map`, `filter`, `throttle`, `distinctUntilChanged`, etc, to allow for reactive value transformations of signals sent by actors:

```
a2.s1.throttle(interval: 0.2).map { String($0) }.connect(to: a3.m2)
```

Cheers
Marc
















More information about the swift-evolution mailing list