16

今日の授業では、私の教授が授業の構成方法について話し合っていました。このコースは主にJavaを使用しており、私は教師よりもJavaの経験が豊富です(彼はC ++のバックグラウンドを持っています)。そのため、Javaでは不変性を優先する必要があると述べました。私の教授は私の答えを正当化するように私に頼みました、そして私は私がJavaコミュニティから聞いた理由を与えました:

  1. 安全性(特に糸脱毛の場合)
  2. オブジェクト数の削減
  3. 特定の最適化を許可します(特にガベージコレクターの場合)

教授は、これらの利点の統計的測定値を見たいと言って、私の声明に異議を唱えました。事例証拠を豊富に引用しましたが、それでも彼が正しいことに気づきました。私が知る限り、不変性が実際に実世界のコードで約束する利点を提供するかどうかについての経験的研究はありませんでした。私はそれが経験からそうすることを知っています、しかし他の人の経験は異なるかもしれません。

それで、私の質問は、実世界のコードにおける不変性の影響について行われた統計的研究はありますか?

4

9 に答える 9

5

効果的なJavaの項目15を指します。不変性の価値は設計にあり(常に適切であるとは限りません。これは最初の近似として適切です)、統計的な観点から設計の好みが議論されることはめったにありませんが、可変オブジェクト(Calendar、Date)は本当に悪くなり、深刻な代替品(JodaTime、JSR-310)は不変性を選択しました。

于 2009-09-29T16:00:15.980 に答える
2

私の意見では、Javaの不変性の最大の利点は単純さです。オブジェクトの状態を変更できない場合は、オブジェクトの状態について推論する方がはるかに簡単になります。もちろん、これはマルチスレッド環境ではさらに重要ですが、単純な線形シングルスレッドプログラムでも、物事をはるかに理解しやすくすることができます。

その他の例については、このページを参照してください。

于 2009-09-29T15:29:43.500 に答える
2

それで、私の質問は、実世界のコードにおける不変性の影響について行われた統計的研究はありますか?

私はあなたの教授がただ鈍感であると主張します-必ずしも意図的にまたは悪いことでさえありません。質問が曖昧すぎるというだけです。質問に関する2つの実際の問題:

  • 「[x]の効果に関する統計的研究」は、探している測定の種類を指定しなければ、実際には何の意味もありません。
  • 「実際のコード」は、特定のドメインを指定しない限り、実際には何の意味もありません。実世界のコードには、科学計算、ゲーム開発、ブログエンジン、自動プルーフジェネレーター、ストアドプロシージャ、オペレーティングシステムカーネルなどが含まれます。

その価値については、コンパイラが不変オブジェクトを最適化する機能が十分に文書化されています。頭のてっぺんから:

  • Haskellコンパイラは森林破壊(ショートカットフュージョンとも呼ばれます)を実行し、Haskellは式map f . map gをに変換しmap f . gます。Haskell関数は不変であるため、これらの式は同等の出力を生成することが保証されていますが、中間リストを作成する必要がないため、2番目の関数は2倍の速度で実行されます。
  • 変換できる一般的な部分式除去は、コンパイラーが純粋関数であることを保証できる場合x = foo(12); y = foo(12)temp = foo(12); x = temp; y = temp;のみ可能です。foo私の知る限り、Dコンパイラはpureandimmutableキーワードを使用してこのような置換を実行できます。私の記憶が正しければ、一部のCおよびC ++コンパイラは、「純粋」(または同等のキーワード)とマークされたこれらの関数への呼び出しを積極的に最適化します。
  • 可変状態がない限り、十分にスマートなコンパイラーは、コードの線形ブロックを複数のスレッドで実行でき、別のスレッドの変数の状態が破損しないことが保証されます。

並行性に関しては、可変状態を使用する並行性の落とし穴は十分に文書化されており、言い換える必要はありません。


確かに、これはすべて事例証拠ですが、それはあなたが得るであろうほとんど最高のものです。不変対可変の議論は主に小便の一致であり、「関数型プログラミングは命令型プログラミングよりも優れている」のような抜本的な一般化を行っている論文を見つけることはできません。

せいぜい、体系化された調査や統計としてではなく、一連のベストプラクティスで不変と可変の利点を要約できることがわかるでしょう。たとえば、可変状態はマルチスレッドプログラミングの敵です。一方、可変のキューと配列は、不変のバリアントよりも記述が簡単で、実際には効率的です。

練習は必要ですが、最終的には、お気に入りのペットのパラダイムをプロジェクトに組み込むのではなく、仕事に適したツールを使用する方法を学びます。

于 2009-09-29T20:02:40.500 に答える
1

私はあなたの教授が過度に頑固であると思います(おそらく意図的に、あなたをより完全な理解に追いやるために)。実際、不変性の利点は、コンパイラーが最適化でできることではありませんが、実際には、人間が読んで理解するのがはるかに簡単です。オブジェクトの作成時に設定されることが保証され、後で変更されないことが保証されている変数は、現在この値であるが後で他の値に設定される可能性がある変数よりも、簡単に理解して推論できます。

これは特にスレッド化に当てはまります。言語がそのような変更が発生しないことが保証されている場合、プロセッサのキャッシュとモニター、および同時変更の回避に伴うすべての定型文について心配する必要はありません。

そして、不変性の利点を「コードがわかりやすい」と表現すると、「わかりやすい」と比較して、生産性の向上の経験的測定を求めるのは少しばかげていると感じます。

一方、コンパイラとホットスポットは、値が決して変更されないことを知っていることに基づいて、おそらく特定の最適化を実行できます-あなたのように、これは行われ、良いことだと感じていますが、詳細はわかりません。発生する可能性のある最適化のタイプ、および結果のコードがどれだけ高速であるかについての経験的データが存在する可能性がはるかに高くなります。

于 2009-09-29T15:27:21.793 に答える
1
  • 教授と議論しないでください。得るものは何もありません。
  • これらは、動的型と静的型のような未解決の質問です。さまざまな理由から、不変データを含む機能的な手法の方が優れていると考えることがありますが、これまでのところ、ほとんどの場合、スタイルの問題です。
于 2009-09-29T15:29:23.797 に答える
1

客観的に何を測定しますか?GCとオブジェクト数は、同じプログラムの可変/不変バージョンで測定できます(ただし、それは主観的なものであるため、これはかなり弱い議論です)。不変性を追加することで修正された断続的な問題に悩まされている実稼働アプリケーションの実際の例と比較する場合を除いて、スレッドのバグの除去をどのように測定できるか想像できません。

于 2009-09-29T15:35:12.620 に答える
0

不変性は値オブジェクトにとって良いことです。しかし、他のものはどうですか?統計を作成するオブジェクトを想像してみてください。

Stats s = new Stats ();

... some loop ...
     s.count ();

s.end ();
s.print ();

「Processed536.21rows/s」と表示されます。count()不変でどのように実装する予定ですか?カウンター自体に不変の値オブジェクトを使用する場合でも、sそれ自体の内部のカウンターオブジェクトを置き換える必要があるため、不変にすることはできません。唯一の方法は次のとおりです。

     s = s.count ();

sこれは、ループ内のすべてのラウンドの状態をコピーすることを意味します。これは可能ですが、内部カウンターをインクリメントするほど効率的ではないことは確かです。

count()さらに、ほとんどの人は、新しいオブジェクトを返すのではなく、オブジェクトの状態を変更することを期待しているため、このAPIを正しく使用できません。したがって、この場合、さらに多くのバグが発生します。

于 2009-09-29T15:35:22.497 に答える
0

他のコメントが主張しているように、不変オブジェクトのメリットに関する統計を収集することは非常に困難です。なぜなら、コントロールケースを見つけることは事実上不可能だからです。つまり、不変を使用することを除いて、あらゆる点で類似しているソフトウェアアプリケーションのペアです。オブジェクトと他はしません。(ほとんどの場合、そのソフトウェアの1つのバージョンが次々と作成され、最初から多くの教訓を学んだと私は主張します。したがって、パフォーマンスの向上には多くの原因があります。)これについて考える経験豊富なプログラマー少しの間、これを実現する必要があります。あなたの教授はあなたの提案をそらそうとしていると思います。

一方、少なくともJavaでは、おそらくC#やその他のオブジェクト指向言語では、不変性を支持する説得力のある議論を行うのは非常に簡単です。Yishaiが述べているように、EffectiveJavaはこの議論をうまく行っています。私の本棚に置かれているJavaConcurrencyinPracticeコピーもそうです。

于 2009-09-29T16:04:17.750 に答える
0

不変オブジェクトを使用すると、参照を共有することでオブジェクトのを共有するコードが可能になります。ただし、可変オブジェクトには、参照を共有することによってオブジェクトのIDを共有したいコードのIDがあります。ほとんどのアプリケーションでは、両方の種類の共有が不可欠です。使用可能な不変オブジェクトがない場合は、新しいオブジェクトまたはそれらの値の目的の受信者によって提供されたオブジェクトに値をコピーすることで、値を共有できます。可変オブジェクトなしで取得するのははるかに困難です。stateOfUniverse = stateOfUniverse.withSomeChange(...)と言うことで、可変オブジェクトをいくらか「偽造」することができますがstateOfUniversewithSomeChangeメソッドが実行されています[あらゆる種類のマルチスレッドを排除します]。さらに、たとえばトラックのフリートを追跡しようとしていて、コードの一部が特定のトラックに関心がある場合、そのコードは、変更された可能性があるときはいつでも、トラックのテーブルでそのトラックを常に検索する必要があります。 。

より良いアプローチは、宇宙をエンティティと値に細分化することです。エンティティは変更可能な特性を持ちますが、アイデンティティは不変であるため、たとえばタイプの保管場所はTruck、トラック自体が位置を変更したり、貨物を積み降ろししたりする場合でも、同じトラックを識別し続けることができます。しかし、不変の特性を持っているでしょう。ATruckは、その場所をタイプとして保存する場合がありますWorldCoordinate。45.6789012N 98.7654321Wを表すAWorldCoordinateは、それへの参照が存在する限り継続します。その場所にあったトラックがわずかに北に移動した場合、WorldCoordinate45.6789013N 98.7654321Wを表す新しいトラックが作成され、古いトラックは破棄され、その新しいトラックへの参照が保存されます。

すべてが不変の値または不変のIDのいずれかをカプセル化し、不変のIDを持つはずのものが変更可能である場合、コードについて推論するのが一般的に最も簡単です。変数の外部で可変オブジェクトを使用したくない場合stateOfUniverse、トラックの位置を更新するには、次のようなものが必要になります。

ImmutableMapping<int,Truck> trucks = stateOfUniverse.getTrucks();
Truck myTruck = trucks.get(myTruckId);
myTruck = myTruck.withLocation(newLocation);
trucks = trucks.withItem(myTruckId,myTruck);
stateOfUniverse = stateOfUniverse.withTrucks(trucks);

しかし、そのコードについて推論することは、次の場合よりも難しいでしょう。

myTruck.setLocation(newLocation);
于 2013-12-26T17:22:18.560 に答える