"Scalaのソースを読んでいて辞めてほしいと思った12の機能" についての感想

http://d.hatena.ne.jp/h_sakurai/20111221

まず前提として、blogを書いた意図をなんとなく推測して適当に独自に3種類に分類

  1. https://github.com/joshcough/Compilers の例があげられているので、とにかくこのソースコードについての文句(ソースコードの汚さ)を主張したい
  2. h_sakuraiさんが一般的にScalaのコードを読む場合に、(そこまでScala自体に詳しくないので) "こういう部分が読みづらく感じた" という主観的な感想(を書いてみたかっただけ)
  3. 一般的なScalaのコードを書くべきときの基準として、使うべきでない機能や、やるべきでないパターンを列挙して、(他の人にも)ここに書いたことを実行して欲しいという主張

おそらく2番目の、"読みづらいと感じた"という部分が大きいのだと思います。1番目もあるとは思うし、3番目もどのくらいあるのかわからないですが。


それで、
1番目のものに対しては、あまり読んだことないし、わざわざ全部読む気にもならないので、あまり深くは触れません。さらに具体的に(汚い部分を?)書いてもらえば、いろいろ書けるかもしれないけれど。

あと、3番目だと決めつけて、真っ向から反論ばかり書いてもあまり生産的にならない気もするし、やめて欲しいといいつつ

いつも悩むので、これは覚えるべきか。

などと、前向きなことも書かれているので、まぁ基本的には2番目だと仮定して、いろいろ書いてみようかと思います。

traitで多重継承っぽくふんだんに使う

自分もそこまで使わない、(というかこのパターンを使い慣れてなくて、もうちょっと使ったほうがいいのではないかと思いつつ使えてない)んですが。

どこに何があるか分からないじゃないかー!

たしかに"どこになにがあるかわかりづらくなって、ソースコードが追いにくくなる"というのはデメリットだと思います。が、メリットもあるので・・・としか書けないですね、具体的な例がないと。あとScalaに限らず、多重継承的なことができる言語すべてに共通しますし。さらにそれに対する代替案も書かれていないので。たとえば

  • とにかく多重継承はせずに(誰にでもわかるような)手続き型で書くべきなのか?
  • Javaみたいに単一継承で?
  • いや継承とか使わずに、純粋関数型で!

とか。

traitを後付けでバックエンドを切り替えて嬉しいぜ機能

これは・・・たまに便利だけど、確かに、はじめて見るととまどうことは多いかもしれません。あまりしっかりソース読んでませんが、

new A with X86Backend

とかなんとかやると、 AにX86Backendの機能が追加されて嬉しいぜってことらしいのだけど

と書かれているので、たしかにそのパターンばかりがでくるなら他で代替できるかもしれませんね。(たまに嬉しいパターンの解説は略。誰か書いて・・・)

_:* なにこれって感じなんですけど

可変長引数は・・・Javaにもあるし、あまりというかほとんど同意できないですねこの点に関しては(´・ω・`)collectionの初期化がすべて可変長引数使ってるので、これがないと以下のようなことができなくなりますし

List(1,2,3,4)
Map("a" -> 1,"b" -> 2)

というか、 _:* と書いているので、可変長引数に対してSequenceを展開して渡す機能のことだけを言ってるのかな?いまいち意図がつかめない・・・

foldLeft, map

これは結構でてきますし、Scalaある程度やっていくつもりなら覚えたほうがいいのではないかと・・・このあたりをつかわないのなら、Scalaを使う意味がかなり減ってしまうでしょうし。また、わりと最近の言語には普通に名前は違えども同じようなものはありますし。*1ただ、foldLeft自体は読みづらいというのは確かで、どこでも使うものではなく、

  • もっと便利につかえる高階関数(またはメソッド)がすでに用意されているならば、それを使うようにする
  • foldLeftで似たようなパターンが何度もでてきて、なおかつ使えそうな高階関数(またはメソッド)がないならば、自分で(foldLeftなどを使って)つくる
  • foldLeftに渡す無名関数が長くなりすぎないようにする

など気をつける点はいろいろあるとおもいますが。

yield

これは、以前にもこんなことがありましたが

ここがヘンだよScala言語
「ここがヘンだよScala言語」についてのまとめ

手続き型言語から入ってるくると

yieldがない形のforの構文が普通で、なんかyieldで値返すのってなんか特殊で気持ち悪い、なんでそんなことできるようになってるの?
と大体の人が思うわけですが、(自体もScalaの勉強当初は多少はこう思った気がする)
逆に、関数型言語の素養がある人や、Scalaにかなり慣れている人からすると
ScalaのforってHaskellのdoと同じでMonadのための記法でしょ
の一言で済んでしまったりするわけです。むしろHaskellのdoと微妙に構文違ったりとか、(yieldで値を返さずに)ループを回す的な使い方ができちゃったり、初心者向けの本ではちゃんとそのあたり説明してなかったり、とそのあたりが微妙だったりもするわけです。
最初に "Javaの拡張forみたいに、コレクションを列挙することに使える" 部分のみを強調しすぎる、弊害(?)的な部分もあるとは思いますが・・・。
だったら、

yieldがある場合とない場合で、そもそも両方に"for"という単語をつかうのではなく別な単語を割り当てるべきだったか?

などと妄想することはできますが、もうScalaのforはこういうものなので、今更構文変えられないだろうしょうがないですね。
for yieldを使わずにmap flatMap withFilterで書いても、ものすごくコード量が多くなるわけでもないですが・・・

このあたりは時間の問題というか、地道に、" Scalaのforは単にループのための構文じゃなくて、 yieldがない場合がむしろ特殊な場合" という考え方もできて、実はモナ(ry
というのを主張しつづけて、広まるのを待つしかないですかね・・・

時間計ってくれる関数

これはほとんど、h_sakurai さんが読んでたソースコード個別の問題という感がしますね。手軽にできるので、開発途中なら結構自分も普通に使いますし、でもある程度完成したのにもかかわらず、こういうコードがそこら中に仕込まれていたらたしかにちょっと邪魔ですし

S式の読み込み、出力機能

なんのことを言っているのかわからなかったので略

パーサ機能

標準ライブラリにパーサライブラリが付いていて、それを手軽に使うべきかどうか、どういうときに使うべきかってこと・・・?

俺はレジスタ割り付けだけ知りたいのでいらないと思う

(本人もわかっていて?)完全に個人的な都合というか、( https://github.com/joshcough/Compilers というソースコードを読む上での )わがままを書いているだけな気がするから、ここは真面目に反応をするところじゃないというか、延々と"パーサとはなにか?"を語ってもあまり意味が気がする。*2いや上記のソースコード中でのパーサライブラリの使い方について(うまく使えているかどうか、使うほどの規模なのか?)については、議論のしようがあるとおもいますが

case classによる、AST表現

(正しく使えば)むしろ短くわかりやすくなるんじゃね?と思うんですが

これもなくても作れるのでないほうが読むソース短くなって

"これなくても作れるので" は極論するとなんでもそうなっちゃうのであれですし、いやしかし case class は(それほど高度なあまり使われてない機能というわけでもなく)普通にどこでもつかわれてるので、この点はあまり同意できません

implicit conversion

new File("a.txt").readとやってファイル読み込めるぜ
っていうことなんですけど、readFile("a.txt")とかいう関数で読み込みでいいよ

これはある程度同意できるというか、このファイルに対してreadという関数を追加する例に限って言えば、implicit conversionを使う必然性はないですね。
(うまい例がだせないというか、説明しだすと長くなるので)implicit conversionそのものに関しては、便利に使える場合もあるので、もちろん必要な機能だとは思いますが。



最後に、タイトルに12って書いてるけど、12個じゃないのは一体・・・どうやって数えれば・・・(´・ω・`)?

*1:っていうかJavaが(ry

*2:そもそもそれほどパーサライブラリに関する知識もない(´・ω・`)