世界を動かす技術を、日本語で。

スウィフト・アーラン・アクターシステム

概要

swift-erlang-actor-system は、Swiftの分散アクターでErlangクラスタに参加できる新しいアクターシステム。 Erlangの「Cノード」機能をSwift向けにラップし、Elixir/Erlangノードと通信可能。 ElixirErlang との連携例や導入手順を紹介。 メッセージシリアライズや @StableNames による関数名安定化に対応。 SwiftとErlang間の分散システム連携を容易にする設計。

swift-erlang-actor-system 概要と特徴

  • swift-erlang-actor-system は、SwiftプログラムがErlangクラスタへ参加可能なアクターシステム
  • Erlang の分散ノード(runtime)や Cノード 機能をSwift用にラップ
  • Swiftの分散アクター機能と組み合わせて、Erlang/Elixirノードと相互通信可能
  • 例として、Swift製のチャットプログラムをElixirノードから操作可能
  • Elixir/Erlang とSwift間でのプロセス間通信を簡単に実現

導入手順

  • Elixir をインストール(macOSなら brew install elixir
  • epmd(Erlang Port Mapper Daemon) を起動しノード発見をサポート
  • Elixirノードを起動し、 cookieホスト名 を取得
    • コマンド例: iex --sname elixir_node
    • Node.get_cookie()でcookie確認
  • Swiftパッケージにotp-interop/swift-erlang-actor-systemを依存追加
  • サンプルアクター(例: Counter)を作成し、ErlangActorSystemでノード初期化
  • 他ノードへの接続やアクター登録を実施し、Elixirから操作可能に
    • 例: GenServer.cast({:counter, :"swift_node@YOUR_HOSTNAME"}, :increment)

技術的詳細

  • ネットワーク・シリアライズ にはErlang/OTPのerl_interface Cライブラリを利用
    • Swiftパッケージ内でCターゲットとして同梱
    • Transport を差し替えることでWebSocket等カスタム通信も可能
  • メッセージのシリアライズはDistributed Erlangの External Term Format を採用
    • TermEncoder/TermDecoderクラスでSwiftのCodable型を変換
    • swift-binary-parsingによるデコードも実験中

@StableNamesによる関数名安定化

  • クロス言語RPCでは 関数名の安定性 が課題
    • Swiftのデフォルトは関数名マングリングのため、Erlang側から呼び出し困難
  • @StableNames マクロで、アクターのメソッドにユニークな安定名を付与可能
    • 例: @StableName("increment")
  • @Resolvable と組み合わせて、Erlang実装プロセスとも連携可能
    • Protocolに@StableNames付与し、HasStableNamesに準拠
  • 安定名を利用して、Swift/Erlang間で正確な関数呼び出しを実現

利用例と応用

  • elixir_pack (ElixirアプリをiOS等にバンドル)の通信基盤として活用
  • クライアント-サーバ間の分散Erlang通信や、メッセージフィルタリング用途
  • Swiftの分散アクター×Erlang/Elixirの分散システム連携基盤

今後の展望

  • クロス言語アクターシステムで 安定名 は必須要素
  • Swift本体への @StableNames 的機能の統合を希望
  • Swift分散アクターのさらなる発展とコミュニティの意見募集

Hackerたちの意見

ひとつ、はっきりした答えが得られないことがあるんだけど、Swiftは自動参照カウントを使ってるよね。どうやら、高コストなアトミック操作が必要みたい。これを回避する方法はあるのかな?データがすべてスレッドローカルだから、非アトミックカウンタを使うのは可能なはずだよね?

やったことはないけど、これが役に立てばいいな。 https://stackoverflow.com/questions/25542416/swift-with-no-a...

「クラス」オブジェクトだけが参照カウントされるよ(ある程度、クラスっぽいオブジェクトもね)。Intや構造体(値セマンティクス)オブジェクトは参照カウントされない。これらは早めにコピーされるんだ。Swiftは、参照カウントを回避してコピーを最小限にするために、値オブジェクトを使う手助けをするための所有権キーワードをたくさん導入したよ。もちろん、私の理解では、Swiftの「アクター」は「クラス」っぽいオブジェクトだから、参照カウントされることになる。でも、それが他のシステムとどう違うのかはよくわからないな(アクター自体が変更可能で、結局は参照オブジェクトになるから)。

Swiftコンパイラは、スレッド間で本当に共有されている場合を除いて、多くのARCオーバーヘッドを排除するためにライフタイムと所有権の分析を行ってるよ。 https://g.co/gemini/share/51670084cd0f - ちょっとダサいけど、コアコンセプトに触れてるね。

他の人が言っていることに加えて、カウントを更新する必要がある場合でも、必ずしもアトミック操作を使う必要はないよ。参考にしてみてね。https://dl.acm.org/doi/10.1145/3243176.3243195: 「BRCは、ほとんどのオブジェクトが単一のスレッドによってのみアクセスされるという観察に基づいていて、これによりほとんどのRC操作が非アトミックで実行できる。BRCはこれを利用して、各オブジェクトを特定のスレッドにバイアスをかけ、各オブジェクトに対して2つのカウンターを保持する --- 1つはオーナースレッドによって更新され、もう1つは他のスレッドによって更新される。これにより、オーナースレッドはRC操作を非アトミックで実行でき、他のスレッドは2つ目のカウンターをアトミックに更新できる。」(今のところSwiftがこれを使っているかは分からないけど)

このプロジェクトに関わってたから、シェアしてくれてありがとう!これは、モバイルデバイスでBEAMを動かしたり、WebSocket経由でdisterlを使ったり、disterlで送信されるメッセージをフィルタリングしたりするプロジェクトが集まった大きなotp-interopのGitHub組織の一部なんだ。プロジェクトについての質問があれば、喜んで答えるよ。

Erlang/OTPは高遅延環境(例えばモバイルデバイス)ではうまく動かないって聞いたけど、本当なの?WANを跨いでOTPを動かすための特別な考慮事項はあるのかな?

このプロジェクトに関わっていて、ちょっと背景を説明したいんだ。これは、ネイティブUIをレンダリングできるウェブブラウザを作るための、もっと大きな取り組みの一部なんだ。例えば、Hello, world!!の代わりに、Hello, world!ができるって感じ。はっきり言っておくけど、これはウェブレンダラーじゃないよ。HTMLをレンダリングしてるわけじゃなくて、実際のネイティブUIをレンダリングしてるんだ。だから、SwiftUIで言うと、Text("Hello, world!")になる。もちろん、スタイルシートシステムを通じてモディファイアやイベント、カスタムビュー登録もサポートしてるし、通常やってることは全部Swiftでできるよ。このライブラリが関わるのは、ヘッドレスブラウザがデバイス上で動くようにElixirで作られてるから。SwiftUIレンダラーとはdisterlを介して通信してる。仮想DOMを構築していて、vDOMの各ノードはそれぞれ独自のErlangプロセスを持つんだ。(DOMのプロセス制限について話したい人がいれば、詳しく説明できるよ)ドキュメントは、対応するSwiftUIビューにプロセスを直接伝える。さらに進めて、クライアントサイドのJSライブラリをWASMにコンパイルして、ヘッドレスブラウザで実行し、WasmExを使ってElixirにブリッジしてる。これがうまくいけば、Webの開発エルゴノミクスを、コンポーザブルUIフレームワークを持つすべてのネイティブプラットフォームに持ち込めるはず。HotwireやLiveWireの実際のネイティブターゲットを考えてみて。現在、ほぼすべてのSwiftUIターゲット(MacOS、iPhone、iPad、Apple Vision Pro、AppleTV)向けにビルドできるよ。Watchは、私たちがこのライブラリに必要なデバイス上のネットワーキングが欠けてるから、ちょっと特殊な存在だね。これは元々LiveView Nativeプロジェクトとして始まったけど、上流プロジェクトとのコラボレーションでいくつかの問題があったから、範囲を広げることにしたんだ。Swiftのポータビリティのおかげで、他の言語にも持ち込めるはずだよ。統合のポイントに近づいていて、この取り組みをベンチマークして検証できるようになってきた。質問があれば、喜んで答えるよ!

このプロジェクトをフォローする場所はあるの?すごく面白そうだね。

これはLiveview Nativeとどう違うの?

「これがうまくいけば、Webの開発エルゴノミクスを、コンポーザブルUIフレームワークを持つすべてのネイティブプラットフォームに持ち込むことができる。これは思っていたよりもずっと大きなものになるだろう!早く見てみたい!」

SwiftUIはUIツリーの要素にアクセスできないと思うんだけど、UIkitとは違うよね。だから、UIを制御するためにXMLのようなコードを使うことを許可してないってこと?単にSwiftUIコードを書くための代替手段って感じ?状態はどう扱うの?SwiftUIでできることと同じように?あなたのVDOMは実際には(抽象)構文木の代替構文なの?SwiftUIコードを書くためのIRとして使われるの?Lynxとはどう違うの?React Nativeとは?(XMLのような構文を除いて、状態管理はどうなの?)かなり興味深いね!

これはXAMLみたいな感じ?Firefoxはずいぶん前にXAMLでUIを構築してなかったっけ?https://en.m.wikipedia.org/wiki/Extensible_Application_Marku... https://news.ycombinator.com/item?id=8730903

これはhyperviewとどう比較されるの?https://hyperview.org/

「上流プロジェクトとのコラボレーションにいくつかの困難があった」 これについて詳しく教えてもらえる?

なんか、思ってた通りに物事が進んでる感じだね。「ウェブサイト」がライブアプリケーションになって、ネイティブUIやフレームワークと連携するようになるっていう。標準化されたAPIを使ってね。メインフレームも悪くないアイデアだったかも。これって、現代版の再構築みたいな感じだし。WASMの時点で、こうなるのはなんとなく予想できてたよ。このプロジェクトが全ての問題を解決する「答え」かどうかは分からないけど、方向性としてはいいステップだと思うし、すごく好きだよ。SwiftもErlangも使ってないけどね。

これ、いいね!私はSwiftユーザーじゃないけど、JInterface(OTPに含まれてるやつ)を使ったプロジェクトに関わったことがあるよ。これは実質的に同じことをJVM言語向けにやってるんだ。すごくうまくいって、すでに持っていたJavaライブラリを簡単に再利用できた。インターフェースもかなり楽だったと思う。