- PR -

変更しない変数にfinalを付けるべきですか?

投票結果総投票数:69
必須 2 2.90%
望ましい 25 36.23%
場合による 7 10.14%
どっちでもいい 1 1.45%
付けなくていい 28 40.58%
付けないほうがいい 4 5.80%
付けるな 0 0.00%
絶対に付け 2 2.90%
  • 投票は恣意的に行われます。統計的な調査と異なり、投票データの正確性や標本の代表性は保証されません。
  • 投票結果の正当性や公平性について、@ITは一切保証も関与もいたしません。
投稿者投稿内容
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-04-05 13:51
引用:

nagiseさんの書き込み (2007-04-05 13:27) より:
classキーワードへの修飾子immutableを新設し、immutable classは
インスタンス変数が全てfinalである必要がある、といった具合でしょうか。



おっ。思っていた方向に話題が進んだみたいですね。
スルーされてたので寂しかったです。。。

引用:

アノテーション@immutableを用意して、クラス側で状態変更を伴わない
メソッドをマーキングしておけば、immutableとされた変数が
状態変更を伴うメソッドの呼び出しをするのを防げるかもしれませんね。



メソッド単位にすると、C++のconst/mutableのようなことになるので、
クラス単位の方がよさそうに思います。

クラス全体がimmutableであれば、
使う側は個々のメソッドまで考えずに不変であることを利用できます。
immutableなクラスのインスタンス変数がconstではなくfinalだとすれば、
必要ならばmutableな状態を内部クラスなどに持たせればよいわけですし。

immutableなクラスでインスタンス変数の更新を行いたい理由の多くは、
パフォーマンス向上のためのキャッシュなどの目的が多そうに思うので、
そういった実装上の詳細は隠したまま、immutableを維持すべきだと思います。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-04-05 14:19
引用:

かつのりさんの書き込み (2007-04-05 13:48) より:
フィールド自体がfinalでもインスタンスの変更自体は可能なので、
再帰的に・・・となると大変っぽい感じがしますね。


あ〜。なるほど。考えが抜けてました。
class修飾子immutable案だとjava.io.Serializableのようなことになりますね。
こちらは直列化の際に動的にエラーとする方式ですが…
immutable性をコンパイル時で検出したいとなれば難しい感じですね。
# 配列をどう扱うんだ、という話もありますね

アノテーション@immutable案は実現可能かもしれませんね。
不変オブジェクトを作成する側が責任を持ってメソッドをマークしないと
いけないという難点はあるのですが、逆に言えば機械処理をあきらめることで
実現させる際の難易度を落としているのですよ。

余裕があれば実装を試みてみたいネタですね。
あぶぽん
大ベテラン
会議室デビュー日: 2005/10/20
投稿数: 205
投稿日時: 2007-04-05 14:22
あしゅさん、皆さん、

mutable/immutableの話が、僕には難しくなってきました。

簡単に質問しますが、その機能があれば、以下のようになるということでしょうか?

コード:
void copy(final Sample1 src, Sample2 dst)
{
    dst.setMember1(src.getMember1());
    src.setMember2(dst.getMember2());    // コンパイルエラーが出る!
}



# まあこんなコピーメッソッドは作りませんが、サンプルということで。。。

つまり、不変オブジェクトが作れると。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-04-05 14:48
一旦論点整理です。

まず、immutableなクラスというのは現時点のJavaでも作成可能です。
java.lang.Stringなどが有名ですね。
クラス全体をimmutableとして設計できるケースはそのようにすればよいのですが、
言語の修飾子なりアノテーションなりで明示できるとよいね、
というあたりが結論ということでよろしいでしょうか。


「不変オブジェクト」というと「不変クラス」との混用が多いようなので
「不変インスタンス」という用語を使いましょう。

可変なクラスの特定のインスタンスといいますか、特定の変数のみ不変としたい。
つまりfinal修飾子を付けて宣言した変数の「参照」ではなく「実態」を不変としたい。
というのがあぶぽんさんの求めるものですよね?

既存のJavaの機能で実現するとしたらアノテーションを使うしかないのではないでしょうか。
コード:
    @immutable
    Hoge hoge = new Hoge();

    hoge.setPiyo(3); // 状態が変更されるのでエラーとなる!
    int piyo = hoge.getPiyo(); // 状態が変更されないgetterの呼び出しは可能


ということができるようにならないでしょうかね、という話ということでよいでしょうか。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-04-05 15:23
引用:

nagiseさんの書き込み (2007-04-05 14:48) より:
コード:
    @immutable
    Hoge hoge = new Hoge();

    hoge.setPiyo(3); // 状態が変更されるのでエラーとなる!
    int piyo = hoge.getPiyo(); // 状態が変更されないgetterの呼び出しは可能




この方向性だと、メソッド毎にmutable/immutableを定義しないと
使い物にならなくなるので、C++のconst関数と同じになってしまうのでは?

それに、個々の変数に対する修飾子(アノテーションでも)として定義すると、
どうしても利用する側の判断になってしまうので、実質的な強制力も低く、
final同様、意味の薄いものになってしまうのではないでしょうか。
あぶぽん
大ベテラン
会議室デビュー日: 2005/10/20
投稿数: 205
投稿日時: 2007-04-05 15:35
nagiseさん、
ご解説ありがとうございます。

皆さんの意見からすると、RubyやPHPでは実現できている機能なんですね。
Javaも言語仕様として提言すべきだと思います。

また、あしゅさんの意見では、

引用:

メソッド単位にすると、C++のconst/mutableのようなことになるので、
クラス単位の方がよさそうに思います。


とありますが、
C++ではどのような点が問題になっているのでしょう?
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-04-05 15:57
引用:

あしゅさんの書き込み (2007-04-05 15:23) より:
この方向性だと、メソッド毎にmutable/immutableを定義しないと
使い物にならなくなるので、C++のconst関数と同じになってしまうのでは?

それに、個々の変数に対する修飾子(アノテーションでも)として定義すると、
どうしても利用する側の判断になってしまうので、実質的な強制力も低く、
final同様、意味の薄いものになってしまうのではないでしょうか。


実現可能性側から考えた話ですので利便性には確かに疑問がありますね。
寡聞ゆえC++のmutableキーワードを知らなかったのですが、
確かに対象クラスの作成者に大きな負担がありますし、信頼性も薄いでしょうね。

状態変更を伴うメソッドというのが容易に判断できないですからね。
そこを製作者責任ということにすれば実現可能という話ですから。
もっと単純にgetter以外を呼ぼうとしたらOUT!という作りであれば
アスペクト指向な環境であれば比較的容易に実現できるのかもしれませんね。
結局、利用可能なメソッドがマークされていないと変な裏道ができちゃうわけですが…

クラスレベルで不変クラスにできるならそれが一番だとは思います。

引用:

あぶぽんさんの書き込み (2007-04-05 15:35) より:
皆さんの意見からすると、RubyやPHPでは実現できている機能なんですね。
Javaも言語仕様として提言すべきだと思います。


RubyやPHPはかじった程度なのですが、インタープリタの実装でがんばれば
確かに可能そうですね。もしJavaに盛り込むとしたらVM側に盛り込めば
動的検出にはなりますが可能なのかもしれませんね。

考慮すべき問題点としてマルチスレッド時の整合性ということも考えると
変数ではなくインスタンス単位で不変とするぐらいしか無理なのかもしれませんね。
あぶぽん
大ベテラン
会議室デビュー日: 2005/10/20
投稿数: 205
投稿日時: 2007-04-05 16:27
みなさん、

完璧を目指すと結局、言語仕様を変えることになるかと思いますが、

僕が、今、一番問題にしているのは、以下のような全く予測不可能な
ところでインスタンスの内容が変えられてしまうことです。

コード:
Punyu getPunyu(final Fuwa fuwa)
{
    final Punyu p = new Punyu();
    fuwa.setPunyuFlg(true);  // なんでこれが通るの?
    return p;
}



こういうことをされると、デバッグにすごく手間がかかるので。

それならいっそfinalなんて付けなきゃいいのに。。。紛らわしい
というわけで、「絶対に付けるな」のうちの一票は僕でした

# 1行目になぜfinalを付けなければならないのかというのも問題ですが。
# CheckStyleの(いや、うちの規約の)せいです。。。蒸し返してすみません。

スキルアップ/キャリアアップ(JOB@IT)