saruboの書き溜め

いいこと書けないですけどこんな記事でよければ見ていってね

Scala の初学者が見る文書で `Seq()` を使わないで欲しい派の主張

注意

ポエム、あるいは思想です。 私が完全に正しいとは思っていません。 そして、私は未だに Seq("foo", "bar", "baz") がどのようにして実体を List[String] として持っているのか理解していません。 という前提で話をグダグダしていきます。

主張

そんなに Seq が使いたいなら、こうすればいいのに!

val seq: Seq[String] = List("foo", "bar", "baz")

検索して見かけるもの

Scalaの記事でたまに見かけるものに

val seq = Seq("foo", "bar", "baz")

のようなものがあると思います。

あなたは初学者なので Seq が何か調べてみることもあるでしょう。 では、公式ドキュメントをあたりましょう。 次のうちのどれかか、全てを参照しました。

ここで驚くべきことに気付きます。 Seq は、なんと trait あるいは object なのです。 あなたはざっくりと、 trait がいわゆる interface のように使われると聞いていたのに、 interface をコンストラクタのように使っているのを見かけてしまったのです。 object は何かそういうことが出来るのかも知れませんが、しかし、 class Doginterface Animal を実装した何かであるとしたら、 interface AnimalAnimal である「何か」を作っているように見えるのです。 めちゃくちゃです。

さて、この疑問にあなたはさらに調べを進めていくこともあるでしょう。 object の方を読んでいたら

This object provides a set of operations to create Seq values. The current default implementation of a Seq is a List.

という記述を見つけるかも知れませんし、コマンドライン

$ scala

と叩いて、REPLを立ち上げ、次のように Seq の実体がどうなっているか調べるかも知れません。

scala> Seq("foo", "bar", "baz")
val res0: Seq[String] = List("foo", "bar", "baz")

あるいは

で同様の記述を見つけるかも知れません。

ともあれ、 SeqList であるようでした。 List について確認してみましょう。

Listclass です。 Seq の実体の正体に辿り着きました。

extends, with あたりを追って行けば、 ListSeq の関係が分かりますし、

の図を見ても関係性は直ぐに分かるでしょう。

いやいや、interface AnimalAnimal である「何か」を作っているように見えるのは変わらないじゃないですか!

思うこと

val seq = Seq("foo", "bar", "baz")

初学者には厳しい

  • なぜ「 Seq のコンストラクタで呼び出した実体がデフォルト実装で List である」という 暗黙知 を前提に記事を読まねばならないのか?
    • 初学者でなかったとしても Library のデフォルト実装を知っていようというのは筋肉な思想では?
  • trait ってそのまま実体として呼び出せるのか?」と誤解させ得る example code は良くはないでしょう?

この感覚を持って欲しいのです。

さらに面白いことをしてみましょう。 厳密には違うでしょうが、 Seq()Seq.apply() と同じであると聞いたことにしましょう。 REPLで遊んでみると?

scala> Seq.apply
-- [E178] Type Error: ----------------------------------------------------------
1 |Seq.apply
  |^^^^^^^^^
  |missing argument list for method apply in class Delegate
  |
  |  override def apply[A](elems: A*): CC[A]
  |
  | longer explanation available when compiling with `-explain`
1 error found

なんと class Delegate であると言うのです。もう分かんないですね。

そんなに Seq が使いたいなら、次のようにすれば、少し冗長ですが、実態に即しており、明確で誰も困らないものと思います。

val seq: Seq[String] = List("foo", "bar", "baz")

Tips

ちなみに以下の様に Seq よりも抽象的な trait でも同じように List が実体となっています。ワオ。

scala> Iterable("foo", "bar", "baz")
val res1: Iterable[String] = List(foo, bar, baz)

scala> Traversable("foo", "bar", "baz")
there was 1 deprecation warning; re-run with -deprecation for details
1 warning found
val res2: Iterable[String] = List(foo, bar, baz)