RubyKaigi 2023で "UTF-8 is coming to mruby/c" というタイトルで話しました

スライドタイトルは「サンタが街にやってくる」つまり「Santa Claus Is Coming to Town」のもじりでした。

UTF-8がルンルンでmruby/cにやってくる様子を思い浮かべながら決めました。

スライド

きっかけ

発表内でも触れましたが、はすみさんにRubyWorldConference2022でmruby/cのUTF-8対応をしませんかと誘われたのがきっかけです。

文字コード好きなひとが来場する情報を事前にTwitterでキャッチしていたので、PicoRubyのUTF-8対応という釣り糸を垂らしたら、うまいこと引っかかりました。 質問タイムのときにちょうどその人が質問してくれて、「ちなみにUTF-8に興味ありません?」と聞いたら「めっちゃあります」とのことで、「じゃあ後ほど打ち合わせしましょう」と公衆の面前で言質をとった次第です。   mruby/cのUTF-8対応は進めてよい、とすでに開発者会議で決まっています(PicoRubyコンパイラ側は私の一存でなんでもできる)から、あとはやるだけです。

shimane.monstar-lab.com

言質をとられるシーンがYouTubeに残っています。

youtu.be

2022年にUTF-8を0から実装できる、しかも人々に使われる言語で…というのはとても魅力的で、ワクワクしました。

この時点ではmrubyとmruby/cの違いもわかっていませんでしたが、はすみさんに質問できるなら実装できないことはないだろうと思っていました。

プロポーザル

2022年末ごろに私はIRBとRelineのメンテナになりました。そうすると不思議なことにRubyKaigiへの焦がれるような執着がスッと消えました。RubyKaigiへのモチベーションがなくなったわけではないけれど、絶対にプロポーザルを出さなければ…という自分の中のプレッシャーからは解放されました。

また、前回のRubyKaigiからあまり日がなかったこともありプロポーザルを出すかどうかは直前まで悩んでいました。メンテナ活動も始めていて、プロポーザルとして出せるような大玉を持っていなかったというのもあります。mruby/cのUTF-8対応も未着手でした。今年は出さなくてもいいかな、と思っていました。Asakusa.rbの新年会までは。

1月24日にAsakusa.rbの新年会があり、そこでIRBの話をたくさんしておいしい羊をたくさん食べてとても楽しい時間を過ごせました。翌日、RubyKaigiのプロポーザルを出そうというやる気が湧いてきました。IRB, Relineで話せるようなネタはないのでmruby/cのUTF-8対応ができそうか下調べを開始していけそうだったのでプロポーザルにまとめてSubmitしました。その時点での実装は0で去年に引き続きまた見切り発車ですが、UTF-8のことは調べれば分かるのとmrubyが参考になりそうなことは知っていたのでまあ形にはなるだろうとの見込みで行きました。

その後しばらく実装を進めておらず、3月にプロポーザル通過の連絡が来て実装をはじめました。今思えば2月にもう少し作業しておけばよかったです。

実装

ただしく実装できた部分は発表の中で話したので、ここでは発表で話さなかった部分を書きます。

Stringの各メソッドでUTF-8に対応させるという方針は決めていたので粛々と実装とテストを書いていました。C言語とmruby/cについては素人なので、ChatGPTにいろいろ質問しながら進めました。ポインタ演算やポインタをprintfする方法など基本的なことを質問したり、関数をまるごと渡して要約してもらったりしました。ChatGPTにはとても助けられました。ChatGPT 4のサポートをしてくれた所属先の永和システムマネジメントに感謝しています。

ほかにはmemcpy, memmoveをすることでどうバイト列を操作するか分からなくて手書きで方眼紙にバイト列とアドレスを書いてどうやってバイト列が移動するのか理解したりしていました。ビット演算も不慣れで、16進数と2進数の変換を脳内で行う練習をしたりしました。こういうのは実際に手を動かすことで理解が深まると思います。

いろいろ困ったこともおきました。\0 を文字列終端の判定にしていたら、Ruby側から途中で \0 を含む文字列が渡されたときに途中までしか見なくなってしまうとか。こう書くと当たり前ですが、Cに不慣れでよくわかっていませんでした。

        s1 = "ABC\x00\x0d\x0e\x0f"
        assert_equal 7, s1.size # => 3

String#inspectの修正には少し悩まされました。mruby/cのテスティングフレームワーク自身がmruby/cのinspectを使っているため、expectedとactualで全く同じ結果が出力されていますがこれはテストに失敗しています。コード読んで直しました。

    1) StringTest#string_inspect_case (:assert_equal)
      description : String#inspect
      expected    : ""\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86"" [String]
      actual      : ""\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86"" [String]
      # /work/mrubyc/test/string_test.rb:951

あとはmruby/cのStringのテストがいろいろ不足していたため、テストを追加するPRをいくつか出しました。mrubyc contoributors 4位になりました (12 commits) https://github.com/mrubyc/mrubyc/graphs/contributors

実装過程は気づいたことや思ったことのメモを取っていました。中途半端なところで中断しても「次はここからやるんだな」ということがひと目で分かって便利でした。また、たまに見返すことで自分がやってきたことを振り返ることができました。この記事を書くのにもかなり役立っています。

RubyKaigiの準備が前日になっても全然終わっていない悪夢を3回くらい見ました。LTとKeebKaigiにはプロポーザルを出さないことを決めました。

発表

人がたくさんいてかなり緊張しました。OpenStudioはお立ち台と1列目が近く、1列目に見知った顔を何人か見かけました。同僚のふーがさんと目があって、声をかけてもらえて少し緊張がほぐれました。

発表は28分で時間的にはちょうど良かったと思います。話し終わった後に「楽しそうに話していてよかった」とフィードバックをもらえてよかったです。文字コードの面白さ、結局すべてはバイト列であるということが少しでも伝わったら幸いです。

ふりかえり

しかしスライド作成がギリギリになったこと、実装が完了できなかったことは残念でした。みなさんにお届けできる状態で発表したいです。また練習不足も感じました。去年よりは早めに手を付けられたものの、やはり実装完了している状態でプロポーザル出すのがスケジュール的にはよいなと感じました。またスライドの英語の説明、図表の少なさ、情報密度などに課題を感じています。特にRubyKaigiは「わからないことによるワクワク感」があっていいカンファレンスだと感じます。もっと情報密度を高めて、わからなくても楽しいと感じるような発表をしたいと感じました。

今後やりたいこと

  • UTF-8対応の残りの実装
  • Unicode Standardを読む
  • mruby/cを実機にデプロイ
  • mruby/cのテスティングフレームワークでassertionが落ちた行が分からないのを修正