RxJava Night振り返り(Reactive Extensionsの歴史)

RxJava Nightというイベントで、Rxの歴史!というほど大仰なものでもないですが、誕生から今に至るまでをサラッと振り返った資料でLTしてきました。

The History of Reactive Extensions from Yoshifumi Kawai

普段は時間オーバー常習犯なんですが、今回はちゃんと時間を意識して収めましたよ!中身的にはまだまだアレもコレも詰めたい欲もあったりなかったりですが、まぁむしろこのぐらいが丁度良いのかもしれません。幸い、わりかし評判も良かったようで何よりです。

Rx across languages

改めて実感したのは、もうRxは.NETだけのものじゃない、ということです。むしろ他言語のほうがずっと盛り上がっているというのは実感するところで、ReactiveCocoa、そしてRxJava。こちらのほうが熱い。それはもう事実として。勿論いいことです。とはいえそうなると、もはや.NETのReactive Extensionsの存在すら知らない人も沢山いるというところなので、そこを少し知ってもらえたら何よりですね。会場のマック率が99%だったりC#erが2人ぐらいだったりと、ひぢょーにゲンジツを感じました!

もしこれ、RxJavaがRx***という名前付けないで別の名前だったら、それで普及して、完全にReactive Extensionsに言及されることはなくなっていたんだろうなあ、ということを思うと、名前が残って良かった良かった(笑)

.NETでRxがそんなに目立って使われないのはいくつか理由がなきにしもあらずなんですが、一番大きな理由は、今回の勉強会でも一番大きく言及されていた非同期関連においてはそんなに重宝しない、というとこかなあ、と思います。重宝しないというか、C# 5.0でasync/awaitが搭載されたので、そちらでやったほうがかなりスッキリ書けるという。

並列処理に関してはgihyoでのグラニがC#にこだわる理由 第1回 神獄のヴァルハラゲートの裏側をCTOが語り尽くす!の図の1の部分を見てもらいたいのですが、さっくり書けてますよね、と。コードは

var frontHPs = await field.OwnGuild.Members
    .Where(x => x.Position == Position.Front)
    .Select(async x => new
    {
        Name = await x.Name,
        CurrentHP = (await x.UserStatus).CurrentHP
    })
    .WhenAll();

とかね。これも含めてサーバーサイド全般での活用に関してはAWS Summit Tokyo 2014で発表した以下の資料をどうぞ。

AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践 from Yoshifumi Kawai

非同期系はそれとして、今回Androidのかたが多かったようにバインディングとかはどーなのか、というと、もともとC#にはView側がXAMLというバインディング前提のHTMLみたいなUIマークアップ言語があったので、Rxにフルに頼る必要がない、という事実はあります。なので、そこまで切羽詰まってない、みたいな。もちろん、組み合わせて使うというのは有り得るパターンで、GitHubでも使われている(というか作ってる人が中の人な)ReactiveUIや、私の作った(現在の機能向上は完全にokazukiさんに渡してます)ReactivePropertyといったライブラリもあります。それらのAndroid(+ Xamarin)への活用はamay077さんがXamarin.Forms と ReactiveProperty で快適MVVM生活といった記事も書かれていますし、色々ありますねというか、別に冷め切ってるわけでもなくて、やっぱRx熱いよ!ってのは全然あります!はい!

LINQ

C#erがRxを理解するにはLINQから入って考えるんですが、他言語の人はRxから入るんですよね。その辺が一番大きなギャップかもしれません。私的にはLINQから入って、IEnumerableとIObservableの関係性とか意識しながらのほうがスムースだったんですが(例えばIObservableでScanを考えるのは大変、このRxJava WikiのScanの図の意味不明さ!でも、IEnumerableでScanを考えるのは、まだ容易!)どーなんでしょふ。別にLINQじゃなくてStream APIとか、自分の言語のコレクション処理と少し付きあわせてみるといいかなあ、というのは本当に思っています。なぜ双対のソの字も出してないか。IEnumerableが前提じゃないから。そこの説明をする時間はない!(Erik Meijerの起こした会社の名前、Applied Dualityは勿論dualityから来てる)

Rxが流行るには?

懇親会で話したことなんですが、どーなんですかねえ、RxJava流行りますか!?個人的には勿論流行って欲しいんですが!言語関係なく共通のお話ができますし、悩みも活用も応用例も、言語が増えれば増えるほど盛り上がる、嬉しい、んですが、実際どうでしょう。まず、ラムダは必須。無名クラスで書くのは無理ですねえ。こういうの、IDEの自動生成でなんとかなるものとなんともならないものがあって、Rxぐらいラムダを使いまくるものは無名クラスで自動生成しまくると、生成後のブツの可読性が悪すぎて辛すぎます。AndroidではまだJava8対応していないようですし、いつするかもわからないということで、辛いですねえ。Groovyのほうがまだ可能性はありそうだけど、AndroidでGroovy、どうなんでしょう、それはそれでそれもまた流行るための壁が二段階増えてる感は否めない気もする。

学習コストは間違いなく大きい。うーん、Streamの時点でもそれなりに高いとは思うんですが、でもやってやれないこともないし、慣れてしまえば凄まじく便利でOKだと思います。ただ、Rxもそれと同じといえるかというとそうでもない。次元が1個増えたような感じなんですよね、シーケンス的な考え方に「時間」と「スレッド」の概念が混ざってくるので、慣れてても複雑に絡み合ったRxのチェーンを読み解くのは大変。二次元なら見えるけど四次元は辛いよね?的な。ただ、それはじゃあ普通に書いても複雑なステートになっているはずなので、Rxが悪いわけじゃあないといえばないんですがねえ。

Rxで非同期やるなら、下の層から上の層までIObservableで通す必要があると思っていて(そうでなければ途中の層でブロックしているということだ!)、ある種の非同期汚染みたいなのが発生します。これはC# 5.0のasync/awaitにもいえて、下から上までTask(Future/Promiseみたいなの)が貫く必要がある。そういった根本的な変化が生じるので、やるんならむしろ徹底的にやってしまったほうが大きな結果が得られるかな、と。

最後に全く関係なくそういえば懇親感で少し話したUnityでのLINQのAOT問題。Unity + iOSのAOTでの例外の発生パターンと対処法ではmonoからEnumerable.csを持ってきたらどーよ?と書いたんですが、OrderByは落ちます。で、うちの会社では(OrderBy以外にも)それなりに手を加えて調整しまくって、今現在はほとんど落ちない状態になっているんですが、とりあえずOrderByの改造点だけ。以下の様な変更をいれれば大丈夫です。

-abstract class OrderedEnumerable<TElement> : System.Linq.IOrderedEnumerable<TElement>
+public abstract class OrderedEnumerable<TElement> : IEnumerable<TElement>, IEnumerable

-abstract class SortContext<TElement> : IComparer<int>
+public abstract class SortContext<TElement> : IComparer<int>

-enum SortDirection
+public enum SortDirection

IOrderedEnumerableだけを露出させると危ないので、abstract classをpublicにしちゃいます。そうした調整のせいでSortContextとか本来はprivateにしてたいものも露出してっちゃって望ましくないんですが、まぁそこは背に腹は代えられないということで妥協しましょう。妥協は大事です。理想よりも現実が一番偉いんです。

Profile

Yoshifumi Kawai

Cysharp, Inc
CEO/CTO

Microsoft MVP for Developer Technologies(C#)
April 2011
|
July 2024

Twitter:@neuecc GitHub:neuecc

Archive