Ada 2020 (36日目) - 一時オブジェクト

対訳表を作っておくべきだった気もしてきました。 そんな厳密なの期待されてないですよね、ね。

オブジェクト

これまでこのシリーズでは「*型のオブジェクト」という言葉を説明なく使ってきました。 ニュアンスとしては constant を付けて宣言した定数や new で割り当てたもの等も含めた「変数」よりは大きなくくりを意図してはいました、一応、ふわっと。

改めて、Adaでのオブジェクトって何でしょうね?

規格では次のように説明されています。

3.3 Objects and Named Numbers

Objects are created at run time and contain a value of a given type. An object can be created and initialized as part of elaborating a declaration, evaluating an allocator, aggregate, or function_call, or passing a parameter by copy. Prior to reclaiming the storage for an object, it is finalized if necessary (see 7.6.1).

Glossarry

An object is either a constant or a variable. An object contains a value. An object is created by an object_declaration or by an allocator. A formal parameter is (a view of) an object. A subcomponent of an object is an object.

イメージはつかめましたでしょうか。

……わかんないですよねー。 規格の文面なんて前提知識がないと意味不明です。 (天丼)

とりあえず宣言した変数や定数、それにアロケーターで割り当てたものがオブジェクトなのは間違いなさそうです。 メモリ上でその型の内部表現を取っている入れ物であることは間違いないでしょう。

しかし、何かに代入する前の途中の式は果たしてオブジェクトなのでしょうか。

  • リテラル(例えば 1.0)はオブジェクトなのでしょうか?

  • named number(例えば U : constant := 1.0;)はオブジェクトなのでしょうか?

  • リテラルのqualified式(例えば Float'(1.0))はオブジェクトなのでしょうか?

  • オブジェクトのqualified式(例えば X : constant Float := 1.0; として Float'(X))はオブジェクトなのでしょうか?

  • 型変換の結果(例えば Float (1))はオブジェクトなのでしょうか?

  • 関数の返値(例えば Cos (0.0))はオブジェクトなのでしょうか?

ある式がオブジェクトかどうかを手元のコンパイラで試す簡単な方法は renames できるか試すことです。

with Ada.Numerics.Elementary_Functions;
procedure Whether_It_Is_Object_1 is
   use Ada.Numerics.Elementary_Functions;
   U : constant := 1.0;
   X : constant Float := 1.0;
-- Case1_Literal      : Float renames 1.0;         -- error
-- Case2_Named_Number : Float renames U;           -- error
-- Case3_Qualified_L  : Float renames Float'(1.0); -- error
   Case4_Qualified_X  : Float renames Float'(X);
-- Case5_Converted    : Float renames Float (1.0); -- error
   Case6_Result       : Float renames Cos (0.0);
begin
   null;
end Whether_It_Is_Object_1;

或いは属性を付けられるか試す方法もあります。

with Ada.Text_IO;
with Ada.Numerics.Elementary_Functions;
procedure Whether_It_Is_Object_2 is
   use Ada.Numerics.Elementary_Functions;
   U : constant := 1.0;
   X : constant Float := 1.0;
begin
-- Ada.Text_IO.Put (1.0'Image);         -- error
-- Ada.Text_IO.Put (U'Image);           -- error
-- Ada.Text_IO.Put (Float'(1.0)'Image); -- error
   Ada.Text_IO.Put (Float'(X)'Image);
-- Ada.Text_IO.Put (Float (1.0)'Image); -- error
   Ada.Text_IO.Put (Cos (0.0)'Image);
end Whether_It_Is_Object_2;

まあ、手元の処理系が正しく規格を実装しているとは限りませんけれどね。 実際GNAT(Community Edition 2019)は Case4_Qualified_X はエラーにしやがりましたし U'ImageFloat'(1.0)'ImageFloat (1.0)'Image をコンパイル通しやがりましたし……。

とまあくだらない事を書いて水増ししてみました。

経緯

GNATのバグはともかくとしまして、規格上型変換がオブジェクト扱いされないのは不便です。

型変換は間違いなくメモリ上にその型の内部表現を持つ値を作っているわけです。 関数の返値と扱いが違うのは変です。

またqualified式に関しては複雑なルールがありましてaliasedやconstrained等の情報が抜け落ちる場合があります。 オーバーロードされた関数呼び出しを解決するためにqualified式で修飾したら他に影響が出るのは困ります。

procedure Qualified_Error is
   F : aliased Float;
   L : aliased Long_Float;
   function Overloaded return not null access Float is (F'Access);
   function Overloaded return not null access Long_Float is (L'Access);
   X : Float renames Float'(Overloaded.all);
   A : not null access Float := X'Access; -- error
begin
   null;
end Qualified_Error;

この例では X を宣言している行の Float'( ) を消すとエラーがなくなります。

Ada 2020での改善

型変換の結果がオブジェクト扱いになりました。 qualified式のルールは改善されました。

上の例 Qualified_Error はAda 2020ではコンパイルできるようになりますし、最初の例はこうなります。

with Ada.Numerics.Elementary_Functions;
procedure whether_it_is_object1 is
   use Ada.Numerics.Elementary_Functions;
   U : constant := 1.0;
   X : constant Float := 1.0;
-- Case1_Literal      : Float renames 1.0;         -- error
-- Case2_Named_Number : Float renames U;           -- error
-- Case3_Qualified_L  : Float renames Float'(1.0); -- error
   Case4_Qualified_X  : Float renames Float'(X);
   Case5_Converted    : Float renames Float (1.0);
   Case6_Result       : Float renames Cos (0.0);
begin
   null;
end whether_it_is_object1;

Ada 2020では全ての型とそのオブジェクトに 'Image 属性が使えるようになりましたから益々printデバッグが捗ります。

関連AI