Ada 202x (43日目) - その他のgenericの変更¶
いくら細部が重要と言っても細部過ぎて既に意味わからない領域ではないかと思います。
abstract引数とclass-wide版のサブプログラム¶
tagged型のプリミティブには対応するclass-wide版のサブプログラムが用意されます。
generic
type T (<>) is tagged private;
with procedure Foo (Obj : in T);
package P1 is
end P1;
package A is
type Something is tagged null record;
procedure Some_Proc (Object : in Something) is null;
end A;
procedure Unrelated_Proc (Object : in A.Something) is null;
package New_P1 is new P1 (A.Something, A.Some_Proc);
package New_P1_U is new P1 (A.Something, Unrelated_Proc);
package New_P1_CW is new P1 (A.Something'Class, A.Some_Proc);
New_P1_CW
では P1
の Foo
として渡しているのは暗黙に用意された procedure Some_Proc (Object : in Something'Class);
です。
(またGNATのバグを見つけたような気がします。
規格ではAda 2012以降でこのコードは通るはずです。)
さて generic
のサブプログラムの仮引数に abstract
を付けますとプリミティブしか受け付けなくなります。
generic
type T (<>) is tagged private;
with procedure Foo (Obj : in T) is abstract;
package P2 is
end P2;
package New_P2 is new P2 (A.Something, A.Some_Proc);
package New_P2_U is new P2 (A.Something, Unrelated_Proc); -- error
package New_P2_CW is new P2 (A.Something'Class, A.Some_Proc); -- error
パッケージの外で宣言した Unrelated_Proc
を弾くようになりました。
ついでに最後のclass-wide版も弾かれました。
class-wide版のサブプログラムはプリミティブではないからです。
ところが generic
をもうひとつ挟むことでエラーになったはずのclass-wide版を通すことができます。
generic
type NT (<>) is new A.Something with private;
package Gr is
package New_P2_In_Gr is new P2 (NT, Some_Proc);
end Gr;
package New_Gr_CW is new Gr (A.Something'Class);
一度 A.Something
(またはそこから派生した)型と限定した NT
を介しています。
A.Something
はプリミティブ Some_Proc
を持っていますので NT
でも Some_Proc
は使えます。
ですので New_P2_In_Gr
は合法です。
基底型を限定した仮引数にclass-wide型を渡すのも合法ですので New_Gr_CW
も合法です。
回避できるのに New_P2_CW
を弾く意味がないということで修正されます。
Ada 202xでは abstract
のついたサブプログラムの仮引数がclass-wide版のサブプログラムを受け付けるようになります。
念の為に書いておきますとclass-wide版のサブプログラムといってもプリミティブに対応するものだけです。 野良で宣言したものは弾かれます。
procedure Unrelated_CW_Proc (Object : in A.Something'Class) is null;
package New_P2_CW is new P1 (A.Something'Class, A.Some_Proc);
package New_P2_U is new P1 (A.Something'Class, Unrelated_CW_Proc); -- error
Pure/Preelaborateとネストされたgeneric¶
これまで規格の文面では翻訳単位の Pure
/Preelaborate
がネストされた generic
にまで影響していなかったらしいです。
package Outer with Pure is
generic
package Inner is
procedure Dummy;
end Inner;
end Outer;
package body Outer is
package body Inner is
Variable : Integer;
procedure Dummy is
begin
null;
end Dummy;
end Inner;
end Outer;
禁止しておかないと Inner
をインスタンス化することで Pure
な翻訳単位にグローバル変数を作ることができてしまいます。
実際この Variable
はGNATもAdaMagicという古いコンパイラも弾くそうです。
Ada 202xでは規格の文面でも禁止されました。
関連AI¶
AI12-0165-1 Operations of class-wide types and formal abstract subprograms
AI12-0232-1 Rules for pure generic bodies