Ada 202x (45日目) - その他のその他の変更¶
まとめていきます。 目指せ完結。
固定小数点数関連¶
"*"演算子¶
固定小数点型の値と任意の整数型の値とで掛け算("*"
)ができるように受け取れる文章が修正されました。
既定義で用意されるのは Integer
との演算です。
サブプログラム関連¶
同じオブジェクトを複数の引数に使うケースの緩和¶
@
のときに「ひとつの文中で in out
パラメータに渡したオブジェクトを同時に他に使うことはできません。」と説明しました。
4日目を参照。
この判定のためのルールが若干緩和、というより本来の意図通りの文面に修正されました。 この変更はAARMでもwording changeに分類されるぐらい影響は超レアなのですが折角読み解いたので書かせてください。
まず、先のざっくりした説明では説明しきれていないことがあります。 参照渡しなら同じ呼び出しでは同時に複数引数に渡してもセーフです。
declare
type By_Ref is tagged null record;
procedure P1 (A, B : in out By_Ref);
-- P1の実装は省略
X : By_Ref;
begin
P1 (X, X);
参照渡しでも同じ呼び出しでなければ評価順の影響を受けますのでアウトです。
declare
function F1 (A : in out By_Ref) return Integer;
-- F1の実装は省略
Z : Integer;
begin
Z := F1 (X) + F1 (X); -- error
値渡しは同じ呼び出しでも評価順の影響を受けますので全部アウトです。
値渡しの out
パラメータは値渡しして値返しされた結果を書き戻すことで実現されます。
この書き戻しの順番が同じ呼び出し内でも不定です。
複合型は値渡しも参照渡しもあります。 最適化で変化する可能性もあります。 例では確実に参照渡しにするためにtagged型にしています。
基本型は常に値渡しです。
……というのを踏まえまして。
影響するのは4引数以上のサブプログラム呼び出しで、2つの引数が同じ複合型、残り2つの引数が基本型の場合のみです。
モードは全部 in out
か out
のどちらかとします。
複合型の2つの引数は参照渡しならセーフ、値渡しならアウトです。 基本型の2つの引数は常に値渡しのため確実に別のオブジェクトでなければなりません。
このように規格の文面はまず複合型か基本型かで分けられてその次に参照渡しか値渡しかで分けられています。 実際にはもっと細かいですが。
で、基本型のときの文面が複合型のほうに影響してしまっていました。
つまり本来セーフの次の例がアウトになっていました。
declare
procedure P2 (A, B : in out By_Ref; C, D : in out Integer);
-- P2の実装は省略
X : By_Ref;
Y, Z : Integer;
begin
P2 (X, X, Y, Z);
複合型の方のルールでは参照渡しですのでセーフです。
基本型の方のルールが問題で2つの引数は Y
と Z
という別々のオブジェクトを渡しているにも関わらず、複合型の方に両方 X
を渡しているのが引っかかってしまっていました。
この超細かい問題がAda 202xで修正されました。
パッケージ関連¶
incomplete型とfreezing¶
特殊な用法においてincomplete型がサブプログラムの引数に使える場面が増えました。
incomplete型は名前だけ先行宣言された型です。 C言語でいうopaque型です。 freezingされるより前に完全な宣言を行う必要があります。
freezingは型の定義をそれ以降変更できなくなることです。 42日目を参照。
よく使われる例としてはリンクリストの定義があります。
declare
type Node;
type Node_Access is access Node;
type Node is
record
Previous : Node_Access;
Element : Float;
end record;
1つ目の type Node;
がincomplete型としての宣言です。
このような相互に参照しあう型の他、 generic
や limited with
のためにも活用されます。
少々特殊な用法としてbody部内の型をprivate部でincomplete型として宣言して使うことができます。 この用法自体は昔からあります。
package Pkg1 is
procedure Proc1;
private
type T;
X : access T;
end Pkg1;
package body Pkg1 is
procedure Proc1 is
begin
null;
end Proc1;
type T is null record;
end Pkg1;
ところがこの用法ではincomplete型をサブプログラムの引数にできませんでした。
package Pkg2 is
private
type T;
X : access T;
procedure Proc2 (Object : in T); -- error
end Pkg2;
-- bodyは省略
本来incomplete型はサブプログラムの引数にできます。
先程の Node
の例で途中にサブプログラムの宣言を挟んでも問題ありません。
declare
type Node;
type Node_Access is access Node;
procedure Add (Root : in out Node; Element : in Float);
type Node is
record
Previous : Node_Access;
Element : Float;
end record;
では何が駄目なのかといいますと、パッケージの仕様部の最後まで到達しますと宣言されたサブプログラムの引数に使われている型が全部freezingされるルールに引っかかっていました。 周りくどいルールですが必要だからあるルールではあるのです。 しかしincomplete型と完全な宣言が分かれる特殊な用法を考慮されていませんでした。
Ada 202xで修正され Proc2
のようなサブプログラムも存在できるようになります。
private procedureとprivate with¶
private procedure
の仕様部から親パッケージの private with
が見えるようになりました。
package Lib is
type T is null record;
end Lib;
private with Lib;
package Parent is
end Parent;
private procedure Parent.Child (A : Lib.T);
アスペクト関連¶
自己参照の禁止¶
X : constant Natural := 1
with Atomic => X > 0;
この手の自己参照が禁止されました。 (GNATはAIの中で出された例は弾きましたがちょっと変えてこうするとクラッシュしました。 わはは。)
抽象型と内部表現のアスペクト¶
抽象型には内部表現のアスペクトは付けられなくなりました。
package Pkg3 is
type T is private with Size => 8; -- error
private
type T is mod 2 ** 8;
end Pkg3;
内部表現はprivate部に書く必要があります。
package Pkg4 is
type T is private;
private
type T is mod 2 ** 8 with Size => 8;
end Pkg4;
Remote_Call_Interface関連¶
'Read/'Write属性の実装禁止¶
Remote_Call_Interface
パッケージで宣言されたサブプログラムの呼び出しはRPC(remote procedure call)に変換されます。
主にCORBA(死語)やO/Rマッピング等に使われます。
その中で定義した型の 'Read
/'Write
属性をユーザー定義の実装に置き換えることは禁止されました。
private with Ada.Streams;
package RCI with Remote_Call_Interface is
type T is null record;
procedure RPC (X : in T);
private
procedure Read
(Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : out T);
procedure Write
(Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : in T);
for T'Read use Read; -- error
for T'Write use Write; -- error
end RCI;
RPCにおいて引数をバイト列にして転送するために 'Read
/'Write
属性が使われます。
ところが Remote_Call_Interface
パッケージ中で定義された 'Read
/'Write
属性の実装になるサブプログラムはそれ自体もRPCの対象になってしまいます。
'Read
/'Write
属性をカスタマイズしたければ型ごと別のパッケージに分離する必要があります。
この修正はAda 2012に入るはずでしたが間に合いませんでした。
Nonblocking¶
Remote_Call_Interface
パッケージのサブプログラムや Remote_Types
パッケージの型の Nonblocking
アスペクトは False
でなければなりません。
他言語関連¶
C言語側でinパラメータを書き換えてはいけない¶
小見出しの通りです。
はっきり言って今までも駄目でした。 念押しの記述が追加されました。
正直変更ではないのですが意図を汲んで私からも念押ししておきます。
with Interfaces.C;
package Imported is
type t is
record
a, b : Interfaces.C.int;
end record
with Convention => C;
procedure c_ffi1 (x : in t)
with Import, Convention => C;
end Imported;
/* This is BAD example! */
struct t {
int a, b;
};
void c_ffi1 (struct t *x)
{
x->a = 1;
}
Ada側で in
としているものをC側で変更するな!
……とのことです。
よほど守らない奴がいてSteve先生も腹に据えかねたのでしょう。
Fortranのバージョンの更新¶
規格が参照しているFortranのバージョンがISO/IEC 1594-1:2018に更新されました。
Fortran 2018になります。
もしFortranに古いイメージをお持ちでしたら調べてみると面白いかもしれません。
関連AI¶
AI12-0002-1 RCI units do not allow specification of user-defined stream-oriented attributes
AI12-0155-1 Freezing of an incomplete view has no effect
AI12-0181-1 Self-referencing representation aspects
AI12-0216-1 6.4.1(6.16-17/3) should never apply to composite objects
AI12-0219-1 Clarify C interfacing advice
AI12-0222-1 Representation aspects and private types
AI12-0224-1 Use of Fortran C Interfacing features
AI12-0261-1 Conflict in "private with" rules
AI12-0283-1 Nonblocking and remote calls
AI12-0300-1 Annex G text for Fixed * integer