Closures / Lambdas /…に対するC#、Java、Scalaのアプローチのメリットとデメリットは何ですか?


30

Project Lambda(JSR 335)のメーリングリストに送信されたBrian Goetzの電子メールPeek Past lambdaで表明された実装のアイデアと懸念と、C#とScalaの技術的な実装の違いは何ですか?

メールから:

「たぶんラムダは単に内部クラスのインスタンスであるべきで、それは本当にシンプルだろう」という道を探りましたが、最終的には「関数は言語の未来にとってより良い方向である」という立場になりました。

そしてさらに:

世界のオブジェクトであるラムダは、この将来の可能性と矛盾しています。ラムダは関数の世界観ではありません。この柔軟性を維持することは、ラムダにオブジェクト性の外観でさえ負荷をかけないことを支持するポイントの1つです。

結論:

Lambdas-are-functionsはドアを開きます。Lambdas-are-objectsはそれらを閉じます。
これらのドアが開いたままになるのを好む。

また、Redditスレッドユーザーからのコメントは次のとおりです。

私は実際にこれについてNeal Gafterにメールしました。彼の説明についての私の限られた理解では、C#と現在のJavaデザインは、デリゲートは実際にはオブジェクトであり、関数型ではありません。JavaはC#のラムダの短所から学び、それらを避けるべきだと彼は信じているようです(C#がJavaの短所から学び、最初にそれらを避けたように)。

「Lambdas-are-functions」アプローチが「Lambdas-are-objects」よりも多くの機会を将来可能にするのはなぜですか?誰かがどのような違いが存在し、それらがコードの記述方法にどのように影響するかを説明できますか?

Scalaの物事が「うまくいく」ことを見て、C#/ Java(8)で採用/提案されているアプローチについて何かが欠けていると考え続けています。


1
これは面白い。Java型システムには現在のところ関数の概念がないため、これを最初に導入する必要があります。これにより、言語が複雑になりすぎる可能性があります。
インゴ

関数は何らかのインターフェイスのインスタンスではありませんか?それらの何がそんなに特別なのですか?
-soc

Lisp / Scheme / Clojureはオブジェクトをモデル化できますが、Java / C#は関数の任意のネストをモデル化できません。ただし、Pythonは両方の長所を備えているようです。
ジョブ

回答:


15

オブジェクトと関数に関する議論は、赤いニシンだと思います。質問が「ラムダは関数ですか、それともオブジェクトですか?」答えはイエスです。

それがファーストクラスの機能のポイントです。それらは他のどのタイプとも異なって扱われません。JavaはすでにObject型とプリミティブ型の違いをほとんど無視しているため(Scalaはさらに優れています)、ラムダがObjectのサブクラスであるか、新しいプリミティブ型であるか、他の何かが言語にとって重要ではありません。重要なのは、ラムダをコレクションに入れ、それらを呼び出して呼び出し、呼び出し、オブジェクトまたはメソッドのいずれかでやりたいことができることです。

Scala applyは、just ()で呼び出せるメソッドが呼び出されたラッパーオブジェクトを使用してこれを実現し、メソッド呼び出しのように見せます。これは見事に機能します。ほとんどの場合、メソッドを持っているか、関数オブジェクトの適用を呼び出しているかを気にする必要さえありません。


9

私が理解から、それはラムダがされている方法の詳細だと考え主要言語レベルで。メールが言うように、

現在の設計はラムダ(SAMタイプ)のオブジェクトボックスと密接に結びついていると思われるかもしれませんが、とにかく効果的にオブジェクトを作成します。しかし、これは将来的に「裸の」ラムダを検討したり、ラムダの他の変換コンテキストを検討したり、ラムダを制御構造にさらに緊密に統合したりできるように、表面から慎重に隠されています。私たちは今それをやっていませんし、そうするための具体的な計画すらありませんが、将来それを可能にする可能性はデザインの重要な部分です。

私はあなたの質問を非常にうまくまとめていると思います。「ラムダはオブジェクト」であると宣言した場合、それらは特定のクラスのオブジェクトに過ぎず、それだけに固執します。一方、「ラムダは関数」と宣言すると、意味的にはるかに豊かな競技場が得られます。Java 1.7はそれらをオブジェクトにコンパイルするかもしれないので、その時点では実質的に同一です。

ただし、Java 1.8または1.9は、関数をより柔軟な方法で使用できるようにするよりも、言語に変更(構造化された構造型など)をもたらす可能性があります。「ラムダがオブジェクト」だった場合、これらの変更には後方互換性がなく、人々の既存のコードを壊さないように、新しいコンセプトを完全に導入する必要があります。しかし、javacラムダを静かに背後のオブジェクトに変換するだけであればjavac、セマンティクスが保持されている限り、新しいものは必要なものに変換できます。


C#のラムダ!=デリゲートから。コンパイラには、それらをデルゲートまたは式ツリーにコンパイルするオプションがあります。どちらも実際にはオブジェクトグラフですが「特定のクラス」にも特定の継承ツリーのクラスにもコンパイルされていません
ルーンFS

私が正しく理解していれば、ラムダをコンパイルしてオブジェクトの内部クラスに関連付け、そのオブジェクトに関連付けます内部クラスの実装を使用できず、不整合が発生します。Javaがすぐに高階関数を持つとは思わない。
mwolfetech

@mwolfetech:私の知る限り、それらはすでにディフェンダーメソッドを備えたJava 8で計画されています。彼らはのようなものを追加したいforeachmapfilterコレクションに。
-soc

@soc良い点です。JSRの数に対応するのが難しく、JSRが実際に完了してJDKのターゲットバージョンを作成するかどうか。ディフェンダーメソッドは同じJSRの一部であるように見えます。このJSRに関しては、Brian GoetzのState of the Lambda投稿が役立つことがわかりました。SAMタイプとラムダ式を実装するための現在の考えを説明しています。
mwolfetech

「現在の考え」mhhh、2010年の投稿は今では時代遅れではないでしょうか。
-soc

5

ほとんどの場合、彼は何かにあまりにも早くコミットしたくないだけです。彼が提示した消去以外の理由はわかりませんが、それは確かに非常に強力な理由です。

私は関数型が好きではありません-私は関数型が大好きです-しかし、その関数型はJava型システムの既存の側面である消去とひどく戦いました。消去された関数タイプは、両方の世界で最悪です。

Scalaのこれらのメソッドを検討してくださいRegex

def replaceAllIn (target: CharSequence, replacer: (Match)  String): String
def replaceSomeIn (target: CharSequence, replacer: (Match)  Option[String]): String

単純に次のようにすれば、より簡単になります。

def replace (target: CharSequence, replacer: (Match)  String): String
def replace (target: CharSequence, replacer: (Match)  Option[String]): String

残念ながら、これらの2つの機能消去下では同一であるため、それは不可能です。しかし、これらの関数はやや異なることを行うので、別の名前でも十分です。

ただし、a Matchは非常に便利なものですが、ほとんどの場合String、サブグループの一致またはリストのいずれかが必要です。これが欲しいです:

def replaceAllIn (target: CharSequence, replacer: (String)  String): String
def replaceAllIn (target: CharSequence, replacer: (Seq[String])  String): String
def replaceAllIn (target: CharSequence, replacer: (Match)  String): String

消去のため不可能です。この特定の例を選んだ理由は、直接関与していたからですが、Stack Overflowで少なくとも半ダースの質問を見てきました。

そして、その後、ScalaのパターンマッチングとJava instanceofは消去のために事実上役に立たないと考えてください。

この問題が処理されるまで関数型を遅らせるのは公平だと思います。結局のところ、JVMにはそれを備えた言語がたくさんあり、Javaが急速に進化している言語のようではありません。


まあ、タイプ消去が唯一の問題である場合、彼らは何をするつもりですか?この地球上のすべてのコード...すでにJava 5のための非オプションを支配された速報
SOC

@soc私は彼らの靴の中にいないのでとてもうれしいです!しかし、それはSunであり、これはOracleです。オラクルは、主要製品のメジャーバージョンとマイナーバージョンとの間で重大な変更を行うことに関して、いかなる責任も負いませんでした。
ダニエルC.ソブラル

言語の名前を変更して新しい言語の開発を開始し、下位互換性を落とす必要があるかもしれません。したがって、古い言語や確立された言語をいじる必要なく、新しい言語の利点を得ることができます。結局のところ、これはScalaとClojureが行ったことです。
ジョルジオ

@Giorgioそれは少し無意味です。さて、今日のJavaの責任者はそれをしましたが、あなたが言ったように、代替手段があります。しかし、Javaの責任者はJava自体を改善する必要があります。結局、彼らはJavaに責任があります。唯一の選択肢は、単にJavaをドロップし、それを制御することから生じるすべての利点を放棄することです。
ダニエルC.ソブラル

@ダニエル・C・ソブラル:IMOプログラミング言語は、ソフトウェアのようなものです。最初は、クリーンで適切に設計できますが、それを使用するほど、面倒になります。したがって、Javaを言語として凍結し、(1)新しいライブラリの作成または既存のライブラリの改善、(2)JVMの改善(可能な場合)、(3)新しい言語の開発に開発を集中することが開発者の利益になると思います。しかし、あなたが言ったように、Javaに責任を持ち、アップグレードの販売を続けたい人がいます。したがって、彼らはそれを「クール」に保つために拡張します。ちょうど私の2セント。
ジョルジオ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.