C#にはなぜconstが無いのか?

今更ですがC#を勉強中のC++プログラマーです。
C#にはC++の機能を受け継いだものも少なくないですが、なぜC++のようなconstの機能は受け継がれなかったのでしょうか?
(C#にもconstキーワード自体はあるが機能はかなり限定されている)
特に関数の入力パラメーターには必ずconstを付けるC++プログラマーにとって、constがないと不安になります。
# 実はあまり役立っていなかったのか、使いこなせない人が多かったのか…

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2011/08/25 10:25:02

回答4件)

id:a-kuma3 No.1

回答回数4973ベストアンサー獲得回数2154

C# が java の対抗馬だから、でしょう、きっと。


.NET 自体が、java が持ってる領域を狙ってて、間口を広げるために CLI を使える言語を

いろいろ取り揃えてて、その中で言語としての java を狙ってるのが C# 。

だから、java が切り捨てたものは、C# には無いんです。


.NET で、c++ をやりたい人は、C++/CLI を使ってね、ということなんでしょう。

一応、J# もありますが、C# は、従来 MFC を使ってた人たちを引き込みたいんでしょう。


特に関数の入力パラメーターには必ずconstを付けるC++プログラマーにとって、constがないと不安になります。

これもそうですし、メソッドの const 修飾が無いのも痛いです。

C# の const は、java の final ですもんね。


ぼくも、c++ 歴は、それなりにあるクチなんですが、引数の中身変わってたー、とか、

他のメンバーの値を書き換えてたー、みたいな障害を見るたびに、

「c++ だったらなぁ...」とつぶやいてます。

id:miscellaneousness

C# が java の対抗馬だから

それじゃあ、「Javaにはなぜconstが無いのか?」に変わるだけの気が。

2011/08/18 14:00:29
id:a-kuma3 No.2

回答回数4973ベストアンサー獲得回数2154

それじゃあ、「Javaにはなぜconstが無いのか?」に変わるだけの気が。

ごめんなさい、脳内では回答してたんですが、回答に書いてませんでした (^^;


もともと、java って、c++ へのアンチテーゼとして設計されているじゃないですか。

例えば、それぞれが独立してるわけじゃないですけど、

  • シンプルな構文
  • 言語レベルでのセキュアな仕組み
  • スレッド

などなど。


ポインタや、多重継承、テンプレート、スタックからのメモリ割り当て、プリプロセッサ、ヘッダファイル(宣言と実装の分離)などが、

ばっさり切り捨てられる中に、const も含まれてた、と。

引数だけに限らず、変数宣言での const も、volatile と合わせて、コンパイラの最適化にとって、

重要だと思いますが、「シンプル」の犠牲になってます。


--

(追記)

何か読み物が無いとつまんないですね。

いくつか、関係するところをみつくろいました。

Java#思想 @Wiki

JavaとC++の比較#設計思想 @Wiki

Write once, run anywhere @Wiki


--

(追記)

また、脳内で完了してた。

テンプレートは、ジェネリック型として採用された、ということあるので、

const の一部 (できれば、メソッドの const 修飾) が採用されるかもしれません。


# Oracle 買収前だったらね

id:miscellaneousness

「JavaとC++の比較 - 文法」で若干constに触れていますが、ズバリの解説はなさそうですね。

「シンプル」にするため、

  • あまり役立っていない
  • 使いこなせない人が多い

ので削ったんですかね。

2011/08/18 21:07:00
id:fenstrial No.3

回答回数57ベストアンサー獲得回数14

Anders Hejlsberg(C#設計者)が以下の記事のImmutablesで述べています。

適当に抜粋、翻訳すると、

ミューテーションは、効率化のためキャッシュを持つことを必ずしも否定しない。外部から見た振る舞いが同じであることがミューテーションだ。イミュータブルは便利だが、それは作者がそう言っておけばよい

と言っています。


以下、自分の文章

引数やmethodにconstがあると後からキャッシュを持たせて、効率化をはかるといったことができないといったことが理由のようです。特別に必要ならstringのように変更があるときは新しいオブジェクトを返すなどのようにして実現するようにということなのでしょう。


http://www.artima.com/intv/choicesP.html

id:miscellaneousness

Immutablesの節を読んでみましたが、fenstrialさんとは異なる解釈になりました。(?_?;


コンパイラーで不変性を扱うのは難しいので、取り入れなかった。イミュータブルオブジェクトは便利だが、作者が不変だというだけで良いじゃないか。


C++のconstの意義を否定している感じ。

2011/08/20 19:28:23
id:Jupiter2100 No.4

回答回数444ベストアンサー獲得回数74

質問者への逆質問で申し訳ありませんが、constreadonlyではいけないのでしょうか?

id:miscellaneousness

質問文にも書いたように機能が足らないと思っていますが、C#で以下のようなことはできますか?

class Foo
{
    int m_data;
public:
    void func1() const {
        m_data = 1; // コンパイルエラー
    }
    void func2() {
        m_data = 1; // OK
    }
};

void func1(const Foo &foo)
{
    foo.func1(); // OK
    foo.func2(); // コンパイルエラー
}

void func2(Foo &foo)
{
    foo.func1(); // OK
    foo.func2(); // OK
}

int main()
{
    const Foo foo1;
    func1(foo1); // OK
    func2(foo1); // コンパイルエラー

    Foo foo2;
    func1(foo2); // OK
    func2(foo2); // OK
}
2011/08/21 21:49:20
  • id:taknt
    C#って Delphiを開発した人をひきぬいて その思想を取り入れてるからじゃないのかなーーー?
  • id:tdoi
    C++ではポインタがあるため、値渡しでも関数内で予想外に値の書き換えを行われる恐れがあるため、constを付けることで、それを防ぐ必要があったけれども、C#の思想的にはポインタを使わないので、refを変更を意図した時だけ指定することで対処できるということではないですかね?
    unsafeを指定した場合は自己責任でということでしょうか。
  • id:rsc96074
     こちらはどうでしょう。(^_^;
    http://d.hatena.ne.jp/Horiuchi_H/20060405/1144227687

  • id:miscellaneousness
    >>
    C#の思想的にはポインタを使わないので、refを変更を意図した時だけ指定することで対処できるということではないですかね?
    <<
    値型ではそうですが、参照型ではデフォルトで呼び出された側で変更できますよね。
    参照は実質ポインターなので。
  • id:a-kuma3
    >参照は実質ポインターなので。
    そうだよね、const なポインタが参照だもんね。
    const なインスタンスとか、オブジェクトの状態を変更しないという宣言にあたる const が無いんだよね。
  • id:a-kuma3
    >使いこなせない人が多い
    に、近いんでしょうね。

    元々は、組込系のプロジェクトで c++ を想定してたところに、別の言語を作ろう、と、いうことだったので、
    「役に立たない」とは思ってなかった、と信じます。
  • id:a-kuma3
    >引数やmethodにconstがあると後からキャッシュを持たせて、効率化をはかるといったことができない
    違いますよ。

    コストが高い計算の結果を、オブジェクトの内部にキャッシュしておきたいからこそ、
    メソッドの const 修飾があるんじゃないですか。

    class C {
    private:
      X cache_;
    public:
      X getFoo() const;
    }

    X C::getFoo() const {
      if (cache_ == NULL) {
        // const だから、内部状態を変更してはいけない、ということじゃない
        cache_ = コストが高い計算
      }
      return cache_;
    }

    const C c = new C();
    X x = c.getFoo();


    こういうのが無いと、Flyweight パターンの実装とかを作るときに、すごく不便。


    No.3 のリンク先の内容も、ぼくにはよく分かんない。
    Immutables の最後で、const ついて触れられてるけど、当たり前じゃん、って感じ。
    引数が non-const だったら、それは「そのオブジェクトの状態を変えるぜ」ってことだから、
    const なインスタンスを渡せないのは当たり前。
    なんで、それが全てのものについて、const と non-const なものを用意しなきゃいけないことになるんだか。

    const をうまく使うのは、難しい、とは思いますけどね。
  • id:miscellaneousness
    # なぜか返信欄では表示が切れてしまうのでコメントに転載します。

    質問文にも書いたように機能が足らないと思っていますが、C#で以下のようなことはできますか?

    >|cpp|
    class Foo
    {
    int m_data;
    public:
    void func1() const {
    m_data = 1; // コンパイルエラー
    }
    void func2() {
    m_data = 1; // OK
    }
    };

    void func1(const Foo &foo)
    {
    foo.func1(); // OK
    foo.func2(); // コンパイルエラー
    }

    void func2(Foo &foo)
    {
    foo.func1(); // OK
    foo.func2(); // OK
    }

    int main()
    {
    const Foo foo1;
    func1(foo1); // OK
    func2(foo1); // コンパイルエラー

    Foo foo2;
    func1(foo2); // OK
    func2(foo2); // OK
    }
  • id:a-kuma3
    >void func1() const {
    >  m_data = 1; // コンパイルエラー
    >}
    あれ、これってコンパイルエラーになりましたっけ。
    もう、ずいぶん使ってないので、忘れてしまいました (^^;
  • id:miscellaneousness
    > >void func1() const {
    > >  m_data = 1; // コンパイルエラー
    > >}
    > あれ、これってコンパイルエラーになりましたっけ。

    はい。エラーになります。キャッシュなど敢えてconstメンバー関数から変更できるようにするには、メンバー変数をmutable宣言する必要があります。

    hatena.cpp(6): error C3490: 'm_data' は const オブジェクトを通じてアクセスされているため変更できません
    hatena.cpp(16): error C2662: 'Foo::func2' : 'const Foo' から 'Foo &' へ 'this' ポインターを変換できません。
    hatena.cpp(29): error C2664: 'func2' : 1 番目の引数を 'const Foo' から 'Foo &' に変換できません。
  • id:Jupiter2100
    >質問文にも書いたように機能が足らないと思っていますが、C#で以下のようなことはできますか?
    コメントいただきありがとうございます。

    足りないと機能が「インライン」だとお考えでしょうか?
    C#にはインラインは不要だと思います。
    なぜなら、C#が吐き出すコードは中間コード(MSIL)ですから、高速化のためにCやC++が用意したインラインという仕組みは意味がないからです。
  • id:a-kuma3
    あ、そだそだ、mutable だわ。
    修飾が多いのも c & c++ の分かりにくいところだわな。しかも言語しばりなんだか、環境しばりなんだか、よく分からんような。

    # とか、自己弁護してみる (^^;
  • id:miscellaneousness
    「インライン」?インライン関数のことですか?全然関係ありません。
    C++のconst相当のことをC#でやるには、C#のconst,readonlyでは機能が足りないという話ですよ。
  • id:tdoi
    先のコメントでは、寝ぼけたことを書いてしまいすみません。

    気になったので、ちょっと調べてみましたが、

    http://stackoverflow.com/questions/3826542/c-readonly-const-function-parameters

    こんな風にインターフェースを使ってやるしかないんですかね。
    思想としては、フィールドを変更できるクラスと、できないクラスは別のクラスとして扱うべきだということなのでしょうか。この方法であれば特定のフィールドだけに触れないインターフェースとか柔軟にはできるとは思いますが、冗長だなぁとも思えてしまいますね。
    フィールドを変更する別なメソッドを呼び出す場合なども考慮すると、もう少し面倒な話しになりそうですし。
  • id:miscellaneousness
    読み込み用と書き込み用のインターフェイスを分けるという方法ですか。
    上に書いたC++のプログラムのようなことができるか考えて見ます。
  • id:tdoi
    インターフェースだと、

    void func1() const {
    m_data = 1; // コンパイルエラー
    }

    これに相当することができませんね。抽象クラスで次のようにはできましたが、多重継承ができないのでこの方法が利用できるケースは限定されてしまうかもしれませんね。

    class IReadableFoo
    {
    public int Bar { get; }

    public sealed void Func1()
    {
    // Compile Error:
    // Bar = 1;
    int n = Bar;
    }
    }

    class IWritableFoo : IReadableFoo
    {
    public int Bar { set; }

    public sealed void Func2()
    {
    Bar = 2;
    }
    }

    class Foo : IWritableFoo
    {
    int bar_;

    public int Bar
    {
    get { return bar_; }
    set { bar_ = value; }
    }

    int IReadableFoo.Bar
    {
    get { return Bar; }
    }

    int IWritableFoo.Bar
    {
    set { Bar = value; }
    }

    public Foo()
    {
    bar_ = 0;
    }
    }

    class MainClass
    {
    static void Main(string[] args)
    {
    Foo foo1 = new Foo();
    foo1.Func1();
    foo1.Func2();
    Func1(foo1);
    Func2(foo1);

    IReadableFoo foo2 = new Foo();
    Console.WriteLine(foo2.Bar);
    foo2.Func1();
    Console.WriteLine(foo2.Bar);
    Func1(foo2);
    Console.WriteLine(foo2.Bar);
    // Compile Error:
    // foo2.Func2();
    // Func2(foo2);
    }

    static void Func1(IReadableFoo foo)
    {
    int n = foo.Bar;
    foo.Func1();
    // Compile Error:
    // foo.Bar = 1;
    // foo.Func2();
    }

    static void Func2(Foo foo)
    {
    int n = foo.Bar;
    foo.Bar = 1;
    foo.Func1();
    foo.Func2();
    }
    }

    何かの参考になれば。
  • id:miscellaneousness
    ありがとうございます。参考にします。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません