こんにちは、テックフィード白石です。
日本のエンジニア界隈をリードするエキスパートに、テクノロジーの最前線を語っていただくYouTube動画連載「Ask the Expert」の新着動画が公開されました!
今回は、WebAssemblyのエキスパートchikoskiさんに、WebAssemblyの最新動向について詳しく伺ってきました。
chikoskiさんのアカウントをぜひフォローしましょう!
chikoskiさん(Wasm Night運営)
ついでに白石のもフォロー推奨:
聞き手: テックフィード白石
以下に掲載するのは、インタビュー動画の内容の要約です(正確な書き起こしではありません)。
内容をフルにご覧になりたい方は、ぜひ動画をご視聴ください。
(ご質問、ご感想などはYouTubeのコメント、もしくはこの記事のコメント欄でも受け付けております)
Wasm コンポーネントモデルが固まりつつある
白石: では1つ目の話題。Wasmコンポーネントモデル、というのはなんですか?
清水:たとえば、Rustコード上でPointという構造体があってx, y, z という3つの値を持てるとしますね。この同一性を調べるためのhash()という関数を定義して、Wasmにコンパイルすると、一番下のような型の関数に変換されます。
(type (;0;) (func (param i32) (result i64)))
清水:面白いのは、元のハッシュはPointという 自分で決めたデータ型の関数ですが、Wasmではi32という型になる ことです。つまり、「符号付き32ビット整数を受け取って、符号付きの64ビットの整数を返す」という関数になるんですね。
WebAssemblyの型は実は、整数か浮動小数点か、32ビットか64ビットかという組み合わせの4つしかなくて 、i32はその1つです。複雑なデータ、ユーザー定義型、文字列型などは別途あるメモリーの上に表現されていて、そのアドレスを受け取る関数みたいな感じで定義されます。
白石:ポインターみたいな。
清水:そう、ポインターです。C言語を知っている人からすると「そうだよね」という感じですね。構造体も何もかも全部アドレスなのでそうなるのですが、他の言語から来る人は驚きがあるかなとは思います。
また、構造体をメモリー上にどう配置するかというのも処理系任せになっています。
Rustだとメモリー表現を指定できるのですが、さっきの例で挙げたPointという構造体でも、指定の仕方によって配置が変わってしまいます。
清水:これが一つのモジュールの中で完結しているうちはいいのですが、たとえばモジュールの外とモジュールの中でやり取りする時に、(処理系によって配置がまちまちだと)困ってしまうわけです。相手のプログラムに文字列を渡せないとか、ファイルみたいなものを扱いたいとか、そういう時にデータ構造を渡しても、相手が解釈できないわけです。
文字列を例に取ると、僕はC言語のつもりで先頭のアドレスからNULL文字までが文字列だと思って作っているんけれども、白石さんは先頭のアドレスとその長さのペアで文字列を表現する前提だったとしたら、文字列の受け渡しができなくなってしまう。
こうした相互運用性の問題は初期からずっと指摘されて検討されてきているのですが、解が出ていませんでした。
しかしようやく、検討の過程でインターフェースとデータ表現の全部を組み合わせないと良い仕様にならないということがわかって、 それまでの議論をいったん全部発展的に解消してコンポーネントモデルという仕様ができています 。
まだ正式な勧告にはなっていないですが、その仕様がフェーズ3として固まりつつあるという感じです。
清水:このコンポーネントモデルの仕様は、大きく分けて2つあります 。
1つは、データ表現をどうするかというデータ表現の変換方式に関する仕様。
もう1つは、そのインターフェースの決め方を決めた仕様です。
後者にはIDL (Interface Definition Language: インターフェース定義言語)という新しい言語が作られていて、この文法に従ってインターフェースを定義していきます。
このIDLを機械的に変換することで、RustやJavaScriptなど、各言語のスケルトンができあがりますので、あとはそれをテンプレートにして実装を埋めていけばコンポーネントが作れるという仕組みです。
同時にツールもできてきています。例えばRustでは、 curgo component
というcurgoのサブコマンドを叩くと、インターフェースも含んだ形でプロジェクトファイルやディレクトリができあがり、それをビルドするとコンポーネントができるというツールチェーンができています。
実行環境としても、Wasmtimeというランタイムが積極的にサポートされています。Rustでプログラムを書いて、Wasmコンポーネントに変換して、Wasmtimeの上で実行することができるようになっているので、今から試すならこれを勉強されるといいと思います。
白石:ありがとうございます。ちなみにちなっみにこのIDLですが、さっき言ってらっしゃった、バイト配列やサイズといったデータ表現を表すにしては だいぶ抽象度が高め ですね。stringなんていう型も使えそうですし。
清水:そうなんですよ。いくつか組み込みの型が抽象度高く定義されていて、たとえば string
だとか、 signed / unsigned int
、列挙型などもあります。
また、最近のプログラミング言語に影響を受けて、成功/失敗を表す result
型や、値を持たない場合がある状態を表す option
型などが組み込みで用意されているところも抽象度が高いと思います。
また、コンポーネントのIDLが出てくると、npmみたいな、パッケージのエコシステムも視野に入ってくる。
そこで、wargというものが提案されています。仕様はnpmと違って、サービス自体ではなくプロトコルが定義される形になっていて、(そのプロトコルに則ったレジストリを)勝手に自分で立てても大丈夫な仕様になっています。
白石:セキュア・レジストリ・「プロトコル」と書いてありますものね。
清水:はい。仕様がプロトコルとして作られていて、参照実装があります。まだ、運用されているレジストリ自身を使うことはできなくてお試し版のみですが。
白石:もしGitHubが対応してくれたら、WasmファイルをGitHubから直接importすることもできるようになるかもしれないですね。
清水:そうですね。GitHubでビルドしてリリースしたら、内部で自動的にプロトコルが走って登録みたいな感じで。
白石:素敵な世界ですね。素晴らしい。
清水:そういうのもそろそろできつつあるという感じです。