2017-02-24 1 views
1

変数への読み取り専用アクセスを提供することは、抽象化によって(もちろん)達成することができます。たとえば、変数をのの呼び出し可能なエンティティのモードパラメータまたはジェネリックにすることができます。これらの定数ビューによる変数の使用は、呼び出し可能なインスタンスまたは汎用インスタンスに限定されます。変数を読み込み専用にする方法はありますが、定数にすることはできません。

この構造は既存のプログラムに追加するのは容易ではないと私は思う。プログラムは既に構造化されているからだ。また、それは "読み取り専用"と構造の間の結合を必要とするため、独立した解決策ではありません。

別のオプションは、変数をprivateにして、その値を返す関数をエクスポートすることです。しかし、私は直接露出を望んでいました。 揮発性の定数であり、まだ異なる視点からの変数です。

私はオーバーレイを思い付いた:

with Interfaces; 

package Read_Only is 
    subtype Pins is Interfaces.Unsigned_16; 

    V : constant Pins with Volatile, Import; 

private 
    Backing : Pins with Volatile; 
    for V'Address use Backing'Address; 
    procedure Reset; 
end Read_Only; 

これはVので、パッケージ本体のみ(と子供を)シールドパッケージのクライアントがVを読むことができますが、その値を変更することができます。しかし、このすべてを側面と住所の後ろに隠していると私は考えています。

編集:@ flyxさんのコメントで思い出しは、constantが表示されますパッケージの公開部分のリーダーとはよくVが物理的に定されていること、それはvolatileであること、ないと思うことがあります。さらに、私はのオブジェクトのような文字をVとし、それ以外の部分はRead_Onlyから変更することはできません。 Vここでは実際には定数オブジェクトではありませんが、その宣言ではそうです。私は、機能の不測の事態を招くことなく、認識可能な揮発性のオブジェクト、または何らかのオブジェクトの定数ビューを宣言したいと思います。

+0

は、コンパイラが 'V'はそれがないので、あなたのコードを中断します' constant'、であるという事実に基づいて特定の最適化を行うことを許可されません実際に一定?私は、関数が最も良い方法であると言います。なぜなら、ユーザーとコンパイラの両方に値が時間とともに変化する可能性があることを通知するからです。 – flyx

+0

** volatileの存在下でコンパイラがこれを最適化できるとは思っていませんが**可能な場合はコピーまたは参照を返す関数をインライン化することがありますが、揮発性変数のしかし、最適化はどのように**一定の**を取り除くことができますか?そのコンパイラはひどく壊れてしまいます。また、** volatile **はパッケージが 'Pure'になるのを防ぎます。一般的に、純粋なパッケージのように、Ada関数は実際に時間の経過とともに変化する価値の弱い指標です。しかし、それは質問または願いの一部です: "定数"≠ "読み取り専用"。 – B98

+0

私は、「揮発性」は、おそらくは一定の伝播を禁止することに同意します。それはちょうど考えだった、私はLRMが暗記されていない。それにもかかわらず、私のGNATは*警告を出す:私がこれをするとき定数は変数をオーバーレイする*。 – flyx

答えて

3

私のアドバイスは次のようになり、簡単な関数とプライベート変数を使用します。

with Interfaces; 

package Read_Only is 
    subtype Pins is Interfaces.Unsigned_16; 

    function V return Pins; 

private 
    Backing : Pins; 
    function V return Pins is (Backing); 
end Read_Only; 

エイダの呼び出し規約をオブジェクトがとにかく最も効率的な方法で返されることを保証します。

また、式関数として実装することで、呼び出しのインライン化が確実に行われます。

function V return Pins with Inline_Always; 

その場合的にので、呼び出しは常に、アクセス変数にインライン化されています。また、あなたが直接露出して、最適化なしでコンパイルしても、すべての状況で無い呼出しを、必要な場合Inline_Always側面を使用することができます直接的なアクセスと厳密に等価です。

編集:申し訳ありませんが、私はちょうどあなたが機能を望んでいないことを見ました。上記を踏まえて、私はなぜか分からない。もっと正確な理由を教えてください。

+2

私は、式の関数をインライン化する必要はないと思います。コンパイラがそれを選択した場合、コンパイラが簡単になるかもしれないことがわかります。 'Inline_Always'はGNATで実装定義されています。 –

+0

考えられる理由は次のとおりです。クライアントにvolatile変数の読み取り回数を制御させる。変数を完全に隠すインターフェースの構築を延期する - 関数は中間地であるが、V型がそうであるようにバイコピー型ではない場合、参照によって参照変数になる可能性があるため、について考える; ... @SimonWrightが観察したように、この必要性はインライン展開に当てはまり、誰が「V」を直接見るのを「妨げる」かによって、おそらく不明瞭と見なされるかもしれません。 – B98

+0

@SimonWright良い点。 Expesssion関数は、ボディが見えるときにインライン化されることが保証されています。 –

1

興味深い質問です。

変数への読み取り専用アクセスを提供することは、抽象化によって(もちろん)達成することができます。たとえば、変数を呼び出し可能なエンティティのモードパラメータまたはジェネリックのパラメータにすることができます。これらの定数ビューによる変数の使用は、呼び出し可能なインスタンスまたは汎用インスタンスに限定されます。

この構造は既存のプログラムに追加するのは容易ではないと私は思う。プログラムは既に構造化されているからだ。また、それは "読み取り専用"と構造の間の結合を必要とするため、独立した解決策ではありません。

私はジェネリックのだろういかに難しいかわからないんだけど、あなたはジェネリック医薬品の使用を再考ために喜んでいる場合、私はあなたがこれを行うことができると思う:

Generic 
    Type Alpha(<>) is private; 
Package Constant_Access is 
    Type Beta is access constant Alpha; 
    Subtype Gamma is not null Beta; 

    Generic 
     Item_Access : in Gamma; 
    Package Access_Accessor is 
     Item : Constant Alpha renames Item_Access.all; 
     Pragma Volatile(Item); 
    End Access_Accessor; 

End Constant_Access; 

次に、あなたがする必要がある場合インスタンスのみを表示するには、Constant_Accessのインスタンス化でAccess_Accessorのインスタンシエーションを使用します。そのインスタンス化の直後に、インスタンス化のItemの名前を、非表示または定数に変更します。

はい、これは少し厄介ですが、それははあなたが必要なプロパティが守られていることを確認しない(おそらく揮発性であること、すなわち。)であっても重い最適化の顔に。


編集:

With 
System.Address_To_Access_Conversions; 

Generic 
    Type Alpha(<>) is private; 
Package Constant_Access with Preelaborate is 

    Package Conversions is new System.Address_To_Access_Conversions(Alpha); 
    Use Conversions, System; 

    ----------------------- 
    -- Type Declarations -- 
    ----------------------- 
    Type Beta is access constant Alpha; 
    Subtype Gamma is not null Beta; 
    Type Epsilon(G : Not Null Access Constant Alpha) is null record 
     with Implicit_Dereference => G, Volatile; 
    -- NOTE: You could excise Beta and Gamma, they are included for flexibility. 

    -------------------------- 
    -- Conversion Functions -- 
    -------------------------- 

    Function "+"(Right : Aliased Alpha) return Gamma is 
     (Right'Access); 
    Function "+"(Right : Gamma) return Alpha is 
     (Right.All); 
    Function "+"(Right : Gamma) return Epsilon is 
     (G => Right.All'Access); 
    Function "+"(Right : Epsilon) return Gamma is 
     (Right.G); 
    Function "+"(Right : Aliased Alpha) return Epsilon is 
     (G => Right'Access); 
    Function "+"(Right : Epsilon) return Alpha is 
     (Right.G.All); -- Not actually needed due to implicit dereferencing. 
    Function "+"(Right : Not Null Access Constant Alpha) return Address is 
     (Right.All'Address); 
    Function "+"(Right : Address) return Alpha is 
     (To_Pointer(Right).All); 
    Function "+"(Right : Epsilon) return Address is 
     (+Right.G); 
    Function "+"(Right : Address) return Epsilon is 
     (G => +To_Pointer(Right).All);  

    ----------------------- 
    -- Accessor Generics -- 
    ----------------------- 
    Generic 
     Item_Access : in Gamma; 
    Package Access_Accessor is 
     Item : Epsilon(Item_Access) 
      with Volatile; 
    End Access_Accessor; 

    Generic 
     Item_Address : in System.Address; 
    Package Address_Accessor is 
     Item : Epsilon := +Item_Address 
      with Volatile; 
    End Address_Accessor; 

End Constant_Access; 
+0

私は定数へのアクセスについて考えていましたが、それまでのところ、ジェネリックの使用については考えていませんでした。これまでのところ、私はまだそれを動作させることができませんでした。 **定数**は名前の変更(マイナー)の一部ではないので、 'Access_Accessor'にはいくつかの調整が必要でした。コンパイラが教えてくれる' Item'に 'Volatile'を追加することはできません。興味深いことに、[RM C.6(13)](http://www.ada-auth.org/standards/aarm12_w_tc1/html/AA-C-6.html#p13)を参照してください。あなたのソリューションを使用する私の現在の試みの[要点](https://gist.github.com/98B/74ce568df4028260a75a8b1bf05cf5ed)があります。 – B98

+0

@ B98 - これはコンパイラを最初に実行しないために得られるものです。 いずれにしても、必要な柔軟性を提供する拡張/編集(およびコンパイル可能な)チャンクを追加しました。 [純粋な*単位では使用できません。] – Shark8

関連する問題