最近Scalaのコード読むことが増えたんですが、implicitパラメータのついた関数が多用されるとメッチャコード読みにくいんすよねアレ。このドワンゴのScala研修テキストにあるようなコード
この3つのメソッドは共通してConnection型を引数に取るのに、呼びだす度に明示的にConnectionオブジェクトを渡さなければならず面倒で仕方ありません。ここでimplicit parameterの出番です。
というコレね
def useDatabase1(....)(implicit conn: Connection) def useDatabase2(....)(implicit conn: Connection) def useDatabase3(....)(implicit conn: Connection)
たかだか変数名のタイプ数文字減らせるだけで何が嬉しいんすか?何の得があるんすか?って話っすよ。書く方は楽できていいかもしれないけど、こんなの読む方はたまったもんじゃない。
メソッド利用者側のコードから見た場合、引数のconnectionが明示されていれば、この関数の呼び出しでDBアクセスしているんだなって一目瞭然なわけじゃないすか。でも省略してしまったら、その情報が欠落するので、いちいち定義にジャンプして確認しなければDBアクセスしてるかどうかもわからないんです。スロークエリ出てるしSQLちょっと直そっかなとか思った時にストレスマッハになるやつですよコレ。一見DBなんて知りませんわーって顔して実はDBアクセスしてやがったって糞ビッチコードっすよ。ま、この例は useDatabase なんて名前付いてるんでビッチだってわかるけど、普通はそんなメソッド名つけないからね。
コードってのは書く時間より読まれる時間の方が長いものなのだから、多少早く書けたところで読むのを妨げるようなコードはトータルで見たらマイナスにしかならんのですよ。
しかしなー、言語デザイナーってのはだいたい超頭がいい人なわけで、そんな人が引数省略できますスゴイでしょwなーんて機能を入れるとは思えんのですよね。つまり俺がなんか根本的に勘違いしている可能性の方が高い。んで
今読んでるコード、コードが読みにくくなるだけでimplicit引数を使うメリットがあるように思えんのだが、おそらくこれは言語デザイナーの想定とは異なる使い方なのではないだろうかという・・・
— hisanori (@nullpon) 2018年4月25日
とかツイートしたらScalaの強い人から教えていただけました。メッチャ参考になります、神か。
こういう意図です。https://t.co/ZgDxf00zmk ご参考まで
— がくぞ (@gakuzzzz) 2018年4月25日
んー、やっぱ本来の趣旨から外れてんじゃんねコレ。スライド見るにimplicitパラメータの本来の目的は関数の多相性のため。ナンセンスな例だが意図するところはこんな感じのコードらしい。
trait Same[A] { def equals(x:A, y:A): Boolean } object Main { implicit val sameInt = new Same[Int] { def equals(x:Int, y:Int) = x == y } implicit val sameStr = new Same[String] { def equals(x:String, y:String) = x equals y } def main(args:Array[String]) = { Console.println(isSame(1, 2)) Console.println(isSame("3", "3")) } def isSame[A](x:A, y:A)(implicit s:Same[A]) = { s.equals(x, y) } }
これは可読性を損ねることはない。この場合コードを読み解く上で、どういう実装がなされているか、型ごとにどういう違いがあるか、スライドで言うところのhowなんて気にする必要ないからね。しかしDBアクセスするメソッドの場合、そのhowが大切なんすよ。DBアクセスしてるという事実そのものがコードの本筋であって読み解く上で重要なんすよね。それをimplicitで隠蔽されて読みやすいわけがない。
ちなみにscalaドキュメントのimplicit parameterの項でも多相性で説明している。いちいち引数かくの面倒だから省略なんてのは邪悪なimplicitではないかと思えてきたんだが、Scala界隈ではどういう位置付けになってるの?