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