アクセス制御の抜け穴 (OCaml編)
Obj.magic 最強、で終わらそうと思ったのですがそう単純な話でもないらしい。
まず OCaml の private メソッドは、Javaなどのprotected相当で、継承した先のクラスからアクセスすることができます。
しかし呼び出せるのは自分に対してだけで、引数として受け取ったオブジェクトに対して呼び出すといったことはできません。method f x = x#g などと定義すると、fの引数xには"gというpublicメソッドを持った型"しかつけられなくなります。
class hoge = object method private priv = print_endline "hoge:private" end class fuga = object inherit hoge as super (* hogeを継承 *) method priv = super#priv (* 同名のメソッドをpublicに再定義可能 *) method call_priv (x:hoge) = x#priv (* type error *) end
method call_priv (x:hoge) = x#priv ^ This expression has type hoge It has no method priv
また、private メソッドは、class type を制限することで継承先クラスにも見せない、本当にそのクラスだけのためのメソッドにすることができます (モジュールのシグネチャを制限するのと同じような感じ)。
class hoge : object (* priv はない *) end = object method private priv = print_endline "hoge:private" end class fuga = object inherit hoge as super (* priv は使えない *) method func = super#priv; print_endline "fuga:func" end
method func = super#priv ^^^^^ This expression has no method priv
で、メソッドがprivateかどうかってのは純粋に型の問題でコンパイラさえごまかしてしまえばなんとかなりそうだと思ったので Obj.magic でいじれば十分だろうと考えたのですが、うまくいったりいかなかったり。内部表現どうなってのコレ。
class type visible = object method priv : unit (* public *) end class hoge = object method private priv = print_endline "hoge:private" end let _ = let x = new hoge in let y:visible = Obj.magic x in y#priv
hoge:private
これはうまくいく。
class type restricted = object (* empty *) end class type visible = object method hidden : unit end class hoge : restricted = object method private hidden = print_endline "hoge:hidden" end let _ = let x = new hoge in let y:visible = Obj.magic x in y#hidden
hoge:hidden
これもうまくいく。しかし
class type visible = object method priv1 : unit method priv2 : unit end class hoge = object method private priv1 = print_endline "hoge:private 1" method private priv2 = print_endline "hoge:private 2" end let _ = let x = new hoge in let y:visible = Obj.magic x in y#priv1; y#priv2
hoge:private 2 hoge:private 2
二つ以上になるとうまくいかない!?
うまくいかない場合について、もう少し厳密に調べたい。