OMG Scalaは複雑な言語です!

「ああ、聖なる天国、Scalaは難しい!」 おそらく、それは本当です。 この複雑さを見て、Scalaと他のオブジェクト指向言語(JavaやC ++など)の主な違いを見てみましょう。







型推論



ほとんどの場合、コンパイラは型を推測できます。これにより、開発者は、JavaやC ++での記述に慣れているほど少ない重複情報を記述できます。

たとえば、「john」が文字列であることは明らかです。したがって、コンパイラは独自に型を推測でき、型を明示的に指定する必要はありません。 私は簡単に書くことができます:



val aGuy = "John"
      
      





型推論に関する承認と批判の両方に出会ったので、何と言ってもいいのかわかりません。 個人的には、値や変数を宣言するたびに、書く回数を減らし、少し愚かさを感じるのが好きです。



簡素化されたクラス定義



OOPはクラス定義に基づいて構築されるため、Scalaでは可能な限り単純に実装されます。 私のドメインモデルはすべて非常にシンプルです。



 class Person (val firstName:String, val lastName:String)
      
      





JavaまたはC ++で同じことを行うには、あらゆる種類のコンストラクタ、ゲッター、セッターなどを含むコードのページがほとんど必要だと言わなければなりません。 Scala開発者は、愚かなコンパイラーに、姓と名の2つのフィールドを持つPersonクラスが必要であることを伝えるためだけに、コードのページ全体を書くべきではないことに気付きました。 そのため、Scalaでは、このようなクラスの定義は、表がSQLで表示されるように1行だけで済みます。

複雑さを増しますか?

まあ...私は生成されたゲッターとセッターをオーバーライドする必要がある場合にのみ心配する必要があります。 それで、それが本当に人生を複雑にするかどうかさえ知りません...

私?! 個人的に、私はこの機会にとても喜んでいるので、率直に言って、私はあなたがそこに何を考えているかを絶対に気にしません。



メソッドと演算子の組み合わせ



私が知っているすべてのプログラミング言語は、 「append」などの名前のメソッドと「+ = "」のような操作との間に明確な線を引きます 。 一部の言語では、既存の演算子の再定義が禁止されています(Java)。 他の言語では、演算子の挿入記法のみが許可されています(C ++)。 Scalaにはこれらの制限がすべてありません。 任意の名前を使用してメソッドに名前を付けることができ、呼び出しには中置表記法が許可されます。



 ListBuffer(1,2,3) append 4 //     ListBuffer(1,2,3) += 4
      
      





唯一の違いは、優先順位のルールです。 もちろん、JavaやC ++よりも「複雑」であると誰かが言うでしょう。なぜなら、それは「自由な手」であり、あなたがやりたいことができるからです。 しかし、これは言及されている言語よりも簡単だと思います。 最終的に、これによりScalaは自然なDSLを作成するための完璧なフレームワークになります。



 "Mary" with "a purse" and "red shoes" should look "nice"
      
      







種類



JavaとC ++の両方で、テンプレートには特定の有線の制限された動作(つまり共分散 )があり、少数の構成( List <T extends Person>など )のみが許可されます。

Scalaには、 List [Person]が不変であるデフォルトの動作がありますが、すべてをカスタマイズできます。 共分散が必要な場合は、コンパイラのリスト[+ Person]またはリスト[-Person]に反分散を伝えてください。 Javaと同様に、 List [T <:Person]およびList [T>:Person]コンストラクトがあります。 Scalaには暗黙的な変換(暗黙的)のメカニズムがあるため、そのような場合のために、別の構成も使用できます: List [T <%Person]

難しいですか?

演算子と同様に、このメカニズムはいくつかの制限を作成しますが、一方で、新しい機会を提供します。 個人的には、このタイプコントロールが好きです。 これを使用しましたか? 日常の開発ではなく、ほとんどの場合、通常のデフォルトの型制御動作で十分です。



デザイナーだけ?



ほとんどの言語では、オブジェクトの構築のみが許可されています。 Scalaではオブジェクトを分解することもできますが、オブジェクトが占有しているメモリを解放することについては話していません。 考慮してください:



 someone match { case Person(first,last) => println (s" name is $first $last") }
      
      





ここでは、オブジェクトを「分解」することによって私が意味することを見ることができます。 作成済みのオブジェクトを取得し、 最初最後のコンポーネントに分解します。 これはほとんどのオブジェクト指向サポーターにとって異質で珍しいように見えますが、信じられませんが、これはめちゃくちゃクールで快適です! これをJavaまたはC ++で実装するために何をしなければならないか想像してみてください...タイプ(instanceof)を確認し、これらの値に2つの変数を割り当てます...

Scalaの文字列補間を思い出してください:



 "$first $last"
      
      







もっと複雑ですか? まあ...これは完全に新しい機能です。 私はそれが好きです! 私を信じて、あなたもそれを好きになるでしょう!

ちなみに、 match / caseは、定数でのみ機能する通常のswitch / caseよりも幅広い可能性を提供します。 マッチ/ケースを使用すると、オブジェクトの分解、定数の一致、タイプの一致など、さらに多くのことができます! はい、自分で見てください:



 someone match { case Person(first,last) => println (" name is " + first + " " + last) case "John" | "Mary" => println ("hello, " + someone.toString) case s:String => println ("name is " + s) case _ => println ("don't know what this is…") }
      
      





難しいですか? JavaまたはC ++では、1〜2ページのコードが必要です。 個人的には、Scalaではシンプルで直感的に見えます。



おわりに



もちろん、これらは言語の一部にすぎません。 追加するものがある場合は、投稿してください、私は喜んでいます。

Scalaの関数型プログラミングには触れませんでした。これはScalaを他の関数型言語と比較する必要があるためです。これはFP'shnik( FP guy )ではありません。 C ++では、関数ポインターを他の関数に渡すことができるようになり、ラムダコンストラクトがJava 8で導入されました。



これはすべて複雑ですか? まあ...あなたは2つの側面からそれをすべて見ることができます:

はい



いや



どう思う? 私は本当に気にしません。 個人的には、これらの機会に出会えてとてもうれしいです。 これにより、ほんの数行のコードで問題を解決できますが、私の友人はまだこれらのゲッターとセッターを書いています...





Scalaでの6年以上の経験で、私が気に入らなかったことがいくつかあります。 それらのいくつかを次に示します。

  1. コンパイルが遅い。 それほど面倒ではありませんが、それでも他の部分よりもずっと遅いです。
  2. 暗黙的な変換。 私は彼らがこのメカニズムをどのように実装したかを嫌います。 AnyからMyCoolThingへの変換を誤ってインポートする可能性があります。これは、インポートされたブロックで定義されています。
  3. コレクションライブラリ。 ほとんどの人にとって、これはそれほど重要ではありませんが、...これはすべて、私が望むよりもはるかに複雑に見えます。
  4. SBT 常に難しいです。 真剣に、あなたが典型的なSBTの経験を超えて何かをする必要があるなら、あなたはそうです。 非常に多くのさまざまな非自明なDSLがあるため、Googleは必要なことを行う方法を見つけようと夢中になります。 彼らは、JSONのような別個の構文か、SBTで作業するときにコンパイラー/ IDEが理解して支援できる何らかの内部DSLを作成する必要がありました。




PS複雑さに関するより詳細な議論: 単純か複雑か?



All Articles