詳説implicitly(あるいはimplicitlyは黒魔術でないことの説明) [Scala] on @Qiita https://t.co/lgI9eojnvY
— Kota Mizushima (@kmizu) 2019年7月23日
この記事を読んでていくつか感じたことと思い出したことをツールドフランス第15日目観戦しながら書き出します。 特にまとまってない。
記事中の黒魔術という表現についての個人的な補足
僕の勘違いでなければ、@kmizuさんは implicitly が静的に(コンパイル時に)一意に決定する、しかもそれがメタプログラミングやマクロ・リフレクションなどのコンパイル処理の外側ではなくコンパイル処理(= ファーストレベルの言語仕様1)として決まる点を指して黒魔術ではない、と行っていると思いました。
ただ、implicitlyを黒魔術的だと認識しているような人にはそこら辺の文脈・ニュアンスが伝わりづらい気がして非常に良い記事だけに少し惜しく感じました。
implicit parameterと型クラスの親子関係
おそらく、 implicit parameterという概念(もしくは、その元ネタである型クラス)
implicit parameterって型クラスから派生した概念でしたっけ?と少し引っかかりました。
implicitは特に型クラスを意識せず実装されたけれど、後々型クラスにも使えることがわかったために型クラスの表現方法としてimplicit + context boundが利用されている、とどこかで読んだような (もしかしたら説明を単純にするためにあえてこう書いているのかも)。
2019/07/26 追記
@kmizuさんにその後詳しく教えていただいたのですが、広く一般には知られていないものの紛れもなくimplicit parameterは型クラスのための機能として作られたとのこと。
詳細はこちら。
感想ありがとうございます。この辺、ちょっとややこしいなと思うのは、implicit parameterは、もともと「紛れもなく」型クラスのための機能である(というのはOdersky先生のバックグラウンドとか、 https://t.co/z17QhhltBc を見ると明らかです)にも関わらず、Odersky先生ご本人は、研究文脈以外では
— Kota Mizushima (@kmizu) July 24, 2019
implicitlyを理解することの困難さ
元の記事は簡潔にまとまったスクロール3画面分ほどの記事なんですが、僕はここで説明されていることを完全に理解できるようになったのは真剣にScalaを触り続けて3,4年経った後だったと思います。
この記事の中ではimplicitlyに到達するまでの道のりがだいたい以下のように提示されています2。
- implicitの使い方・作用
- context boundの意味
- implicitlyの使い方・作用
Haskellなどのバックグラウンドのない、Javaを触ったことのある程度の人間(だいたい10年前の僕)がもうちょっと補足するとこうなります。
題目 | 僕が理解した時期(Scala使い始めからの年数) | 理解にかかる労力 |
---|---|---|
implicitの使い方・作用 | 1~2年 | めっちゃ大変 |
context boundの意味 | 3~4年 | 型クラスを理解していると一瞬。 理解していないと使い方・概念がさっぱりわからない |
型クラスの概念 | 4~6年 | 大変。数回の挫折をはさみつつ足掛け5年かけてすごいHaskellたのしく学ぼう!と独習 Scalaz — 独習 Scalazで理解した |
implicitlyの使い方 | 1 ~ 2年 | それ自体は死ぬほど理解が単純。 型クラスとしての使い方に気づいたのは型クラスを理解した後だった |
上に書いていますが、僕が元の記事をだいたい理解できるようになったのは型クラスをぼんやり理解し始めた4年目以降でした。
こう書くとお前どんだけ頭悪いんだよと思われるかもしれませんが、実際のところ3つの職場で一緒にScalaを書いた同僚諸氏で確実に僕より早く・より深く上を理解していたのは10人中2,3人程度でした。 勉強への熱意や理解の早さはともかく、実際にScalaを使っている人でもかなりの人がimplicitやcontext boundなどをよくわからず使っている、またはそれらを知らなくても十分Scalaを使えていると思います。
implicit は本当にわかりにくい
改めて考えるとscalaのimplicitは本当にわかりにくいと思います。これはimplicitに多数の側面やシンプルでない仕様があるからだと思います。 以下implicitのわかりにくい点。
- 文字通りの暗黙的な関数パラメータという側面
- sttpのbackendのような、メソッド呼び出しの中で本質的ではないパラメータをメソッド呼び出しへ書かないことでよりメソッドの本質に集中する機能
- implicitで渡されるパラメータは環境・コンテキストなどのイメージ
- 多用により可読性の低下を招くと言われていたimplicitはこの用法のイメージ
- 型クラスとしての活用の側面
- implicitという修飾子がメソッドの外側・内側両方で作用する点3
- implicitが探索するスコープのルール
- 暗黙のパラメータ解決優先順位 | eed3si9nがよくまとまっていますが、継承、import、local宣言、パッケージオブジェクトなど片手に余る様々な方法でimplicitの値は渡すことができます
- Scala熟練者が多用するにも関わらず初心者が知らない概念の一つに暗黙のスコープ (implicit scope)があります
2) 探している implicit の型に少しでも関係のある様々なコンパニオンオブジェクトやパッケージオブジェクトから成る暗黙のスコープ (implicit scope) (具体的には、型のパッケージオブジェクト、型そのもののコンパニオンオブジェクト、もしあれば型の型コンストラクタのコンパニオン、もしあれば型の型パラメータのコンパニオン、型の親型や親トレイトのコンパニオンなど)。
結論
何が言いたいか。
1. implicit / context bound / 型クラス / implicitly わからないのは当たり前
それらがすぐにわからないからと言って、自分が頭が悪いと思ったりScalaに絶望しなくていもいいと思います。これらの概念は広範に普及しているプログラミング言語の中でもかなり難しい概念ではないかと。
2. implicit なんて全く使わなくても better java としてそこそこ使える
過去にimplicitもFutureもモナドも使わないScalaによるAPIサーバをScala初心者の人たちと一緒に書きましたが、Future・モナド・implicitを半端な理解で乱用したアプリケーションより10倍良いコードでした このように単なるbetter javaとしてscalaを使うことは全然ありだと思います4。
3. implicitly が黒魔術に見えている人はimplicitly以前にimplicitそのものや型クラス、型クラスを実現するためのcontext boundというsyntax sugarという概念がわかっていない
ここで話が最初の記事に戻ってきます。 元々の記事は非常によくまとまっていて内容は正しいのだけど、最低でもScala数年触っているような人じゃないとあれ読んですぐ理解するのは難しいんじゃないかと思いました。
4. 型クラスはちゃんと理解したほうがいい
implicitはScala 3でなくなるそうですが、型クラスの概念は多少変遷しうるもののおそらく今後20年, 30年以上プログラミング技術の中で使用される可能性が高いです。 すごいHaskellから逃げずに(!?)頑張って勉強しておきましょう。それにより得られるリターンは本当に大きいと思いますし、実際大きかったです(プログラミングの表現の幅が広がった)。