2011-09-09 7 views
8

私は、オブジェクトが最終的に使用される関数で構築されなければならない不変的なコードをいくつか持っています(理想的ではないが部分的な仮定の)。コンストラクタコールの場所のスカラーコンパイル時のチェック

ムーを操作する責任を負う関数booがあるとします。 BOOを使用するBOOの

def boo(mooGen:() => Moo) { 
    val m = mooGen() // a new MOO must be created HERE 
    m.moo() 
} 

クライアントは関数は、所望の武を生成する()=>武、の種類に通過しなければなりません。

理想のクライアントの動作:

boo(() => new Moo(// specific parameters here)) 

武がブーイング本体の内部まで作成されません。

ただし、クライアントは簡単に次のコードを脱調することができます

val myMoo = new Moo(// specific parameters here) 
boo(() => myMoo) 

これは、我々はMOOの建設だけブーイングで発生したい不変を破ります。

基本的には、関数の呼び出しスタック内にmooGenの戻り値が作成されているのか、あらかじめ作成されているのかを判断したいと考えています。

実行時にこれを確認する方法はたくさんあります。しかし、このパターンを強制的に行う方法はありますかコンパイル時間?暗黙の言葉や何か他のものを巧みに使う?

アイデアがありがとうございます!

答えて

12

booとMooを、オブジェクトの外部でインスタンス化できないトークンクラスとともに、独自のオブジェクトに入れます。あなたが行うことができますしたい今、何

scala> object Foo { 
    | class Moo(token:Token) {} 
    | class Token private[Foo]() 
    | def boo(mooGen: (Token) => Moo) {val m = mooGen(new Token)} 
    | } 
defined module Foo 

scala> Foo.boo(new Foo.Moo(_)) 

そして、あなたが行うことができないしたくないものを:

scala> val mymoo = new Foo.Moo(new Foo.Token) 
<console>:8: error: constructor Token in class Token cannot be accessed in objec 
t $iw 
     val mymoo = new Foo.Moo(new Foo.Token) 
         ^

しかしが本当にが望んでいるクライアントの場合彼は - 残念ながら - まだ彼のムーを得ることができます:

val ireallywantone = new Foo.Moo(null.asInstanceOf[Foo.Token]) 
3

私はMooのコンストラクタとメソッドbooの両方があなたのコントロール下にあり、そしてクライアントによって書き込まれる必要がない場合、その後、あなたはMooは暗黙のパラメータを取る作ること、およびそのAのみの場所を手配することができますね有効な暗黙的な値の範囲は、booです。

暗黙のパラメータの型を完全にプライベートにすることができない場合があります。クライアントがMoobooの外側にインスタンス化しないことがさらに確実になります。なぜなら、私は、コンパイラがMooの定義に漏れている私的な型について不平を言うと思う。しかし、それがなくても、それは少なくともあなたが偶然を防ぐのを助けるべきであるのMooの作成はbooの外側にあります。クライアントは意図的に暗黙の値を取得して、Mooを作成する必要があります。

関連する問題