いけむランド

はてダからやってきました

freeze について考えてみる

ちょっとtwitterで話題になったこと。 - 都元ダイスケ IT-PRESS を読んで、思ったことをまとめてみる。


自分が設計するならば、修飾子じゃなくて

  • マーカインタフェース java.lang.Freezable
  • メソッド java.lang.Object#freeze()
  • Freezable インタフェースを implement していないクラスのインスタンスで freeze() を呼び出した場合に投げられる実行時例外クラス java.lang.FreezeNotSupportException
  • freeze() されたインスタンスのフィールドを変更しようとした場合に投げられる実行時例外クラス java.lang.FrozenObjectException

を用意すると思う。

package java.lang;
public interface Freezable {}
package java.lang;
public class FreezeNotSupportedException extends Exception
{
  public FreezeNotSupportedException()
  {
    super();
  }
  public FreezeNotSupportedException(String s)
  {
    super(s);
  }
}
package java.lang;
public class FrozenObjectException extends UnsupportedOperationException
{
  public FrozenObjectException()
  {
    super();
  }
  public FrozenObjectException(String s)
  {
    super(s);
  }
}
package java.lang;
public class Object
{
  :
  private boolean frozen = false;
  protected void freeze() throws FreezeNotSupportedException { ... }
  :
}

freeze() の処理を clone() と同じような挙動にすると、わかりやすいと思う。ただし、実装するとなると、ちょっとややこしい気がする。
freeze() を呼び出した後はそのインスタンスのフィールドの変更がされそうになった場合に例外をスローする仕組みが必要はなずだけど、それをどうやって検出するのか?
基本的にはバイトコード内で this に対する putfield 命令を持つようなメソッドで、その前に frozen? のチェックを入れればいいとは思うけど、それだと継承しているすべてのメソッドを調べて、必要なメソッド (setHoge() の類) をオーバーライドしなければいけないはず。
だけど、中には private メソッドや final メソッドがあるはずだから、コンパイラが特別扱いして処理しないと解決できないと思う。
それはさすがによろしくないだろうから、やっぱり freeze の実装は難しそうな気がする。


.NET Framework には Freezable クラス があるみたいなのだが、どのように実装しているのだろうか?