Ada 202x (3日目) - generalized array aggregate¶
Ada 202xではaggregate式に大幅な手が入ってます。 その中でも、昨日少し触れましたように今回紹介するこれが一番影響が大きいのでさっさと済ませます。
経緯¶
従来Adaではcomposite typeに対するaggregate式はこのように書いていました。
declare
type Point is record
X, Y : Float;
end record;
type Vector is array (Positive range <>) of Float;
P1 : Point := (X1, Y1); -- positional association
P2 : Point := (X => X2, Y => Y2); -- named association
A3 : Vector (1 .. 3) := (1.0, 2.0, 2.0); -- positional association
A4 : Vector (1 .. 3) := (1 => 1.0, 2 .. 3 => 2.0); -- named association
要素の名前を書かずにソースコードに書かれた順番で埋めていくのをpositional association、要素の名前を明示するのをnamed associationといいます。 配列の場合に単一要素ではなく範囲を使うのもnamed associationです。
さて、ここで使われる括弧は他と同じ丸括弧 (
)
です。
要素数が2個以上のときは中に ,
がありますのでaggregate式とわかります。
しかし要素数が1個の場合は優先順位の括弧と区別が付きません。
そうです、要素数が1個のaggregate式をpositional associationで書くことができませんでした。
=>
があればaggregate式とわかりますのでnamed associationで書くことはできます。
declare
type Wrapper is record
Element : Integer;
end record;
-- W5 : Wrapper := (0); -- error
W6 : Wrapper := (Element => 0);
-- A7 : Vector (1 .. 1) := (1.0); -- error
A8 : Vector (1 .. 1) := (1 => 1.0);
要素数が0の場合は、record型の場合は null record
を使い、配列の場合は 'First
> 'Last
になるような範囲を指定する必要があります。
declare
type Unit is null record;
-- U9 : Wrapper := (); -- error
UA : Wrapper := (null record);
-- AB : Vector (1 .. 0) := (); -- error
AC : Vector (1 .. 0) := (1 .. 0 => <>);
長さ0の配列でも、記法上ダミーの値を書く必要があります。
といっても具体的な値を用意する必要はなくて、デフォルト初期化を意味する <>
が使えます。
また、この例のように代入先の型によりインデックスの範囲が確定している場合は、範囲を繰り返す必要はなくて others
が使えます。
declare
AD : Vector (1 .. 0) := (others => <>);
空の括弧 ()
が禁止されているのは理由がありまして、Adaではなるべく値を書くべきところに何も書いていなければエラーになるように文法を設計する、という方針によるものです。
記述が冗長な反面、ミスを含むコードが意図に沿わない形でコンパイルを通ってしまうようなことが少なくなっていて型システムとは違う形で堅牢性を支えています。
(このサイトに訪れてくださる方は難解コードコンテスト等が好きな方が多いと思いますので、つまらないかもしれませんね。)
なお要素数0のrecordが null record
なら配列も null array
と書けて良さそうなものですが、そのような記法は残念ながらありません。
Ada 202xでの改善¶
ASCIIコードが普及しきっていなかった時期に作られた古い言語ではISO 646の文字だけでソースコードが書けるようになっているものが多いです。 C言語のトライグラフなんかもそうです。 まあつまり、Adaではまだ使っていないASCII記号が沢山あります。 括弧も丸括弧しか使ってませんでした。
驚きです。 Ada 202xではついに、ついに、これまで使われていなかった記号が使われるようになります。 95でも、2005でも、2012でも手が付けられることがなかった部分です。
Ada 202xで新たに使われるようになるのは @
、 [
、 ]
の3文字です。
このうち [
と ]
がaggregate式に使われます。
そうです、配列のaggregate式に使われる括弧が (
)
から [
]
に変更されます。
驚きです。
勿論互換を確保する必要がありますので (
)
も従来通り使えますが、[
]
を用いた場合は先述のような優先順位のための括弧との区別を考える必要がなくなるわけです。
要素数1の場合でもpositional associationで書けますし、要素数0の場合は単に []
で良くなります。
declare
A3 : Vector (1 .. 3) := [1.0, 2.0, 2.0];
A4 : Vector (1 .. 3) := [1 => 1.0, 2 .. 3 => 2.0];
A7 : Vector (1 .. 1) := [1.0];
A8 : Vector (1 .. 1) := [1 => 1.0];
AB : Vector (1 .. 0) := [];
AC : Vector (1 .. 0) := [1 .. 0 => <>];
AD : Vector (1 .. 0) := [others => <>];
pygmentsがエラーになってシンタックスハイライトされないですね。残当。
注意点として、 record
のaggregate式は (
)
のままです。
↓の関連AIのタイトルに Container aggregates が含まれますように、ユーザー定義型もaggregate式で初期化できるようになります。
そのため、record型そのものの生のaggregate式には (
)
、ユーザー定義の初期化には [
]
と使い分けることになります。
関連AI¶
AI12-0212-1 Container aggregates; generalized array aggregates
AI12-0306-1 Split null array aggregates from positional array aggregates
AI12-0307-1 Resolution of aggregates
昨日の例を書き直し¶
ておきます。 これがあるから、順番としてこっちを先にするべきだったのですよ……。
declare
Array_Var : array (1 .. Length) of T :=
[for I in 1 .. Length => Create (I)];
declare
Geometric : constant array (0 .. Length) of Integer :=
[for I in 0 .. Length => 2 ** I];
declare
Identity_Matrix : constant array (1 .. Length, 1 .. Length) of Float :=
[for I in 1 .. Length => [I => 1.0, others => 0.0]];
所感¶
思い切りましたよねえ……という感想しか出てこないです。 uniformと言いつつ新しい文法と頭痛の種を追加したC++11のuniform initialization syntaxを連想させてくれます。
ユーザー定義型でaggregate式を使えるようにする方法はまた後日。 (ネタを使い切らないよう小出し。)