C ++のようなconstを言語に組み込む際の問題は何ですか?


17

私はC ++のようなconst特定の実行ではなく(キャストアウトのようなconst)のアイデアに興味があります。

たとえば、C#を考えてみましょう。C++のようなconstがなく、その理由は通常の人と時間です。さらに、C#チームはC ++の実行を見て、constCLRをマーケティングし、この時点で十分でした(c#およびconstパラメーターにconstメンバーメソッドがない理由を参照してください;ありがとうSvick)。ことがあれば、我々はさらにそれよりも移動し、何かありますか?

もっと深いものはありますか?例えば、多重継承を考えてみてください-通常、(ユーザーにとって)把握するのは難しいと見られているため、言語に追加されません(ダイヤモンドの問題のように)。

言語にそれを避ける方が良いという問題を引き起こす自然の何かがありconstますか?const深さを浅くするか浅くするかを決定するようなものです(constコンテナがあるため、新しい要素を追加したり、既存の要素を変更したりできません。要素が参照型の場合はどうなりますか)。

更新:私はC#について言及しているため、歴史的な観点constから、言語の潜在的な問題の性質に興味があります。

これは言語の挑戦ではありません。現在の傾向や人気などの要因を無視してください-私は技術的な問題にのみ興味があります-ありがとうございます。


3
余談として:多重継承を把握するのは難しくないかもしれませんが、メソッドの解決は非常にquiteくなることがあります。素朴な深さ優先の解像度はすぐに直感的ではなくなります(「ダイヤモンドの問題」)。C3メソッド解決順序('96を発表したが)、これを解決するが、確かにありません理解しやすいです。したがって、多重継承を違法にすることはしばしば非常に賢明に思えるかもしれませんが、実際の問題は、JavaがC3アルゴリズムよりも前であり、C#がJavaを指向していることです。
アモン14年

3
@amon Dプログラミング言語の作成者など、そもそも多重継承が必要な機能だとは思わない人が多いです。これは議論の余地のある価値のある複雑な機能です。効率的な方法で実装することは非常に困難であり、コンパイラはそれを実装する際に多くのバグを起こしやすいです。MIのほとんどすべての値は、インターフェイスと集約を組み合わせた単一の継承で処理できます。残っていることは、MI実装の重みを正当化するものではありません。 (ソース)
jcora 14年


2
さえせずに多重継承、次のことができ、すでにので、それはNP完全作り、C#でのメソッド解決(またはより正確に過負荷解像度)などの任意の3-SAT問題をエンコードします。
ヨルグWミットタグ14年

1
@svick、どうもありがとう。この質問に対する答えがなかったので、歴史的な理由ではなく問題の性質に集中するために、99%が「時間+人+反C ++バイアス」であるように、それを大幅に編集する自由を取りました。 + CLR」。
greenoldman 14年

回答:


10

これが適切かどうかを確認してください。ただし、標準MLのような関数型言語では、すべてがデフォルトで不変です。突然変異は、一般的なrefエレンスタイプによってサポートされます。したがって、int変数は不変であり、ref int変数はintsの可変コンテナーです。基本的に、変数は数学的な意味での実際の変数(未知ではあるが固定値)であり、refsは命令型プログラミングの意味での「変数」です-読み書き可能なメモリセルです。(私はそれらをassignablesと呼ぶのが好きです。)

問題constは2つあると思います。まず、C ++にはガベージコレクションがありません。これは、重要な永続データ構造を持つために必要です。意味をなすためには深くconst なければなりませんが、C ++で完全に不変の値を持つことは実用的ではありません。

次に、C ++ constでは、オプトアウトするのではなくオプトインする必要があります。しかし、const何かを忘れて後で修正すると、@ RobYの回答で言及されている「const poisoning」状況に陥りconst、コード全体に変更がカスケードされます。場合はconstデフォルトだった、あなたは適用自分自身を見つけることができませんでしょうconst遡及。さらに、constどこにでも追加する必要があるため、コードに多くのノイズが追加されます。

後に続いた主流言語(Javaなど)は、CとC ++の成功と考え方によって大きく形作られたのではないかと思います。適切な例として、ガベージコレクションを使用しても、ほとんどの言語のコレクションAPIは可変データ構造を想定しています。すべてが可変で不変であるという事実は、一例として一般的な言語の背後にある命令的な考え方について多くを語っています。

編集greenoldmanのコメントを反映した後const、データの不変性に関するものではないことに気付きました。constインスタンスに副作用があるかどうかをメソッドの型にエンコードします。

参照透過動作を実現するために突然変異を使用することは可能です。連続して呼び出されたときに異なる値を返す関数があるとします。たとえば、から単一の文字を読み取る関数などですstdin。この関数の結果をキャッシュ/メモ化して、参照的に透過的な値のストリームを生成できます。ストリームはリンクされたリストになり、ノードは値を最初に取得しようとしたときに関数を呼び出しますが、結果をキャッシュします。あればstdinconstains Hello, world!、あなたが最初のノードの値を取得しようとする最初の時間は、それが1を読んであげるcharと返しますH。その後H、aを読むためのさらなる呼び出しなしで戻り続けますchar。同様に、第2のノードは、読んでいましたcharからstdin最初にその値を取得しようとすると、今回はeその結果を返し、キャッシュします。

ここで興味深いのは、本質的にステートフルなプロセスを、ステートレスに見えるオブジェクトに変えたことです。ただし、これを実現するには、オブジェクトの内部状態を(結果をキャッシュすることによって)変更する必要がありました。この変更は良性の効果でした。CharStream constストリーム不変の値のように動作する場合でも、作成することはできません。ここでStreamconstメソッドを備えたインターフェースがあり、すべての関数がを期待してconst Streamsいると想像してください。あなたは、CharStreamインターフェイスを実装することはできません!

EDIT 2:どうやらキーワードと呼ばれるC ++がありますmutableことを、私たちは、カンニングやメイクできるようになるCharStream constしかし、この抜け穴を破棄します。constの保証は-今、あなたは本当に何かがのmutateそのを通じてません確認することはできませんconst方法私はそれがあることではないと仮定します。あなたは明示的に抜け穴を要求しなければならないので悪いですが、あなたはまだ名誉制度に完全に依存しています)

次に、高階関数があると仮定します。つまり、関数を引数として他の関数に渡すことができます。constnessは関数のシグネチャの一部であるためconst、関数を期待するconst関数の引数として非関数を渡すことはできません。constここで盲目的に強制すると、一般性が失われます。

最後に、constオブジェクトを操作しても、背後にある外部(静的またはグローバル)状態が変化しconstないことは保証されません。

副作用の有無を型システムにエンコードすることが普遍的に良いことであることは私には明らかではありません。


1
+1ありがとう。不変オブジェクトは、C ++ const以外のものです(より多くのビューです)。しかし、C ++にはデフォルトでconstがありvar、オンデマンドでは1つの問題しか残らない、と言うのは深さですか?
greenoldman 14年

1
@greenoldman良い点。C ++を使用してからしばらく経ちましたのでconst、非constオブジェクトへの参照があることを忘れていました。それでも、私は浅いを持つことは意味をなさないと信じていますconst。全体のポイントconstは、その参照を介してオブジェクトを変更できないことの保証です。constconst参照を作成して回避することは許可されていませんがconst、オブジェクトのメンバーを変更して回避するのはなぜですか?
ドーバル14年

+1 :-)更新で非常に興味深い問題(非/定数ラムダでの生活と、おそらく外部状態でのより弱い問題)、私はそれをより長く消化しなければなりません。とにかく、あなたのコメントに関しては、私は何も悪いことを心に留めていません-まったく逆に、コードの明快さを高めるための機能を探しています(もう1つ:非NULLポインター)。ここに同じカテゴリ(少なくとも私の目的です)を定義します。func foo(const String &s)これはsで変更されないシグナルfooです。
greenoldman 14年

1
@greenoldman私は間違いなく魅力と根拠を見ることができます。しかし、私は可能な限り変更可能な状態を回避以外の問題の真の解決策ないと思う(のような他の厄介なものと一緒にnull、継承が。)
Doval

8

主な問題は、プログラマーが十分に使用しない傾向があるため、必要な場所にアクセスしたり、メンテナーが後でconst-correctnessを修正したい場合、大きな波及効果が発生することです。それでも、完全に優れた不変コードを記述することはできconstますが、コンパイラーはそれを強制せず、最適化するのがより困難になります。一部の人々は彼らのコンパイラが彼らを助けないことを好みます。私はそれらの人々を理解していませんが、それらの多くがあります。

関数型言語ではconst、ほとんどすべてがであり、許可されている場合、可変であることはまれな例外です。これには、並行状態の容易さや共有状態に関する推論の容易さなど、いくつかの利点がありますが、可変カルチャの言語から来ている場合は慣れる必要があります。言いかえれば、欲しくないということconstは人的な問題であり、技術的な問題ではありません。


+1ありがとう。不変オブジェクトは私が探しているもの以外のものです(C#またはJavaでオブジェクトを不変にすることができます)、不変のアプローチであっても、それが深いか浅いかを決定する必要があります、例えばポインタ/参照のコンテナを取ります指すオブジェクトの値を変更します)。1日後、主な問題はむしろデフォルトとして設定されているものであり、新しい言語を設計するときに簡単に解決できるようです。
greenoldman

1
lolzの+1 @「一部の人々は、コンパイラが彼らを助けないことを好む。私はそれらの人々を理解していないが、多くの人々がいる」。
トーマスエディング14年

6

欠点は次のとおりです。

  • 「const poisoning」は、constの1つの宣言が前または後の宣言でconstを使用することを強制できる場合の問題であり、その結果、前の後続の宣言でconstが使用される場合があります。あなたがコントロールできないと、悪い場所で立ち往生する可能性があります。

  • それは絶対的な保証ではありません。通常、constは参照のみを保護しますが、何らかの理由で基になる値を保護できない場合があります。Cでも、constが到達できないエッジケースがあり、constが提供する約束を弱めます。

  • 一般的に、業界のセンチメントは強力なコンパイル時の保証から遠ざかっているように見えますが、どれほどの快適さがあなたと私をもたらすかもしれません。完璧に機能し、十分に設計され、十分にテストされ、完全に機能する10個のPythonモジュールを打ち出しました。そして、彼はそれをやったときでもハッキングしていませんでした。

おそらく、疑問は、なぜあなたはあなたの気の利いた新しい言語を採用しようとしているのかについて、一部の専門家でさえあいまいな、物議を醸す可能性のある機能を繰り越すのでしょうか?

編集:簡単な答え、新しい言語は、採用のために登る急な丘を持っています。設計者は、採用するために必要な機能について真剣に考える必要があります。たとえば、Goを使用します。グーグルは、コナン・ザ・バーバリアンスタイルのデザインを選択することで、最も深い宗教上の戦いのいくつかを残酷に切り詰めました。


2
2番目の箇条書きは正しくありません。C ++には、参照/ポインタwrtを宣言する3つまたは4つの方法があります。constness:int *可変値へのint const *可変ポインター、const値int * constへの可変ポインター、可変値へのint const * constconstポインター、const値へのconstポインター。
フレネル14年

ありがとうございました。私はマーケティングについてではなく、性質について尋ねました(「業界の移転」はC ++のような性質ではありませんconst)。const中毒について-例を挙げていただけますか?私の知る限りそれが利点なので、あなたは何かを渡しconst、それが残っているべきですconst
greenoldman 14年

1
それはconst問題ではありませんが、型を実際に変更します-あなたが何をするにしても、それは常に問題になります。合格を検討してRichStringから、より良い合格を実現してくださいString
greenoldman 14年

4
@RobY:後者前者で何/誰に対処しているのかわかりません。ただし、その午後、コードを調べた後は、トップダウンではなく、ボトムアップ、つまり最も内側のユニットから始めて、const-correctnessにリファクタリングする必要があることを学習しているはずです。ユニットも十分に隔離されておらず、その代わりに密結合されているか、内部システムの餌食になっている可能性があります。
フレネル14年

7
「Const poisoning」は実際には問題ではありません-実際の問題は、C ++がデフォルトでnon-になっていることconstです。constあるべきではないことをするのは簡単すぎるconst
ドーバル14年

0

const言語への追加には、いくつかの哲学的な問題があります。constクラスに宣言する場合、クラスは変更できません。ただし、クラスとは、メソッド(またはミューテーター)と組み合わされた変数のセットです。クラスの状態を一連のメソッドの背後に隠すことで抽象化を実現します。クラスが状態を隠すように設計されている場合、外部からその状態を変更するミューテーターが必要になりますが、それはconstもうありません。したがって、const不変のクラスに対してのみ宣言できます。だから、constクラス(またはあなたが宣言したいタイプはシナリオでのみ可能思えるconst)些細です...

constとにかく必要ですか?そうは思わない。const良いデザインがあれば簡単にできると思います。必要なデータと場所、I / O、ネットワーク、ビューなどに必要なデータとデータのメソッド、抽象化が必要なメソッド。次に、状態を処理するモジュールとクラスが自然に分割され、メソッドと状態を必要としない不変のクラス。

ほとんどの問題は、それ自体を保存、変換、描画できる大きな太ったデータオブジェクトで発生するので、たとえばレンダラーに渡したいと思います。したがって、データの内容をコピーすることはできません。大きなデータオブジェクトにはコストがかかりすぎるためです。しかし、どちらも変更したくないので、あなたがconst思うようなものが必要です。コンパイラに設計上の欠陥を見つけさせます。ただし、これらのオブジェクトを不変のデータオブジェクトのみに分割し、責任のあるモジュールにメソッドを実装する場合、ポインターを渡す(のみ)ことができ、不変性を保証しながらデータでやりたいことができます。

C ++ではconst、ミューテーターであるため、一部のメソッドを宣言し、他のメソッドで宣言しないことは可能です。そして、しばらくしてからキャッシュが必要になり、ゲッターが(遅延読み込みのため)オブジェクトを変更し、それはconstもうありません。しかし、それがこの抽象化の要点でしたね。各呼び出しでどの状態が変化するかわかりません。


1
「だから、constはクラス(またはconstを宣言したい型)が自明なシナリオでのみ可能だ...」永続的なデータ構造は不変であり、自明ではありません。それらのほとんどすべてが複数のインスタンス間で内部データを共有しているため、C ++では表示されません。C++には、そのためのガベージコレクションがありません。「良いデザインがあれば、constなしでも簡単にできると思います。」不変の値を使用すると、コードの推論がはるかに簡単になります。
ドーバル14年

+1ありがとう。「const to a class」を明確にしてください。クラスをconstに設定するつもりでしたか?はい、私はこれについて尋ねていません-C ++ constはビューのように機能します。クラスではなくオブジェクトの隣にconstを宣言できます(またはC ++ 11で変更されたもの)。また、次の段落と「簡単に」という言葉に問題があります-C#のC ++-constについての良い質問があり、それに伴う作業量が最重要です-配置しようとするすべてのタイプに対してconst(C ++の意味で)すべてのプロパティについても、インターフェイスを定義する必要があります。
greenoldman 14年

1
「クラス」について話しているとき、実際には「クラスのインスタンス」を意味しますよね?それは重要な違いだと思います。
svick 14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.