Copyright IBM Corp. 1987, 2004. All Rights Reserved. Copyright IBM Japan 2006

「Rational」という名称および Rational の製品は、IBM Corporation の商標です。その他の会社名ならびにその製品名はそれぞれの会社の商標であり、参照以外の目的で利用することはできません。

目次

このマニュアルについて

はじめに

基本原則
前提事項
ガイドラインの分類
唯一のガイドライン

コード・レイアウト

概論
大/小文字の区別
インデント
行の長さと改行
位置合わせ

コメント

概論
コメントの使用に関するガイドライン

命名規則

概論
パッケージ

例外
サブプログラム
オブジェクトとサブプログラム (またはエントリー) パラメーター
汎用ユニット
サブシステムの命名方針

型、オブジェクト、プログラム・ユニットの宣言

列挙型
数値型
実数型
レコード型
アクセス型
密閉型
派生型
オブジェクト宣言
サブプログラムと汎用ユニット

式とステートメント


ステートメント
コーディングのヒント

可視性の問題

多重定義と同形異義語
コンテキスト節
名前変更
use 節に関する注意事項

プログラム構造とコンパイルの問題

パッケージの分解
宣言部の構成
コンテキスト節
詳細化の順序

並行性

エラー処理と例外

低レベル・プログラミング

表現節と属性
チェックされない変換

まとめ

参考資料

用語集


第 1 章

このマニュアルについて

このマニュアル「Rational Unified Process - Ada プログラミング・ガイドライン」は、 ユーザーの組織に合ったコーディング標準を作成する際に使用可能なテンプレートです。このマニュアルでは Ada プログラムを作成する場合に守らなければならない方法を説明しています。想定する読者は、Ada を実装言語として、 またはインターフェースやデータ構造などを 指定するための設計言語として使用する、すべてのアプリケーション・ソフトウェア設計者と開発者です。

このマニュアルで説明する規則はコーディングのほとんどの側面を網羅しています。全般的な規則は、 プログラム・レイアウト、命名規則、コメントの使用法に適用されます。特定の規則は Ada の選択された機能に適用され、禁じられた構造、推奨される使用パターン、 プログラムの品質を向上させるための一般的なヒントを明らかにします。

プロジェクトの設計 ガイドラインとこのプログラミング・ガイドラインには 一定の重複がありますが、これは意図的なものです。ソフトウェア設計におけるオブジェクト指向 を 積極的に支援し、強化するため、特に命名規則 の領域で多くのコーディング規則が導入されています。

このガイドラインはもともと Ada 83 向けに作成されました。Ada 95 との互換性規則は 含まれていますが、タグ型、子ユニット、小数型など、改訂された言語標準に導入された 新機能の使用に関する具体的なガイドラインは含まれていません。

このマニュアルの構成は「Ada Reference Manual」(参考資料 [ISO 8052]) の構成にほぼ従っています。

第 2 章「概論」では、このガイドラインの基礎となる基本原則を説明し、ガイドラインの分類を紹介します。

第 3 章「コード・レイアウト」では、プログラムのテキストの一般的な構成を視覚的観点から説明します。

第 4 章「コメント」では、コメントを用いた、構造化され、実用的で、保守しやすいコードの記録方法について説明します。

第 5 章「命名規則」では、言語エンティティーの命名に関する一般的な規則と例を示します。この章は、特定のプロジェクトまたは組織の要求に合わせて適用する必要があります。

第 6 章「宣言」と第 7 章「式とステートメント」では、言語構造の各種別について詳細を説明します。

第 8 章「可視性の問題」と第 9 章「プログラム構造とコンパイルの問題」では、グローバル構造とプログラムの構成について説明します。

第 10 章「並行性」では、タスク処理の使用と時間に関連する言語機能という 部分に特化した話題を提供します。

第 11 章「エラー処理と例外」では、例外を用いて、または用いずに体系的かつ軽量な方法でエラーを処理する方法について説明します。

第 12 章「低レベル・プログラミング」では、表現節について説明します。

第 13 章「まとめ」では、最も重要なガイドラインを要約します。

このマニュアルは、「Ada Guidelines: Recommendations for Designers and programmers」Application Note #15, Rational, Santa Clara, CA., 1990 を置き換えるものです。


第 2 章

はじめに

基本原則

Ada は、品質、信頼性、再利用性、 移植性が高いソフトウェアの開発を支援するために明示的に設計されました「参考資料 [ISO 87, sect. 1.3]」。しかし、 プログラミング言語自体でこれを確実に達成するものはありません。プログラミングは十分に統制のとれた過程の一部として実行しなければなりません。

明確で理解しやすい Ada ソース・コードはこのマニュアルで提供するガイドラインのほとんどの主な目標です。これは信頼性と保守容易性の大きな要因です。明瞭で理解しやすいコードが意味することは、以下の 3 つの単純な基本原則として把握できます。

最小限の意外性原則

ソース・コードの存続期間の中で、書かれる回数よりも読まれる回数の方が多く、 特に仕様についてこのことがあてはまります。コードは、実行される内容と実行による 利益を英語の記述を読むように理解できるのが理想的です。 プログラムは、コンピューターに向けてというよりは、 人間のために作成されます。コードを読むことは 複雑な知的プロセスであり、その労力は統一性によってサポートされます。 このガイドでは、そのような統一性を最小限の意外性原則 と呼んでいます。プロジェクト全体で統一されたスタイルは、 ソフトウェア開発者のチームがプログラミング標準に関して同意するための重要な根拠です。 ある種の罰則または創造性や生産性を妨げる障害として受け止めてはいけません。

保守の単一点

このガイドの基礎となるもう 1 つの原則は保守の単一点原則 です。設計の決定は可能な限り、Ada ソース・コード中のただ 1 つの場所で表さなければならず、 その結果のほとんどはこの点からプログラム的に派生しなければなりません。この原則に違反すると、 保守容易性と信頼性に加えて、理解のしやすさも大きく損なわれます。

最小限の雑音

最後に、読みやすくするための重要な要素として、最小限の雑音原則 が適用されています。 つまり、ソース・コードが視覚的な「雑音」によって雑然となることを回避するために 労力をかけます。雑音とは、各種のバー、ボックス、重要度の低い情報または ソフトウェアの目的の理解には寄与しない情報を含むその他のテキストなどです。

移植性と再利用性も多くのガイドラインの理由です。コードは異なるターゲット・コンピューター用の異なるコンパイラーに、 最終的には Ada の上級バージョンである「Ada 95」に移植されなければなりません 「参考資料 [PLO92, TAY92]」。

前提事項

本書に記載するガイドラインには、次の前提事項があります。

読者は Ada を知っている。

有用な場合は常に高度な Ada 機能の使用を推奨します。 プログラマーの一部がそれらに不慣れだという理由で使用を避けるべきではありません。 これは、プロジェクトが真に Ada の使用による利益を得ることができるただ 1 つの方法です。Ada が Pascal または FORTRAN であるかのように使用してはいけません。コメント中でコードを言い換えることを推奨しません。 反対に、使用可能な場合は常に、コメントの代わりに Ada を使用しなければなりません。

読者は英語を理解している。

命名規則の多くは、語彙と構文の両方で英語に基づいています。さらに、Ada キーワードは普通の英単語で成り立っており、 それらに別の言語を混在させると読みにくくなります。

use 節の使用が大幅に制限される。

命名規則とその他のいくつかの規則は「use」節を使用しないことを前提としています。

非常に大規模なプロジェクトを処理する。

多くの規則は、大規模な Ada システムで最も大きな価値をもたらします。 ただし、プロジェクトまたは会社レベルでの実践原則と統一性のためであれば、小規模システムでも使用できます。

ソース・コードは Rational 環境で開発される。

Rational 環境を使用することにより、コード・レイアウトや構造を閉じる際の ID などの問題は Ada エディターとフォーマッターが処理します。 ただし、このマニュアルに含まれるレイアウトの推奨事項は任意の開発プラットフォームに適用できます。

コーディングはオブジェクト指向設計に従う。

多くの規則は、オブジェクト指向 (OO) 概念から Ada 機能と特定の命名規則への体系的なマッピングに対応しています。

ガイドラインの分類

ガイドラインは同等の重要性を持っているわけではありません。おおまかに以下のように分類されます。

ヒント:ヒント・アイコン

このガイドラインは簡単なアドバイスです。指示に従わないことにより実害はありません。 また、好みで選択または拒否できます。このマニュアルの中で、ヒントには上の記号が付いています。

推奨事項:OK アイコン

このガイドラインは通常、より技術的な理由に基づいています。移植性または再利用性は影響を受けることが考えられますし、 実装によっては性能にも関係することがあります。 これらの推奨事項は、使用しない正当な理由がない限り、従う必要があります。このマニュアルではいくつかの例外を述べています。このマニュアルの中で、 推奨事項には上の記号が付いています。

注意事項:注意アイコン

問題の機能を使用することは危険ですが、完全に禁止されているわけではありません。 使用の決定はプロジェクト・レベルで行わなければなりません。 また、その決定は高い可視性を持っていなければなりません。このマニュアルの中で、制限事項には上の記号が付いています。

要求事項:要求アイコン

違反すると明らかに不良で、信頼できず、移植性のないコードになります。 要求事項に違反することは許されません。このマニュアルの中で、要求事項には上に示す手の形の記号が付いています。

Rational Design Facility を使用して、制限された機能の使用に印を付けたり、要求された規則や推奨事項の多くを強制したりします。

他の多くの Ada コーディング標準とは反対に、実際、 このガイドラインの中で完全に禁止されている Ada 機能はほとんどありません。優れたソフトウェアを作成するための鍵は、次のとおりです。

唯一のガイドライン

要求アイコン常識的な 考え方を採用します。

規則やガイドラインが見つからない場合、 規則が明らかに適用されていない場合、何もかもが失敗する場合は、 常識的な考え方に基づいて、基本的な原則を確認します。この規則は、 他のどの規則よりも優先されます。常識的な考え方は必要不可欠 です。


第 3 章

コード・レイアウト

概論

プログラム・ユニットのレイアウトは完全に Rational Environment Formatter の制御下にあり、 コメントと空白を除いて、プログラマーはプログラムのレイアウトを気にしすぎる必要はありません。このツールで採用されているフォーマット規則は、 「Reference Manual for the Ada Programming Language」の付録 E「参考資料 [ISO87]」 に示されているものです。 特に、構造の開始と終了を示すキーワードは垂直方向に位置合わせすることが提案されています。また、構造の ID は構造の終わりで意図的に繰り返されます。

フォーマッターの正確な動作は一連のライブラリー・スイッチ により制御されます。 ライブラリー・スイッチは、共通のモデル界に基づき、 プロジェクト全体で統一された値のセットを受け取ります。関連するスイッチを、推奨されるモデル界 の現行値とともに以下に示します。

大/小文字の区別

Format . Id_Case : Letter_Case := Capitalized

Ada ユニットにおける ID の大/小文字を指定します。 最初の文字と下線の後の最初の文字は大文字です。現在使われているほとんどの画面やレーザー・プリンターのフォントについて、 先頭を大文字にすることにより、人間である読み手が最も読みやすい形式になります。

Format . Keyword_Case : Letter_Case := Lower

Ada キーワードの大/小文字を指定します。これはキーワードと ID を若干区別します。

Format . Number_Case : Letter_Case := Upper

浮動小数点数リテラルの文字「E」とベースとなるリテラルの数字 (「A」から「F」) までの種別を指定します。

インデント

Ada ユニットは、「Ada Reference Manual」(参考資料 [ISO87]) の付録 E で示される一般的な規則に従って整形されます。 これは、構造の開始と終了を表すキーワードが位置合わせされることを意味します。 例えば、「loop」と「end loop」、「record」と「end record」などです。 構造 の要素は右方向にインデント されます。

Format . Major_Indentation : Indent_Range := 3

フォーマッターが、「if」ステートメント、「case」ステートメント、「loop」ステートメントといった主要な構造をインデントする桁数を指定します。

Format . Minor_Indentation : Indent_Range := 2

フォーマッターが、レコード宣言、可変レコード宣言、型宣言、例外ハンドラー、代替、case ステートメント、名前付けとラベル付けステートメントといった比較的重要性が低い構造をインデントする桁数を指定します。

行の長さと改行

Format . Line_Length : Line_Range := 80

フォーマッターが Ada ユニット中の行を印刷するため、 折り返す前に使用する桁数を指定します。これにより、整形されたユニットを従来の VT100 仕様の端末で表示できます。

Format . Statement_Indentation : Indent_Range := 3

ステートメントが Line_Length より長いために分割しなければならない場合、 フォーマッターがステートメントの 2 番目以降の行をインデントする桁数を指定します。フォーマッターは、 インデントされるコードを位置合わせ可能な語彙的な構造がない場合にのみ、Statement_Indentation の桁数をインデントします。

Format . Statement_Length : Line_Range := 35

ステートメントを表示するために各行に予約される桁数を指定します。 現在のインデントのレベルでは、1 行で許される桁数が Statement_Length の桁数よりも小さい場合、 フォーマッターは Wrap_Indentation の桁を新しいインデントのレベルとして開始します。こうした動作により、 ネストが深いステートメントが右の余白を超えて印刷されることを防ぎます。

Format . Wrap_Indentation : Line_Range := 16

現在のインデントのレベルが Statement_Length を可能にしない場合、 フォーマッターが次のインデントのレベルを開始する桁を指定します。こうした動作により、 ネストが深いステートメントが右の余白を超えて印刷されることを防ぎます。

位置合わせ

Format . Consistent_Breaking : Integer := 1

形式 (xxx:aaa; yyy:bbb) のリストの整形を制御します。これらはサブプログラムの形式部や型宣言の判別式として現れます。 また、形式 (xxx=>aaa, yyy=>bbb) の一覧の整形も制御します。これらはサブプログラム呼び出しや集約に現れます。 このオプションはゼロでない (True) ので、リストが行に合わない場合、リストのすべての要素は新しい行で始まります。

Format . Alignment_Threshold : Line_Range := 20

名前の付いた表記におけるコロン、割り当て、矢印など、連続したステートメント中の語彙的な構造の位置合わせを行うために、 フォーマッターが挿入可能な空白の数を指定します。構造の位置合わせをするためにこれよりも多い空白数が必要な場合、 構造は左の位置合わせが行われません。

要求アイコン 一定の レイアウトを強制するために、プログラマーは、<space> <space> <carriage-return> を入力することにより、フォーマッターによって 削除されない行末または改行を挿入できることに注意してくださ い。

OK アイコンこの技法を 使用して、また、読みやすさと保守のしやすさを向上させるため、Ada 要素のリストが 3 項目を上回り、1 行に収まらない場合、 1 行あたり 1 項目のみを含むように分割しなければなりません。 これは特に以下の Ada 構造 ("Ada Reference Manual"「参考資料 [ISO87]」の付録に定義) に適用されます。

引数関連

pragma Suppress (Range_Check,
                 On => This_Type,
                 On => That_Type,                 On => That_Other_Type);      

ID リスト、コンポーネント・リスト

Next_Position,
Previous_Position,
Current_Position : Position;
type Some_Record is
    record
        A_Component,
        B_Component,
        C_Component : Component_Type;
    end record;      

列挙型定義

type Navaid is
       (Vor,
        Vor_Dme,
        Dme,
        Tacan,
        VorTac,
        NDB);      

判別式制約

subtype Constrained is Element
        (Name_Length    => Name'Length,
         Valid          => True,
         Operation      => Skip);      

ステートメントの連続 (フォーマッターにより実行)

形式部、汎用形式部、実パラメーター部、汎用実パラメーター部

procedure Just_Do_It (This     : in Some_Type;
                      For_That : in Some Other_Type;
                      Status   : out Status_Type);
Just_Do_It (This     => This_Value;
            For_That => That_Value;
            Status   => The_Status);      

第 4 章

コメント

概論

広く考えられていることとは反対に、優良なプログラムはコメントの で 特徴付けられるのではなく、その で特徴付けられます。

コメントは Ada コードを補完 するために用いなければならず、言い換えるために用いるべきではありません。 Ada 自体は非常に読みやすいプログラミング言語ですが、適切な命名規則を適用することでさらに読みやすくなります。 コメントを使用し、明白でないことを説明することで Ada コードを補完しなければなりません。 コメントが Ada 構文またはセマンティクスを繰り返すことがないようにしなければなりません。 コメントは、読者が背景概念、依存関係、特に複雑なデータ・エンコードとアルゴリズムを理解することを助けなければなりません。 コメントは、コーディングと設計の標準からの逸脱、制限された機能の使用、特殊な「トリック」を強調しなければなりません。 主要な Ada 構造 (サブプログラムやパッケージなど) のそれぞれについて意図的に現れるコメント枠またはフォームは、 統一性とプログラマーにコードを記録することを案内するという点で役に立ちますが、 現実には言い換えになる場合が多くあります。各コメントについて、 プログラマーは「このコメントによりどのような価値を加えられるのか。」という問いに十分な回答を用意できなければなりません。

誤解を招く恐れがあるコメントまたは間違ったコメントは何もコメントを付けないことよりも有害です。コメントはコンパイラーによってチェックされません (Rational Design Facility を使用する場合のように、 正式な ADL (Ada Design Language) または PDL (Program Design Language: プログラム設計言語) に属する場合を除く)。したがって、 保守の単一点原則に従って、設計決定は、たとえ宣言の数が増えようとも、 コメントではなく Ada の中で表さなければなりません。

例 (あまりよくはありませんが) として、以下の宣言を考えてください。

------------------------------------------------------------
-- プロシージャー Create
------------------------------------------------------------
--
   procedure Create
              (The_Subscriber: in out Subscriber.Handle;
               With_Name     : in out Subscriber.Name);
--
-- 目的: この手順は指定された名前を持つサブスクライバーを
-- 作成する。
--
-- パラメーター:
-     The_Subscriber    :モード in out、型 Subscriber.Handle
-               作成されたサブスクライバーへのハンドル
-     With_Name         :モード in、型 Subscriber.Name
-               作成されるサブスクライバーの名前
-               この名前の構文は次のようになる。
--                 <文字> { <文字> | <数字> }
-- 例外:
--    Subscriber.Collection_Overflow
--    新しいサブスクライバーを作成するスペースがない場合。
--    Subscriber.Invalid_Name
--    名前が空白または形式に合っていない場合。
--
-------------------------------------------- Create の終わり ----

この例についていくつかの点を指摘できます。

- プロシージャー Create の名前を変更する必要が生じた場合、複数の場所を修正することになります。コメントに対する一貫した変更はコンパイラーによって強制的に行われません。
- パラメーター、その名前、モード、型をコメント中で繰り返す必要はありません。
- ここに含まれる各 Ada エンティティー用に選択された適切な名前は、 目的とパラメーターの説明を冗長にします。これは上記のような単純なサブプログラムについてあてはまることに注意してください。より複雑なサブプログラムではやはり目的とパラメーターの説明が必要です。

この場合、以下のように、より簡潔で有用な形が適切です。

procedure Create (The_Subscriber : in out Subscriber.Handle;
                  With_Name      : in    Subscriber.Name);--
--Subscriber.Collection_Overflow を発生される。
--Subscriber.Invalid_Name を発生される。
--条件は名前が空白または形式に合っていない場合。
--(型 Subscriber.Name の宣言に付随する構文の説明を参照)。      

コメントの使用に関するガイドライン

OK アイコンコメントは 関連するコードの近くに、同じインデントで配置しなければなりません。 また、そのコードに付属させる必要があります。つまり、以下のように空のコメント行を用いて、 コメントのブロックを Ada 構造に視覚的に結び付けます。

procedure First_One;
--
-- このコメントは First_One に関係する。
-- しかし、このコメントは Second_One 用である。
-- 
procedure Second_One (Times : Natural);      

OK アイコン関連するソース・コードの ブロック (コメントとコード) を分割するにはブランク行を使用し、以下のような重いコメント行は避けます。

OK アイコン段落を分割するには、 以下のように、空白行ではなく、1 つのコメント・ブロック中に空のコメントを入れます。

-- ここに記述する説明は後の段落で
-- 継続する必要がある。
--
-- 上の空のコメント行は単一のコメント・ブロックを
-- 処理していることを明らかにする。

OK アイコン コメントは、関連する Ada 構造の上または下に配置できますが、 セクション・タイトルまたはいくつかの Ada 構造に適用される主要な情報などのコメントは 構造の に配置します。注意や追加情報のコメントは、適用される Ada 構造の に配置します。

OK アイコン Ada 構造の冒頭で、ページ幅全部を使用して、コメントをグループ化します。 Ada 構造と同じ行のコメントは避けます。こうしたコメントは位置が合わなくなることがよくあります。ただし、こうしたコメントは、 列挙型リテラルなど、長い宣言中の各要素の説明では許容されます。

OK アイコンセクション・タイトルについて、 以下のように標準ブロックの小さな階層を用います。ただし、非常に大規模な Ada ユニット (宣言またはステートメントが 200 を超える場合) に限ります。

--===========================================================
--
--               ここに主要なタイトル
--
--===========================================================


-------------------------------------------------------------
--               ここに小タイトル
-------------------------------------------------------------


--             --------------------
--               サブセクション・ヘッダー
--             --------------------      

こうしたタイトルの下よりも上により多くのブランク行を配置します。 例えば、前に 2 行、後に 1 行といった具合です。これはタイトルをその後のテキストに視覚的に関連付けます。

OK アイコン作成者、電話番号、 作成日と更新日、ユニットの場所 (またはファイル名) などはすぐに古い情報となるため、ヘッダーには記述しません。 特に Rational 環境を利用する場合、所有者の著作権に関する情報をユニットの終わりに配置します。 パッケージ仕様のソースを利用する場合 (例えば、Rational 環境で [Definition] を押すなど)、 ユーザーは、プログラムの理解に役立たないテキスト、 または著作権に関する表記といったプログラム情報を含まないテキストを数ページに渡ってスクロールする必要がありません。 垂直バーや囲みは使用しないようにします。これらは視覚的に邪魔になるだけでなく、一貫性を保ちにくくします。ユニット履歴を保持するには Rational CMVC メモ (またはその他の形式のソフトウェア開発ファイル) を使用します。

OK アイコン通常、 他の場所にある情報と重複しないようにしてください。その情報への参照を提供します。

OK アイコン可能な限り、コメントではなく、Ada を使用します。 これを実現するために、より適切な名前、追加の一時変数、修飾子、名前変更、サブ型、静的表現、属性を使用できます。 これらはすべて生成されるコードに影響しません (少なくとも適切なコンパイラーを使用する場合)。また、 小さなインライン式の述部機能を使用して、コードの複数の個別セクションのタイトルを 提供する名前を持つ、パラメーターなしの複数のプロシージャーにコードを 分割することもできます。

例:

次の例を考えてください。

exit when Su.Locate (Ch, Str) /= 0;
-- 発見した場合、検索ループを出る。

Search_Loop : loop

Found_It := Su.Locate (Ch, Str) /= 0;

exit Search_Loop when Found_It

end Search_Loop;

次の例を考えてください。

if Value < 'A' or else Value > 'Z' then
-- 大文字でない場合。

subtype Uppercase_Letters is Character range 'A' .. 'Z';
if Value not in Uppercase_Letters then ...      

次の例を考えてください。

X := Green;         -- これは Color ではなく、
                    -- Status の Green である。
raise Fatal_Error;  -- パッケージ Outer_Scope から。
delay 384.0;        -- 6 分 24 秒
                    -- と同等。      

The_Status := Green;      

X := Status'(Green);
raise Outer_Scope.Fatal_Error;
delay 6.0 * Minute + 24.0 * Second;      

次の例を考えてください。

if Is_Valid (The_Table (Index).Descriptor(Rank).all) then
-- これは反復の現行値である。
-- 値が有効な場合、含まれるリストに追加する。
   Append (Item,           To_List => The_Table (Index).Descriptor(Rank).Ptr);|      

declare
    Current_Rank : Lists.List renames The_Table
                    (Index).Descriptor (Rank);
begin
    if Is_Valid (Current_Rank.all) then
        Append (Item, To_List => Current_Rank.Ptr);
    end if;
end;      

OK アイコンコメント中の文体、構文、 つづりに注意します。短くあいまいな文体は用いないでください。スペル・チェッカーを使用します (Rational 環境では Speller.Check_Image を起動します)。

要求アイコンアクセントのついた文字 または他の非英語文字を用いないでください。非英語文字は、Ada Issue AI-339 に従って、 一部の開発システムと一部の Ada コンパイラーのコメントのみでサポートされる場合があります。しかし、これは移植性がなく、他のシステムではうまく動作しない可能性があります。

OK アイコン サブプログラムについて、少なくとも以下の事項を記録します。

OK アイコン型とオブジェクトについて、 Ada で表現できない任意の不変な、または補足的な制約を記録します。

要求アイコン コメント中の 繰り返しを避けます。例えば、目的セクションは、「どのように行うか」ではなく、 「何を行うか」という質問に対する簡潔な回答になっていなければなりません。概要は設計の簡潔な説明になっていなければなりません。 説明は使用されるアルゴリズムを説明するのではなく、パッケージが使用されるしくみを説明しなければなりません。

Data_Structure とアルゴリズムのセクションは、主な実装方針を理解するのに役立つ十分な情報を含まなければなりません (パッケージが正しく使用できるように) が、すべての詳細情報、またはこのパッケージの正しい使用に関連のない情報を提供する必要はありません。


第 5 章

命名規則

概論

Ada エンティティー (プログラム・ユニット、型、サブ型、オブジェクト、リテラル、例外) を指定するために適切な名前を選択することは、 すべてのソフトウェア・アプリケーションにおいて考慮しなければならない最も繊細な問題の 1 つです。 中規模以上のアプリケーションでは、名前の競合という別の問題が発生します。より正確に述べると、同じ現実世界の概念に関する、 異なるが類似の観念を示す (または型、サブ型、オブジェクト、パラメーターに名前を付ける) ために十分な同義語を見つけることの難しさです。 ここで、「use」節を用いない規則が利用可能です (または大きく制限された条件でのみ)。これにより、多くの状況で混乱のリスクなく、 名前の短縮と同じ説明語句の再利用が可能になります。

OK アイコン明確で、読みやすく、 意味のある名前を選択します。

他の多くのプログラミング言語と異なり、Ada は ID の長さを 6、8、15 文字に 制限しません。入力の速度は省略語の受け入れられる理由付けになりません。1 文字の ID は たいてい貧弱な選択または怠惰の現れです。いくつかの例外は考えられます。自然対数の底の E や、Pi、その他の十分に認知されているわずかな場合です。

OK アイコン1 つの名前のさまざまな単語は、 次のように下線で区切ります。

Is_Name_Valid のようにし、IsNameValid は避けます。

OK アイコン省略形ではなく 完全な名前を用います。

OK アイコンプロジェクトで承認された 省略形のみを用います。

省略形を用いる場合は、アプリケーション領域で非常に一般的 (例えば、Fast Fourier Transform (高速フーリエ変換) に対する FFT など) であるか、 プロジェクト・レベルで認められている省略形の一部でなければなりません。そうでないと、類似するが完全に一致しない省略形があちこちに現れ、 後で混乱と誤りを招く可能性が大きくなります (例えば、Track_Identification の省略形を Tr_Id、Trck_Id、Tr_Iden、Trid、Tid、Tr_Ident などとする場合)。

OK アイコンAda 構造のカテゴリーを示す 接尾辞は控えめに用います。接尾辞は読みやすさを向上させません。

パッケージの _Package、例外の _Error、型の _Type、 サブプログラム・パラメーターの _Param といった Ada エンティティーの カテゴリー別接尾辞は通常、コードの読み取りと理解の過程にあまり有効ではありません。 _Array、_Record、_Function といった接尾辞の場合はむしろ悪くなります。 Ada コンパイラーも人間の読者も状況によって例外とサブプログラムを区別します。 例外名のみが raise ステートメントや例外ハンドラーの中に出現し得ることは明らかです。こうした接尾辞は以下のような限定された状況で有用です。

_Constrained の接尾辞が付く汎用形式型

_Pointer または _Handle や _Reference といった間接参照形式の接尾辞が付くアクセス型

_Or_Wait により、潜在的なブロッキング・エントリー呼び出しを隠蔽するサブプログラム

OK アイコン名前が 使用法 の観点から適切に見えるように表現します。

エクスポートされたエンティティーが使用される状況について考えてみてください。 その観点から名前を選択します。エンティティーは 1 度宣言され、 何度も使用されます。これは特にサブプログラムの名前とそれらのパラメーターにあてはまります。 結果的な呼び出しは、名前を付けた関連を使用して、 自然言語になるべく近くなるようにしなければなりません。use 節がないため、宣言するエンティティーのほとんどについて、 修飾名が必須となることを忘れないでください。汎用仮パラメーターについて適切な妥協点を見つけなければなりません。 これはクライアント・サイドよりも汎用ユニットでより多く用いられる可能性がありますが、 サブプログラムの仮パラメーターについては、クライアント・サイドに適切に見えることが明らかに優先されます。

OK アイコン英語の語句を使用し、 正確につづります。

言語を混在させると (フランス語と英語など)、コードが読みにくくなり、 ID の意味があいまいになることがあります。 Ada キーワードはもともと英語なので、英語の語句は必須です。Rational 環境に組み込まれているスペル・チェッカーを使用するには、 米国式のつづりが適切です。

要求アイコンパッケージ Standard の任意のエンティティーを再定義しないでください。これは絶対に禁止されています。

これを行うと混乱が生じ、著しい誤りが発生します。この規則は Calendar や System といった他の定義済みライブラリー・ユニットに拡張される場合があります。また、これには ID Standard そのものも含まれます。

OK アイコンSystem や Calendar といった他の定義済みパッケージの ID の再定義を避けます。

要求アイコンID として Wide_CharacterWide_String を使用しないでください。 これらは Ada 95 のパッケージ Standard に導入されます。Ada という名前のコンパイル・ユニットを導入しないでください。

要求アイコンID として abstractaliasedprotectedrequeuetagged、および until を使用しないでください。これは Ada 95 のキーワードになります。

さまざまな Ada エンティティーに対する命名の提案を以下に示します。通常の「オブジェクト風」の設計形態を仮定しています。詳しくは付録 A を参照してください。

パッケージ

OK アイコン パッケージがオブジェクト・クラスを導入する場合、そのオブジェクト・クラスの名前を付けます。 通常、普通名詞の単数形で、必要があれば (つまり、パラメーター化されたクラスが定義されている場合)、接尾辞 _Generic を 付けます。オブジェクトが常にグループで表される場合にのみ複数形を用います。次に例を示します。

package Text is
package Line is
package Mailbox is
package Message is
package Attributes is
package Subscriber is
package List_Generic is      

OK アイコン パッケージがインターフェースまたは機能のグループ化を指定し、 オブジェクトと関連しない場合、これを名前の中で表現します。

package Low_Layer_Interface is
package Math_Definitions is      

OK アイコン 1 つの「論理」パッケージをフラットに分解し、 複数のパッケージとして表現する必要がある場合、プロジェクト・レベルで合意されているリストに基づく接尾辞を用います。 例えば、論理パッケージ Mailbox は以下のように実装できます。

package Mailbox_Definitions is
package Mailbox_Exceptions is
package Mailbox_Io is
package Mailbox_Utilities is
package Mailbox_Implementation is
package Mailbox_Main is      

その他、以下の接尾辞も受け入れられます。

_Test_Support
_Test_Main
_Log
_Hidden_Definitions
_Maintenance
_Debug      

OK アイコン オブジェクト・クラスを定義するパッケージ中で、 次のように使用します。

type Object is ...      

 

これは、コピー・セマンティクスが含まれている場合です。つまり、型がインスタンス化可能で、 何らかの割り当て形式が実現可能な場合です。クラスの名前を ID の中で繰り返さないように注意してください。なぜなら、常に完全修飾名で用いられるからです。

Mailbox.Object
Line.Object      

要求アイコン 共有セマンティクスが 暗示される場合、つまり、型がアクセス値 (またはその他の形態の 間接化技法) と共に実装され、使用可能な割り当てがオブジェクトをコピー しない場合、この事実を 次のように表します。

 

要素そのものをパッケージ名の前に配置しただけでは不明確またはあいまいになる場合は、接尾辞として使用します。

要求アイコン複数のオブジェクトが含まれる場合、以下のいずれかを使用します。

要求アイコン オブジェクトの 文字列指定については、以下を使用します。

type Name

OK アイコン 読みやすさのために、 型の修飾名もパッケージ定義全体で使用しなければなりません。これはまた、Rational 環境において、サブプログラム呼び出しで [Complete] 関数を使用する場合に適切な動作になります。

例えば、以下の例で完全な名前 Subscriber.Object に注意してください。

package Subscriber is
    type Object is private;
    type Handle is access Subscriber.Object;
    subtype Name is String;
    package List is new List_Generic (Subscriber.Handle);
    Master_List : Subscriber.List.Handle;
    procedure Create (The_Handle : out Subscriber.Handle;
                      With_Name  : in  Subscriber.Name);
    procedure Append (The_Subscriber : in     Subscriber.Handle;
                      To_List        : in out Subscriber.List.Handle);
    function Name_Of (The_Subscriber : Subscriber.Handle) return
            Subscriber.Name;
    ...
private
    type Object is
        record
            The_Name : Subscriber.Name (1..20);
                    ...
end Subscriber;    

要求アイコン 他の 状況では、型の名前に名詞または修飾子 + 名詞を使用します。型には複数形を使用し、 オブジェクト (変数) に単数形を使用する場合があります。

type Point is record ...
type Hidden_Attributes is ( ...
type Boxes is array ...    

列挙型の場合、Mode、Kind、Code などを単体または接尾辞として使用します。

配列型については、単純な名前が既にコンポーネント型に使用されている場合、 接尾辞 _Table を使用できます。名前または _Set や _List などの接尾辞は、 配列が暗示されるセマンティクスと共に維持される場合にのみ使用します。対応する数学的な概念に対して、_Vector と _Matrix を予約します。

要求アイコン 単数の タスク・オブジェクトは避けられるので (理由は後述)、タスク型のオブジェク トが 1 つしかなくてもその型を導入しなければなりません。これは _Type などの単純な接尾辞の方針で十分な場合です。

task type Listener_Type is ...
for Listener_Type'Storage_Size use ...
Listener : Listener_Type;    

要求アイコン 同様に、 型の名前に名詞 (または名詞句) を使用する際や、オブジェクトまたはパラメーターの 名前の場所で競合がある場合、型に対して名詞に接尾辞 _Kind を付け、オブジェクトに対して 単純な名詞を維持します。

type Status_Kind is (None, Normal, Urgent, Red);
Status : Status_Kind := None;    

要求アイコン また、 常に複数で扱うものについては、型の複数形を使用します。

OK アイコン アクセス型は継承の危険があるため、 ユーザーは注意しなければなりません。それらは一般に Pointer (ポインター) と呼ばれます。名前だけではあいまいな場合は接尾辞 _pointer を使用します。 代替として _Access も可能です。;

要求アイコン ネストされた サブパッケージを用いて 2 番目の抽象化を導入すると命名が簡潔になる場合があります。

package Subscriber is    ...
    package Status is
        type Kind is (Ok, Deleted, Incomplete, Suspended,
                      Privileged);
        function Set (The_Status    : Subscriber.Status.Kind;
                      To_Subscriber : Subscriber.Handle);
    end Status;
    ...    

例外

OK アイコン 例外はエラー状況を処理する目的にのみ使用しなければならないため、 次のような、否定的な概念が明確に伝わる名詞または名詞句を使用します。

Overflow (オーバーフロー)、Threshold_Exceeded (しきい値超過)、Bad_Initial_Value (不正な初期値)

クラス・パッケージで定義される場合、Bad_Initial_Subscriber_Value などのように ID がクラスの名前を含むことは役立ちません。なぜなら、例外は常に Subscriber.Bad_Initial_Value として使用されるからです。

OK アイコン 体系的に Error という語を使用しても特定の情報が伝わらないので、Bad、Incomplete、Invalid、Wrong、Missing、Illegal といった語を名前の一部にします。

Illegal_Data, Incomplete_Data    

サブプログラム

OK アイコン プロシージャー (とタスク・エントリー) について、 動詞を使用します。関数について、オブジェクト・クラスの属性または特徴を持つ名詞を使用します。論理値 (述部) を返す関数については、 形容詞 (または過去分詞) を使用します。

Subscriber.Create
Subscriber.Destroy
Subscriber.List.Append
Subscriber.First_Name          -- 文字列を返す。
Subscriber.Creation_Date       -- 日付を返す。
Subscriber.List.Next
Subscriber.Deleted             -- 論理値を返す。
Subscriber.Unavailable         -- 論理値を返す。
Subscriber.Remote    

要求アイコン 述部について、 名詞の前に接頭辞 Is_ または Has_ を追加すると便利な場合があります。 時制に関して、正確性と一貫性を維持します。

function Has_First_Name ...
function Is_Administrator ...
function Is_First...
function Was_Deleted ...    

これは、型名または列挙リテラルとして既に単純名が使用されているときに効果的です。

述部は肯定形式で使用します。つまり、「Not_」を含まないようにしなければなりません。

共通の操作については、プロジェクトで選択しているリスト (システムの知識を得るにつれて拡張されるリスト) に基づく動詞を一貫して使用します。

Create
Delete
Destroy
Initialize
Append
Revert
Commit
Show, Display    

要求アイコン 述部関数と 論理型パラメーターについて、肯定的な名前を使用します。否定的な名前を使用すると二重否定となり (Not Is_Not_Found など)、 コードが読みにくくなることがあります。

function Is_Not_Valid (...) return Boolean
procedure Find_Client (With_The_Name : in  Name;
                       Not_Found     : out Boolean)    

上の例は下のように定義しなければなりません。

function Is_Valid (...) return Boolean;
procedure Find_Client (With_The_Name: in Name;
                       Found: out Boolean)    

これにより、クライアントは要求どおりに式を否定できます (実行時に不利益はありません)。

if not Is_Valid (...) then ....    

場合によっては、反義語を使用することで、否定的な述部をその意味内容を変えることなく肯定表現に置き換えることができます。 例えば、「is_not_valid」(有効でない) の代わりに「is_invalid」(無効である) のように表現します。ただし、肯定的な名前の方がより読みやすくなります。例えば、「Is_Valid」 (有効である) は「not Is_Invalid」 (無効でない) よりも理解が容易です。

OK アイコン 同じ意味が含まれる場合は、 同義語やバリエーションを見つける努力をするのではなく、同じ単語を使用します。したがって、最小限の意外性の原則を維持し、統一性を拡張するための多重定義を推奨します。

要求アイコン サブプログラムが エントリー呼び出しの「スキン」または「ラッパー」として使用される場合、 動詞に接尾辞 _Or_Wait を付けるか、Wait_For_ などの句に名詞を続けることにより、 この事実を名前に反映させると便利なことがあります。

Subscriber.Get_Reply_Or_Wait
Subscriber.Wait_For_Reply    

一部の操作は常に同じ名前を使用し、一貫して定義する必要があります。

要求アイコン 文字列、 対称関数に対する型変換の場合

    function Image と function Value    

要求アイコン 低レベルの 表現 (データ交換の Byte_String など) に対する型変換の場合

    procedure Read と Write    

要求アイコン 割り振られた データの場合

    function Allocate (Create ではない)
function Destroy (またはオブジェクトが消えることを表すには Release)

これを一貫した命名により、体系的に行うと、型の構成ははるかに容易になります。

OK アイコン アクティブな反復子について、 以下の基本要素を常に定義しなければなりません。

Initialize
次へ
Is_Done
Value_Of
Reset
. 同じスコープに複数の反復子型が導入される場合、 各反復子について異なる ID のセットを導入するのではなく、 これらの基本要素を多重定義しなければなりません。参考資料 [BOO87] を参照。

OK アイコン Ada の定義済み属性を関数名として使用する場合、'First、'Last、'Length、'Image、'Value など、 同じ一般セマンティクスと共に使用することを確認してください。 属性の中には予約語のために関数名として使用できないものがあることに注意してください (Range や Delta など)。

オブジェクトとサブプログラム (またはエントリー) パラメーター

OK アイコン 一意性を強調する、 またはこのエンティティーがアクションの主対象であることを示すには、オブジェクト名またはパラメーター名に接頭辞 The_ または This_ を付けます。副次的、一時的、付随的なオブジェクトを示すには、A_ または Current_ という接頭辞を付けます。

procedure Change_Name (The_Subscriber : in Subscriber.Handle;
                       The_Name       : in Subscriber.Name );
            declare
    A_Subscriber : Subscriber.Handle := Subscriber.First;
            begin
    ...
    A_Subscriber := Subscriber.Next (The_Subscriber);
end;    

OK アイコン 論理型オブジェクトの場合、述部の文節を肯定形で使用します。

Found_It
Is_Available    

 

Is_Not_Available は避けなければなりません。

OK アイコン タスク・オブジェクトの場合、 アクティブなエンティティーを示す名詞または名詞句を使用します。

Listener
Resource_Manager
Terminal_Driver    

OK アイコン パラメーターの場合、 クラス名または特徴的な名詞に事前条件を接頭辞として付けても読みやすくなります。特に、名前付き関連が使用される呼び出し側にあてはまります。補助パラメーターの便利な接頭辞には他に Using_ があります。 また、2 次的な影響を受ける in out パラメーターの場合は Modifying_ があります。

procedure Update (The_List     : in out Subscriber.List.Handle;
                  With_Id      : in     Subscriber.Identification;
                  On_Structure : in out Structure;
                  For_Value    : in     Value);
procedure Change (The_Object   : in out Object;
                  Using_Object : in     Object);    

OK アイコン 呼び出し側の観点からすると、 パラメーターが定義される順序 も非常に重要です。

これにより、主要なパラメーターの名前付き関連を使用する必要がなく、デフォルトを活用できます。

OK アイコン関数の中であっても、 モード「in」を明示的に示さなければなりません。

汎用ユニット

OK アイコン 非汎用バージョンについて使用する最適な名前を選択します。 パッケージの場合はクラス名、プロシージャー (上記参照) の場合は他動詞 (または動詞句) に接尾辞 _Generic を付けます。

OK アイコン 汎用形式型について、 汎用パッケージが抽象データ構造を定義する場合、汎用形式には Item または Element、 エクスポートされた抽象化には Structure または他のより適切な名詞を使用します。

OK アイコン 受動的な反復子について、ID の中に ApplyScanTraverseProcessIterate といった動詞を使用します。

generic
		with procedure Act	(Upon : in out Element);
procedure Iterate_Generic	(Upon : in out Structure);    

OK アイコン 汎用仮パラメーターの名前を同形異義語にすることはできません。

generic
    type Foo is private;
    type Bar is private;
    with function Image (X : Foo) return String;
    with function Image (X : Bar) return String;
package Some_Generic is ...    

上の例を下のように置き換えます。

generic
    type Foo is private;
    type Bar is private;
    with function Foo_Image (X : Foo) return String;
    with function Bar_Image (X : Bar) return String;
package Some_Generic is ...    

必要があれば、汎用ユニットの中で汎用仮パラメーターの名前を変更できます。

function Image (Item : Foo) return String Renames Foo_Image;
function Image (Item : Bar) return String Renames Bar_Image;    

サブシステムの命名方針

Rational サブシステム (または相互接続された別のプログラム・ライブラリーの形態) に大規模なシステムが含まれる場合、命名方針を定義しておくと以下のことが可能になり便利です。

名前競合の防止

何百ものオブジェクトとサブオブジェクトで構成されるシステムにおいては、ライブラリー・ユニット・レベルで何らかの名前競合が起こる可能性があり、Utilities、Support、Definitions などのいくつかの非常に便利な名前について同義語が不足します。

Ada エンティティーの容易な特定

Rational ホストの参照機能を使用してエンティティーが定義されている場所を検索するのは簡単な作業ですが、コードが目標環境に移植され、 その環境のツール (デバッガー、テスト・ツールなど) を使用して、100 個のサブシステム中の 2,000 個のユニットの中からプロシージャー Utilities.Get を特定することはプロジェクトに新しく参加した人にとってはかなりの難題になる可能性があります。

OK アイコン ライブラリー・ユニット名には、 それが含まれるサブシステムの 4 文字の略語を接頭辞として付けます。

サブシステムのリストはソフトウェア・アーキテクチャー説明書 (SAD) にあります。多数のプロジェクト、COTS 製品、 標準ユニットで再利用される可能性がある再利用性が高いコンポーネントのライブラリーはこの規則から除外します。

例:

Comm 通信

Dbms データベース管理

Disp 表示

Math 数学パッケージ

ドライブ・ドライバー

例えば、サブシステム Disp からエクスポートされるすべてのライブラリー・ユニットに Disp_ という接頭辞を付け、Disp を担当するチームまたは会社が完全に自由に命名できるようにします。DBMS と Disp の両方が Subscriber の名前のオブジェクト・クラスを導入する必要がある場合、 パッケージは以下のようになります。

Disp_Subscriber
Disp_Subscriber_Utilities
Disp_Subscriber_Defs
Dbms_Subscriber
Dbms_Subscriber_Interface
Dbms_Subscriber_Defs    

第 6 章

型、オブジェクト、プログラム・ユニットの宣言

OK アイコン 異なる型の混在を防ぐために、Ada の強力な入力機能が使用されます。概念的に異なる型は異なるユーザー定義型として実現しなければなりません。プログラムの読みやすさを向上させ、 コンパイラーによって生成される実行時チェックの効果を拡大するために、サブ型を使用しなければなりません。

列挙型

OK アイコン 可能な限り、 未初期化、無効、値なしを表す追加のリテラル値を列挙に導入します。

type Mode  is (Undefined, Circular, Sector, Impulse);
type Error is (None, Overflow, Invalid_Input_Value,Ill-formed_Name);    

これは体系的にオブジェクトを初期化するための規則を支援します。このリテラルをリストの最後ではなく最初に配置し、 保守を容易にし、以下のような有効な値の連続した下位範囲を可能にします。

subtype Actual_Error is Error range Overflow .. Error'Last;    

数値型

OK アイコン 定義済みの数値型の使用を避けます。

高度な移植性と再利用性が目的である場合、または数値オブジェクトによって占有されるメモリー空間に対する制御が必要な場合、 定義済みの数値型 (パッケージ Standard から) は使用してはいけません。この要求の理由は、定義済みの型 Integer と Float の特徴が、 「Reference Manual for the Ada Programming Language」[ISO87] で (故意に) 指定されていないからです。

要求アイコン 最初の 体系的な方針は、正確性またはメモリー・サイズを示す名前を持つ、プロジェクト固有の 数値型を、パッケージ System_Types などに導入することです。

package System_Types is
        type Byte is range -128 .. 127;
        type Integer16 is range -32568 .. 32567;
        type Integer32 is range ...
        type Float6 is digits 6;
        type Float13 is digits 13;
...
end System_Types;    

要求アイコン 標準型 (パッケージ Standard の型) を再定義しないでください。

要求アイコン 派生元になるベースの型を指定しないでください。 コンパイラーに選択させます。 次の例は不適切です。

type Byte is new Integer range -128 .. 127;    

要求アイコン ほとんどの コンピューターで、32 ビットの浮動小数点は 6 桁の正確さを実現しても、Float6 は Float32 よりも適切な名前です。

要求アイコン プロジェクトの 各部分で、Baty_System_Types の名前よりも意味がある名前を持つ型を導き出します。 最も正確な型の一部は、限定された正確性をサポートするターゲットへの最後のポートをサポートするために、密閉にすることができます。

この方針は以下のような場合に使用されます。

それ以外の場合、別のより簡単な方針は常に新しい型を定義することです。 この場合、要求される範囲と正確さを指定しますが、派生元になるベースの型を指定しません。例えば、以下のように宣言します。

type Counter is range 0 .. 100;
type Length is digits 5;    

これは、以下よりも優先されます。

type Counter is new Integer range 1..100; -- 64 ビットになる場合がある
type Length is new Float digits 5; -- 13 桁になる場合がある

上の 2 番目の方針では、プログラマーが任意に一定のビット数を選択するのではなく、 各型が要求する正確な範囲と正確さを考慮しなければなりません。ただし、範囲がベースの型と一致しない場合、 コンパイラーによって体系的な範囲検査が適用されることに注意してください。 例えば、上の型 Counter の場合、ベースの型が 32 ビットの整数かどうかがチェックされます。

要求アイコン 範囲検査が 問題になる場合、回避方法の 1 つは以下のように宣言することです。

type Counter_Min_Range is range 0 .. 10_000;
type Counter is range Counter_Min_Range'Base'First .. Counter_Min_Range'Base'Last;

OK アイコン ループ、索引範囲などを通じて、 標準の型が構造からコードに漏れないようにします。

定義済みの数値型のサブ型は以下の状況でのみ使用されます。

例:

for I in 1 .. 100 loop ...
-- I の型は Standard.Integer
type A is array (0 .. 15) of Boolean;
-- 索引は Standard.Integer

代わりに Some_Integer range L .. H という形態を用います。

for I in Counter range 1 .. 100 loop ...
type A is array (Byte range 0 .. 15) of Boolean;

要求アイコン 符号なしの型を実装しないようにしてください。

符号なしの算術を持つ整数型は Ada に存在しません。言語定義の下で、すべての整数型は間接かどうかを問わず定義済みの型から派生し、 ゼロについて対称的でなければなりません。

実数型

OK アイコン 移植性のためには、 一定範囲の値を持つ実数型にのみ依存します。

[-F'Large .. -F'Small]  [0.0]  [F'Small .. F'Large]    

F'Last と F'First はモデル数ではなく、 任意のモデル間隔にもない場合があることに注意してください。F'Last と F'Large の相対位置は型の定義と基底のハードウェアによります。特に好ましくない例は、 以下のように固定小数点の 'Last が型に属さない場合です。

type FF is delta 1.0 range -8.0 .. 8.0;    

"Ada Reference Manual 3.5.9(6)" を詳しく読むと、FF'Last = 8.0 は型に属すことができません。

大きなまたは小さな実数を表現するには、整数型のような属性 'First と 'Last ではなく、属性 'Large または 'Small (とそれらの否定形) を使用します。

OK アイコン 浮動小数点型については、<= と >= のみを使用し、=、<、>、/= を使用しません。

絶対比較のセマンティクスは明確に定義されていません (表現の同等と必要な正確さの程度における非同等)。例えば、X < Y は not (X >= Y) と同じ結果を生じません。 等式 A = B のテストは次のように表現する必要があります。

abs (A - B) <= abs(A)*F'Epsilon    

読みやすさと保守のしやすさを向上させるには、上記の式をカプセル化する Equal 演算子の提供を検討します。

より簡単な式を考えます。

abs (A - B) <= F'Small    

上の式は A と B が小さな値の場合にのみ有効で、一般的には推奨されないことにも注意してください。

OK アイコン 定義済みの例外 Numeric_Error への任意の参照を避けます。Ada Board の義務的な解釈により、 以前 Numeric_Error を起こしていたすべての場合は Constraint_Error を起こすようになっています。例外 Numeric_Error は Ada 95 で古くなっています。

要求アイコン 実装により Numeric_Error がいまだに発生する場合 (Rational 固有のコンパイラーの場合)、 例外ハンドラーの同じ選択肢で、Numeric_Error と共に Constraint_Error をチェックします。

when Numeric_Error | Constraint_Error => ...    

要求アイコン アンダーフローに 注意してください。

アンダーフローは Ada で検出されません。結果は 0.0 となり、例外は発生しません。オペランドのいずれもが 0.0 でない場合、 アンダーフローのチェックは、0.0 に対する乗算または除算の結果をテストすることにより、 明示的に達成可能であることに注意してください。また、効率は若干悪くなりますが、 ユーザー独自の演算子を実装してそうしたチェックを自動的に実行可能であることにも注意してください。

注意アイコン 固定小数点型の使用は制限されます。

可能な限り、浮動小数点型を使用します。Ada 実装を通じて、一様でない固定小数点型の実装は移植性の問題を引き起こします。

要求アイコン 固定小数点型の場合、'Small は 'Delta と等しくなければなりません。

コードはこれを指定する必要があります。'Small のデフォルトの選択が 2 の累乗であるという事実はあらゆる種類の問題を生じます。選択を明らかにする 1 つの方法は以下のように書くことです。

Fx_Delta : constant := 0.01;
type FX is delta Fx_Delta range L .. H;
for FX'Small use Fx_Delta;    

固定小数点型に対して長さ節がサポートされていない場合、 この規則に従うためのただ 1 つの方法は、2 の累乗である 'Delta を明示的に指定することです。 下位型は 'Delta と異なる 'Small を持つことができます (この規則は型定義、つまり "Ada Reference Manual" の用語でいうと「最初の名前付きサブ型」にのみ適用されます)。

レコード型

OK アイコン レコード型のコンポーネントについて、 可能な限り簡単で、静的な初期値を提供します ('First または 'Last といった値が使用できることがよくあります)。

ただし、これを判別式に適用しないでください。言語の規則では判別式が常に値を持つことになっています。可変レコード (つまり、判別式のデフォルト値を持つレコード) は、 変化のしやすさが必要な特徴である場合にのみ導入しなければなりません。そうでないと、可変レコードのために、 余分なオーバーヘッドがメモリー空間 (最大のバリアントが割り振られることがよくあります) と時間 (バリアントのチェックは実現がより複雑になります) に生じます。

OK アイコン 任意のコンポーネントのデフォルトの初期値で関数呼び出しを避けます。 なぜなら、これは「詳細化前のアクセス」エラーを引き起こすからです (「プログラム構造とコンパイルの問題」を参照)。

要求アイコン 可変レコード (判別式がデフォルト値を持つレコード) について、判別式が他のコンポーネントの 範囲で使用される場合、適度に小さな範囲を指定します。

例:

type Record_Type (D : Integer := 0) is
record
            S : String (1 .. D);
    end record;    A_Record : Record_Type;    

上の例は、ほとんどの実装で Storage_Error を発生させる可能性があります。判別式 D のサブ型について、より合理的な範囲を指定します。

OK アイコン レコードの物理レイアウトについて何も仮定しないでください。

特に、他のプログラミング言語と異なり、コンポーネントは定義で指定された順序で配置する必要はありません。

アクセス型

注意アイコン アクセス型の使用を制限します。

これは特に、仮想メモリーを持たない小規模なコンピューター上で 永続的に実行されるアプリケーションにあてはまります。 アクセス型は危険です。なぜなら、小さなプログラミングの間違いが ストレージの枯渇を起こしたり、適切なプログラミングであっても メモリーの断片化が発生したりするからです。 アクセス型は比較的低速 でもあります。 アクセス型の使用はプロジェクト規模の方針の一部でなければならず、 コレクション、サイズ、割り振りと割り振り解除の場所を追跡しなければなりません。 抽象化のクライアントにアクセス型が操作されていることを気付かせるには、 それを示す名前として Pointer を選択するか、名前に接尾辞 _Pointer を付けます。

OK アイコン プログラム詳細化中にコレクションを割り振り、 各コレクションのサイズを体系的に指定します。

指定値 (ストレージ・ユニット) は静的または動的に (例えば ファイルから読み取り) 計算可能です。この規則の根拠は、プログラムが N 日後に 奇妙にダウンするのではなく、すぐに障害を起こさなければならないということです。 汎用パッケージは、これに対して、サイズを指定する追加の汎用形式を提供できます。

割り振られた各オブジェクトについて、何らかのオーバーヘッドが存在する 場合が多いことに注意してください。ターゲット・システム上の実行時に、 内部管理用に各メモリー・ブロックと共に追加情報が割り振られる場合があります。 したがって、サイズが M ストレージ・ユニットのオブジェクトを N 個 格納するために、N × M ストレージ・ユニットを超えるコレクション用の容量、 例えば N * (M + K) などを割り振る必要があります。 このオーバーヘッド K の値は、参考資料 [ISO87] の 付録 F を参照するか、実験を行うことで取得します。

OK アイコン 割り振りルーチン (Ada 基本要素 new) の使用をカプセル化し、 解放します。可能であれば、内部の自由なリストを管理し、Unchecked_Deallocation には頼りません。

再帰的なデータ構造を実装するためにアクセス型が使用される場合、 同じアクセス型を (1 つのコンポーネントとして) 持つレコード型に アクセスする可能性が高くなります。これにより、空間オーバーヘッドを 追加することなく、自由なセルを自由なリストにつなげることにより 再利用できます (リストの先頭へのポインターではない)。

new により発生する Storage_Error 例外を明示的に処理し、 より意味のある例外を再エクスポートして、コレクションの 最大ストレージ・サイズの枯渇を示します。

割り振りと割り振り解除を単一点で行うことで、問題発生時のトレースとデバッグが容易になります。

OK アイコン 割り振り解除は、 同じサイズ (したがって同じ判別式) の割り振り済みセル上でのみ使用します。

これはメモリーの断片化を防ぐために重要です。 Unchecked_Deallocation がメモリー圧縮サービスを提供する見込みはまず考えられません。 ランタイム・システムが解放された近隣ブロックの結合機能を 提供するかどうかチェックしておくことを推奨します。

OK アイコン アクセス型を 持つ Destroy (あるいは Free、または Release) 基本要素を体系的に提供します。

これは特に、アクセス型と共に実装された抽象データ型について重要であり、 複数のそのような型が構成できるように体系的に実 行しなければなりません。

OK アイコン オブジェクトを体系的に解放します。

呼び出しを割り振りと割り振り解除に対応付け、 割り振られたすべてのデータが割り振り解除されることを確認するようにしてください。 データを割り振り解除する場合は、割り振られたときと 同じスコープで行うようにしてください。 例外が発生した場合も忘れずに割り振り解除します。 これは、raise ステートメントで終わる、when others 選択肢を 使用するための 1 つの場合であることに注意してください。

適切な方針は「取得 - 使用 - 解放」というパターンを適用することです。 プログラマーはオブジェクトを取得し (動的なデータ構造を作成)、 使用して、解放しなければなりません。 この 3 つの操作がコード中に明確に定められていることと、例外を含め、 考えられるすべてのフレーム終了で解放が実行されることを確認してください。

要求アイコン レコードに 含まれる場合がある一時的な複合データ構造を割り振り解除する際は注意してください。

例:

type Object is
record
    Field1: Some_Numeric;
    Field2: Some_String;
    Field3: Some_Unbounded_List;
    end record;    

上の例で、「Some_Unbounded_List」は複合リンク構造です。 つまり、互いにリンクされている多数のオブジェクトで構成されています。 では、以下のような一般的な属性関数を考えてください。

function Some_Attribute_Of(The_Object: Object_Handle) return
Boolean is Temp_Object: The_Object;
            begin
    Temp_Object := Read(The_Object);
    return Temp_Object.Field1 < Some_Value;
end Some_Attribute_Of;    

オブジェクトが Temp_Object に読み込まれる際、ヒープ中に暗黙に作成される 複合構造は割り振り解除されませんが、アクセスできなくなります。 これはメモリー・リークです。適切な解決法は、そうした高価な構造に対する 「取得 - 使用 - 解放」パラダイムを実装することです。 言いかえると、クライアントはまずオブジェクトを取得し、 必要に応じて使用して、解放しなければなりません。

procedure Get (The_Object  : out Object;
               With_Handle : in  Object_Handle);
function Some_Attribute_Of(The_Object : Object)
                        return Some_Value;
function Other_Attribute_Of(The_Object	: Object)
                        return Some_Value;
...
procedure Release(The_Object: in out Object);    

クライアント・コードはこのようになるでしょう。

             declare
    My_Object: Object;
            begin
    Get (My_Object, With_Handle => My_Handle);
    ...
    Do_Something
      (The_Value => Some_Attribute_Of(My_Object));
      ...
    Release(My_Object);
end;    

密閉型

OK アイコン 実装の詳細を隠蔽する必要がある場合は常に、 型を private で宣言します。

実装の詳細は、以下の場合に密閉型を用いて隠蔽する必要があります。

Rational 環境において、密閉型を閉じた private 部、サブシステムと使用することで、最終的なインターフェース設計変更の影響を大幅に減らすことができます。

要求アイコン いわゆる 「ピュアな」オブジェクト指向プログラミングとは反対に、対応する完全な 型が、 考えられる最適な抽象化である場合、密閉型を使用しないでください。 現実に即して考えます。型を密閉にすることで何が得られるかを問うようにしてください。

例えば、数学的なベクトルは密閉型よりも、配列またはレコードとして平面上の点でより適切に表現されます。

type Vector is array (Positive range <>) of Float;
Type Point is
record
        X, Y : Float := Float'Large;
    end record;    

型を無用に密閉にすると一連のサブプログラム呼び出しが必要になりますが、それよりも配列の索引化、レコード・コンポーネントの選択、集約の表記の方がはるかに読みやすいものです (最終的には効率的でもあります)。

OK アイコン 実際のオブジェクトと 値のデフォルトの割り当てまたは比較が意味を持たない、 非直感的である、不可能といった場合は、密閉型を limited で宣言します。

これは以下のような場合です。

OK アイコン 限定された密閉型は自ら初期化しなければなりません。

こうした型のオブジェクト宣言は合理的な初期値を受け取らなければなりません。なぜなら、一般に、サブプログラム呼び出し中に何らかの例外を発生させるリスクなしで、後で割り当てることができないからです。

要求アイコン 実行可能で 意味がある場合は常に、限定された型について、Copy (または Assign) プロシージャーと Destroy プロシージャーを提供します。

要求アイコン 汎用の 形式型を設計する際、対応する汎用ユニットの使いやすさを向上させるために、 同等または割り当てが内部的に必要でなければ limited の密閉型を指定します。

前の規則に従って、意味があれば、Copy/Destroy 汎用形式プロシージャーと Are_Equal 述部をインポートする場合があります。

要求アイコン 汎用形式密閉型について、 実際に対応するものが制約されなければならないかどうかを仕様内に示します。

これは以下のように命名規則または注釈により実現できます。

generic
    --制約されなければならない。
    type Constrained_Element is limited private;
package ...

または、Rational 定義のプラグマ Must_Be_Constrained を使用します。

generic
    type Element is limited private;
    pragma Must_Be_Constrained (Element);
package ...

派生型

要求アイコン 型の 派生により、同じ宣言部に親の型として宣言されるすべてのサブプログラム、 つまり派生可能なサブプログラムも派生されることに注意してください。したがって、 それらのすべてを派生型の宣言部にスキンとして再定義するのは無駄です。しかし、汎用サブプログラムは派生可能ではなく、 それらをスキンとして再定義しなければならない場合があります。

例:

package Base is
    type Foo is
record
            ...
    end record;        procedure Put(Item: Foo);
    function Value(Of_The_Image: String) return Foo;
end Base;
with Base;
package Client is
    type Bar is new Foo;
    -- この時点で、次の宣言が
    -- 暗黙に作成される。
    -- 
    -- function "="(L,R: Bar) return Boolean;
    -- 
    -- procedure Put(Item: bar);
    -- function Value(Of_The_Image: String) return Bar;
    -- 
end Client;

したがって、これらの操作をスキンとして再定義する必要はありません。ただし、 汎用サブプログラム (受動的な反復子など) は他の操作と共に派生されないのでスキンとして再エクスポートしなければならないことに注意してください。 ベースの型宣言を含む仕様以外で定義されたサブプログラムも派生可能でないため、 スキンとして再エクスポートする必要があります。

オブジェクト宣言

OK アイコン オブジェクトが自ら初期化するか、 暗黙のデフォルト初期値が存在する場合 (アクセス型、タスク型、非判別フィールドのデフォルト値を持つレコードなど) を除いて、 オブジェクト宣言の中で初期値を指定します。

割り当てられる値は、型の任意の値ではなく、現実的に意味のある値でなければなりません。入力パラメーターなどのように実際の初期値が使用可能な場合、 それを割り当てます。意味のある値を計算することが不可能な場合、後でオブジェクトを宣言することを検討するか、 可能であれば任意の「nil」値を割り当てます。

要求アイコン 「nil」という 名前は「Uninitialized」(未初期化) を意味し、アルゴリズムによって統制のとれた 方法で却下可能な、「使用できない既知の値」として使用できる定数を宣言するために 用いられます。

可能な限り、nil 値は初期化以外の目的に使用してはいけません。これは、この値の出現が常に初期化されていない変数のエラーを示すようにするためです。

一部の型、特に角度などのモジュラー型に対しては nil 値を宣言できない場合もあることに注意してください。この場合はより可能性が低い値を選択します。

要求アイコン 大量の レコードを初期化するコードは、特にレコードに変形があったり、初期値の一部が 非静止 (より正確には値がコンパイル時に計算不可能) である場合、コストが かかる場合があることに注意してください。思い切ってすべての初期値を推敲し (おそらく型を定義しているパッケージ内で)、 次のように明示的に割り当てる方が効率的な場合があります。

R : Some_Record := Initial_Value_For_Some_Record;    

メモ:

経験上、初期化されていない変数は、コードの移植時における問題の主な原因の 1 つであり、プログラム・エラーの主な原因の 1 つです。 これは、開発ホストがプログラマーへの「サービス」から、 少なくともいくつかのオブジェクトに対するデフォルト値を提供する場合 (例えば Rational 固有コンパイラーの型 Integer など) や、 ターゲット・システムがプログラムのロード前にメモリーをクリアする場合 (例えば DEC VAX など) に悪化します。移植性を実現するには、常に最悪の事態を想定します

要求アイコン コストがかかる場合や、 オブジェクトの使用前に値が割り当てられることが明らかな場合は、宣言の中で 初期値を割り当てることを省略できます。

例:

procedure Schmoldu is
    Temp : Some_Very_Complex_Record_Type;
 -- 後で初期化
            begin
loop
        Temp := Some_Expression ...
        ...    

OK アイコン コード中のリテラル値の使用を避けます。

定義される値が型になる場合、定数 (型を持つ) を使用します。 そうでない場合、特にすべての寸法のない値 (純粋な値) については名前付きの数字を使用します。

Earth_Radius : constant Meter := 6366190.7;   -- メートル単位。
Pi           : constant       := 3.141592653; -- 単位なし。

要求アイコン 関連する 定数を普遍的で、静的な式で定義します。

Bytes_Per_Page :   constant := 512;
Pages_Per_Buffer : constant := 10;
Buffer_Size :      constant := Bytes_Per_Page * Pages_Per_Buffer;
Pi_Over_2   :      constant := Pi / 2.0;    

これは、上の式が必ずコンパイル時に計算されなければならないという事実を利用しています。

OK アイコン 匿名の型を持つオブジェクトを宣言しないでください。詳しくは、「Ada Reference Manual 3.3.1」を参照してください。

保守容易性は低下し、オブジェクトをパラメーターとして受け渡すことは不可能となり、型競合エラーに至る場合がよくあります。

サブプログラムと汎用ユニット

要求アイコン サブプログラムは プロシージャーまたは関数として宣言できます。宣言する形態を選択するために 利用可能な一般的な基準を示します。

関数を宣言する場合:

プロシージャーを宣言する場合:

OK アイコン 構造 (テーブル、 コレクションなど) の測定に使用される汎用仮パラメーターにデフォルト値を与えることを避けます。

OK アイコン 副次作用がなるべく少ないローカル・プロシージャーと副次作用がまったくない関数を作成します。副次作用を記録します。

副次作用はたいていグローバル変数の修正であり、サブプログラムの body を読んで初めて気付く場合があります。プログラマーは呼び出し側で副次作用に気が付かないことがあります。

必要なオブジェクトをパラメーターとして渡すようにすると、コードはより堅牢になり、理解しやすく、内容への依存性が薄まります。

この規則は主にローカルのサブプログラムに適用されます。エクスポートされたサブプログラムはパッケージ本体内でのグローバル変数へ正当なアクセスが必要になる場合がよくあります。


第 7 章

式とステートメント

要求アイコン 括弧を 多く使用して、複合的な式を分かりやすくします。

式のネストのレベルとは、演算子の優先順位の規則を無視するなら、式を左から右に評価するために必要な、ネストされた括弧の組の数と定義されます。

要求アイコン 式の ネストのレベルを 4 に限定します。

OK アイコン レコード集合は名前付きの関連を用い、 修飾されなければなりません。

Subscriber.Descriptor'(Name    => Subscriber.Null_Name,
                       Mailbox => Mailbox.Nil,
                       Status  => Subscriber.Unknown,
                   ...);    

要求アイコン レコード集合について、when others の使用は禁止されています。

これは、配列とは異なり、レコードはもともと異種構造であり、統一された割り当てが合理的でないからです。

要求アイコン 単純な 述部について、「if...then...else」ステートメントの代わりに単純な真偽値式を 使用します。

function Is_In_Range(The_Value: Value; The_Range: Range)
     return Boolean is
            begin
            if The_Value >= The_Range.Min and The_Value <= The_Range.Max then return True; 
        end if;
end Is_In_Range;    

以下を使用した方がよいでしょう。

function Is_In_Range(The_Value: Value; The_Range: Range)
     return Boolean is
            begin
    return The_Value >= The_Range.Min
        and The_Value <= The_Range.Max;
end Is_In_Range;    

2 つ以上の if ステートメントを含む複雑な式は、読みやすさに影響を及ぼす場合、このように変更してはいけません。

ステートメント

OK アイコン loop ステートメントは以下の場合に名前を持たなければなりません。

Forever: loop
   ...
end loop Forever;    

OK アイコン ループが名前を持つ場合、 そこに含まれる任意の exit ステートメントはそれを指定しなければなりません。

OK アイコン 最初に完了テストを必要とするループは「while」ループ形式を使用しなければなりません。 どこか他の場所で完了テストを必要とするループは一般形式と exit ステートメントを用いなければなりません。

要求アイコン ループ中の exit ステートメントの数を最小限にします。

OK アイコン 配列に対して繰り返す「for」ループでは、 明示的な範囲またはその他のサブ型ではなく、配列オブジェクトに適用される 'Range 属性を使用します。

要求アイコン 任意の ループ非依存コードをループの外に移動します。「コードの巻上げ」は一般的なコンパイラー最適化ですが、 不変のコードが他のコンパイル・ユニットへの呼び出しを行う場合は実行できません。

例:

World_Search:
while not World.Is_At_End(World_Iterator) loop
    ...
Country_Search:
    while not Nation.Is_At_End(Country_Iterator) loop
            declare
        City_Map: constant City.Map := City.Map_Of
            (The_City => Nation.City_Of(Country_Iterator),
             In_Atlas => World.Country_Of(World_Iterator).Atlas);
            begin
        ...    

上記のコードで、「World.Country_Of」への呼び出しはループ依存です (つまり、内部ループで国は不変のままです)。 ただし、多くの場合、コンパイラーは呼び出しをループの外に移動することが禁止されています。 なぜなら、呼び出しはプログラムの実行に影響を及ぼす可能性がある副次作用を持つことがあるからです。したがって、コードはループを通る度に無用に実行されます。

このループは以下のように書き換えると、より効率的で、理解と保守がしやすくなります。

Country_Search:
while not World.Is_At_End(World_Iterator) loop
            declare
        This_Country_Atlas: constant Nation.Atlas
            := World.Country_Of
                    (World_Iterator).Atlas;
            begin
        ...
        City_Search:
        while not Nation.Is_At_End (The_City_Iterator) loop
            declare
                City.Map_Of (
                    The_City => Nation.City_Of
                                        (Country_Iterator),
                    In_Atlas => This_Country_Atlas );
            begin
                ...    

OK アイコン サブプログラムとエントリー呼び出しは名前付き関連を使用しなければなりません。

ただし、最初の (またはただ 1 つの) パラメーターが操作の主要な焦点 (例えば、他動詞の直接目的語など) である場合は、次のようにこのパラメーターについてのみ名前を省略できます。

Subscriber.Delete (The_Subscriber => Old_Subscriber);    

上の例で、Subscriber.Delete は他動詞で、Old_Subscriber は直接目的語です。名前付き関連 The_Subscriber => Old_Subscriber がない以下の式は認められます。

Subscriber.Delete	(Old_Subscriber);
Subscriber.Delete (Old_Subscriber,
                   Update_Database  => True,
                   Expunge_Name_Set => False);
if Is_Administrator (Old_Subscriber) then ...    

パラメーターの意味があまりに明らかなので名前付き関連が読みやすさを損ねるだけという場合もあります。例えば、以下のように、 すべてのパラメーターが同じ型とモードであり、デフォルト値を持たない場合です。

if Is_Equal (X, Y) then ...
Swap (U, B);    

OK アイコン when others は、case ステートメントの中またはレコード型定義 (バリアント用) の中で使用してはいけません。

when others を使用しないことは保守段階で役立ちます。これは個別の型定義を修正する際、常にこれらの構造を無効にすることです。 プログラマーは修正を処理するために行わなければならないことを考えざるをえなくなります。ただし、セレクターが長精度整数である場合は許容されます。

要求アイコン 分岐条件が 不連続な値の場合は、一連の「elsif」ではなく、case ステートメントを使用します。

OK アイコン サブプログラムは復帰の単一点を持たなければなりません。

ステートメント部の終わりでサブプログラムを終了してみてください。関数は単一の return ステートメントを持たなければなりません。関数の本体内にいくつもの return ステートメントを置くことは goto ステートメントの多用と同様に、 コードの解読と保守を困難にします。

プロシージャーは return ステートメントを持ってはいけません。

要求アイコン 複数の return は非常に小さな関数でのみ許されます。これは、以下のように、 すべての return を同時に見渡すことができ、コードの構造が非常に 規則的である場合のみです。

function Get_Some_Attribute return Some_Type is
            begin
    if Some_Condition then
        return This_Value;
else
        return That_Other_Value;
        end if;
end Get_Some_Attribute;    

注意アイコンgoto ステートメントの 使用は制限されます。

「goto」ステートメントの弁護として。goto ラベルの構文や Ada における goto 使用の制約条件は考えられているほどこのステートメントを傷つけないことに注意してください。 また、多くの場合、同等の構造よりも適切で、読みやすく、意味があります (例外と共に作成された偽の goto など)。

コーディングのヒント

要求アイコン 配列を 操作する場合、索引が 1 から始まると仮定しないでください。属性 'Last、'First、'Range を 使用します。

要求アイコン 非制約型の 一般的な制約サブ型を定義します (主としてレコード)。パラメーターや戻り値に それらのサブ型を使用し、クライアント・コード中のセルフ・チェックを向上させます。

type Style is (Regular, Bold, Italic, Condensed);
type Font (Variety: Style) is ...
subtype Regular_Font is Font (Variety => Regular);
subtype Bold_Font is Font (Variety => Bold);
function Plain_Version (Of_The_Font: Font) return Regular_Font;
procedure Oblique (The_Text   : in out Text;
                   Using_Font : in     Italic_Font);
...    

第 8 章

可視性の問題

多重定義と同形異義語

以下のガイドラインを推奨します。

OK アイコン サブプログラムを多重定義します。

ただし、同じ ID を使用する場合、真に同じ種類の操作を意味することを確認してください。

OK アイコン ネストされたスコープ内に同形異義語の ID を隠さないでください。

このようなコードは読む者を混乱させ、保守における潜在的なリスクになるおそれがあります。「for」ループ制御変数の存在とスコープについても注意してください。

OK アイコン サブ型の操作を多重定義しないでください。常に型について行います。

経験の浅い読者が考えることとは反対に、多重定義処理はベースの型とそのすべてのサブ型に適用されます。

例:

subtype Table_Page is Syst.Natural16 range 0..10;
function "+"(Left, Right: Table_Page) return Table_Page;    

コンパイラーは、サブプログラムを照合する際、パラメーターのサブ型ではなくベースの型を探します。したがって、 上記の例で、「+」は、実際 Table_Page だけでなく、 現在のパッケージ中のすべての Natural16 値について再定義されます。そのため、 任意の式「Natural16 + Natural16」は「+」(Table_Page, Table_Page) への呼び出しにマップされます。 これはおそらく間違った結果を返すか、例外を生成します。

コンテキスト節

OK アイコン 「with」節により導入される依存関係の数を最小限にします。

「with」節の使用により可視性が拡張される場合、その節がカバーするコードの範囲をなるべく狭くしなければなりません。 必要な場合にのみ「with」節を使用します。理想的には本体上のみまたは大きな本体スタブ上で使用します。

インターフェース・パッケージを用いて下位エンティティーを再エクスポートすることにより、 多数の下位パッケージを「with」で可視にすることを避けます。これを行うには、派生型、名前変更、スキン・サブプログラムのほか、 おそらく文字列などの定義済み型を使用します (Environment コマンド・パッケージによる実効と同様)。

「with」節を使用してユニット間の結合をハード (強く) にするのではなく、 汎用仮パラメーターを使用してソフト (弱く) にします。

例: 複合型の Put プロシージャーをエクスポートするには、直接 with を用いて Text_Io を扱うのではなく、コンポーネントに対するプロシージャー Put を汎用形式としてインポートします。

OK アイコン「Use」節は 使用してはいけません。

できるだけ「use」節を避けることで読みやすさと判別のしやすさが増します。 ただし、この規則が、コンテキストの使用を効果的にする命名規則と適切な名前変更によって十分にサポートされていることが条件になります (前述の「命名規則」を参照)。また、このことは、特に保守段階で可視性の問題を防ぐのに役立ちます。

文字型を定義するパッケージの場合、この文字型に基づく文字列リテラルを定義するのに必要な任意のコンパイル・ユニットで 「use」節が必要になります。

package Internationalization is
    type Latin_1_Char is (..., 'A', 'B', 'C', ..., U_Umlaut, ...);
    type Latin_1_String is array (Positive range <>) of
            Latin_1_Char;
end Internationalization ;
use Internationalization;
Hello : constant Latin_1_String := "Baba"    

「use」節がないため、挿入形式の演算子の使用を防げます。それらは以下のように、クライアント・ユニットで名前変更できます。

function "=" (X, Y : Subscriber.Id) return Boolean
            renames Subscriber."=";
function "+" (X, Y :Base_Types.Angle) return Base_Types.Angle
            renames Base_Types."+";    

OK アイコン 「use」節の欠如により多数のクライアント・ユニットに同じ名前変更のセットが含まれることが多いので、 それらのすべての名前変更は、定義しているパッケージにネストされるパッケージ Operations により、 定義パッケージ自体に因数分解可能です。パッケージ Operations 上の「use」節はクライアント・ユニットで以下のように推奨されます。

package Pack is
    type Foo is range 1 .. 10;
    type Bar is private;
     ...
    package Operations is
        function "+" (X, Y : Pack.Foo) return Pack.Foo
                renames Pack."+";
        function "=" (X, Y : Pack.Foo) return Boolean
                renames Pack."=";
        function "=" (X, Y : Pack.Bar) return Boolean
                renames Pack."=";
        ...
    end Operations;
private
	...
end Pack;
with Pack;
package body Client is
    use Pack.Operations; -- Operations のみを直接可視にする。
    ...
    A, B : Pack.Foo;    -- まだ接頭辞 Pack が必要。
    ...
    A := A + B ;        -- 「+」は直接可視であることに
                        -- 注意。    

パッケージ Operations は常にこの名前を持たなければならず、 常に定義パッケージの可視部分の一番下に配置しなければなりません。 「use」節は必要な場合にのみ配置しなければなりません。 つまり、よくあるように、仕様中に操作が使用されない場合、「use」節は Client の本体でのみ配置しなければなりません。

with Defs;
package Client is
    ...
    package Inner is
        use Defs;
        ...
    end Inner;		-- use 節のスコープはここで終わる。
    ...
end Client;
            declare
    use Special_Utilities;
            begin
    ...
end;                -- use 節のスコープはここで終わる。    

名前変更

要求アイコン 名前変更宣言を 使用します。

コードを読みやすくするため、「use」節を制限すると共に、名前変更を推奨します。非常に長い名前を持つユニットが何度も参照される場合、 ごく短い名前にすると以下のように読みやすさが向上します。

with Directory_Tools;
with String_Utilities;
with Text_Io;
package Example is
    package Dt renames Directory_Tools;
    package Su renames String_Utilities;
    package Tio renames Text_Io;
    package Dtn renames Directory_Tools.Naming;
    package Dto renames Directory_Tools.Object;
        ...    

OK アイコン 短縮名の選択は、 最小限の意外性原則を守り、プロジェクト全体で一貫性がなければなりません。これを実現する方法は、以下のようにパッケージそのものの中で短縮名を提供することです。

package With_A_Very_Long_Name is package Vln renames
            With_A_Very_Long_Name;
    ...
end
with With_A_Very_Long_Name;
package Example is package Vln renames With_A_Very_Long_Name;
-- ここから Vln は省略語である。   

パッケージの名前変更は名前が変更されたパッケージの可視部にのみ可視性を与えることに注意してください。

OK アイコン インポートされたパッケージの名前変更は 宣言部の最初でグループ化し、アルファベット順に並び替えなければなりません。

要求アイコン 名前変更は、 ローカルで読みやすさを向上させる任意の場所で使用可能です (実行時の不利益は ありません)。型は制限なくサブ型として名前変更できます。

コメントに関するセクションで示しているように、名前変更は、コードを記録するための簡潔で保守可能な方法を提供することがよくあります。 例えば、複雑なオブジェクトに単純な名前を付けたり、型の意味をローカルで詳細化します。名前変更の ID のスコープは混乱を起こさないように選択しなければなりません。

要求アイコン 名前変更の 例外により、例外をいくつかの単位に因数分解できます。例えば、汎用パッケージの すべてのインスタンス化などです。型を派生させるパッケージ中で、派生する サブプログラムにより潜在的に発生する可能性がある例外は、クライアントがオリジナル・ パッケージと「一緒」にならないように、派生型とともに再エクスポートしなければなりません。

with Inner_Defs; 
package Exporter is ... 
procedure May_Raise_Exception; -- Raises exception Inner_Defs.Bad_Schmoldu when ... ... 
Bad_Schmoldu : exception renames Inner_Defs.Bad_Schmoldu; ...

要求アイコン サブプログラムを 「in」パラメーターの異なるデフォルト値で名前変更すると、単純なコード因数分解が 可能になり、読みやすさが増す場合があります。

procedure Alert (Message : String;
                 Beeps   : Natural);
procedure Bip (Message : String := "";
                   Beeps   : Natural := 1)
        renames Alert;
procedure Bip_Bip (Message : String := "";
                   Beeps   : Natural := 2)
        renames Alert;    procedure Message (Message : String;
                   Beeps   : Natural := 0)
        renames Alert;    procedure Warning (Message : String;
                   Beeps   : Natural := 1)
        renames Alert;    

OK アイコン 名前変更宣言の直接のスコープ内で名前変更されたエンティティーの名前 (古い名前) を使用するのは避けます。 名前変更宣言により導入される ID または演算子記号 (新しい名前) のみを使用します。

use 節に関する注意事項

長年に渡って、Ada コミュニティーには「use」節についての論議が交わされてきており、時には宗教戦争の様相を帯びることもありました。 両当事者はともに大規模なプロジェクトに拡張しにくいさまざまな論拠や、現実とかけ離れた、あるいは故意に不公平な事例を用いてきました。

「use」節の支持者は、読みやすさが向上すると主張し、 何度も使用される場合に名前変更による利益が見込まれる、特に読みにくく、冗長な名前を例に挙げます。また、 支持者は Ada コンパイラーが多重定義を解決できるともいいます。 これは事実ですが、大規模な Ada プログラムに没頭している人間はコンパイラーほど確実に多重定義を解決できませんし、 それほど高速にできないのは明らかです。支持者は Rational 環境などの高度な APSE が明示的な完全修飾名を無用にすると主張します。 しかし、これは真実ではありません。 ユーザーは自らが不確かな各 ID について [Definition] を押す必要はないはずです。ユーザーは推測する必要はありませんが、 使用されるオブジェクトと抽象化をすぐに確認できなければなりません。 「use」節の支持者はプログラムの保守におけるその潜在的な危険性を否定し、 そうしたリスクを生み出すプログラマーに落第点を与えることを提案していますが、 われわれは完全修飾名がそのリスクを取り除くと思っています。

「use」節に関する制限の影響を軽減するための上記の提案方法があまりにも多くの入力を要すると思われる場合は、Norman H. Cohen 氏の結論を検討してください。 「プログラムの入力時に節約される任意の時間は、プログラムのレビュー、デバッグ、保守の際に何度も失われることになる」のです。

最後に、大規模なシステムにおいて、「use」節の欠如は、シンボル・テーブルの参照オーバーヘッドを減少させることにより、コンパイル時間を改善します。

use 節の論議に関して興味のある読者は以下の資料を参照してください。

D. Bryan 著 "Dear Ada," Ada Letters, 7, 1, January-February 1987, pp. 25-28.

J. P. Rosen 著 "In Defense of the Use Clause," Ada Letters, 7, 7, November-December 1987, pp. 77-81.

G. O. Mendal 著 "Three Reasons to Avoid the Use Clause," Ada Letters, 8, 1, January-February 1988, pp. 52-57.

R. Racine 著 "Why the Use Clause Is Beneficial," Ada Letters, 8, 3, May-June 1988, pp. 123-127.

N. H. Cohen 著 Ada as a Second Language, McGraw-Hill (1986), pp. 361-362.

M. Gauthier 著 Ada-Un Apprentissage, Dunod-Informatique, Paris (1989), pp. 368-370.]


第 9 章

プログラム構造とコンパイルの問題

パッケージの分解

大きな「論理」パッケージを分解する基本的な方法は 2 つあり、 初期の設計フェーズから、管理、コンパイル、保守、理解が容易な複数の比較的小さな Ada ライブラリー・ユニットが作成されます。

a) ネストされた 分解

この手法は Ada サブユニットまたはサブパッケージに重点を置きます。主なサブプログラム、 タスク本体、内部パッケージ本体は体系的に分割されます。この過程はそれらのサブユニット/サブパッケージの内部で再帰的に繰り返されます。

b) フラットな 分解

論理パッケージは「with」節で相互接続される、より小さなパッケージに分解され、 元の論理パッケージはほとんど再エクスポート・スキン (またはもはや存在しない設計成果物) になります。

各手法にメリットとデメリットがあります。ネストされた分解はコード作成の必要性が少なく、 命名が単純になります (多くの ID は接頭辞が不要)。 また、少なくとも Rational 環境において、構造はライブラリー・イメージで可視であり、変換が容易です (コマンドは Ada.Make_Separate、Ada.Make_Inline)。 フラットな分解は再コンパイルが少なくて済み、構造をより適切または整然にできることがよくあります (特にサブシステム境界で)。 また、再利用も促進します。さらに、自動再コンパイル・ツールや構成管理を使用した管理も容易です。ただし、フラットな分解の場合、 分解中に作成された下位パッケージを「with」で処理することによる、元の設計に対する違反のリスクが高まる危険性があります。

OK アイコン ネストのレベルは、 サブプログラムに対しては 3、パッケージに対しては 2 に制限されます。サブプログラム内でパッケージをネストしないでください。

package Level_1 is
    package Level_2 is
package body Level_1 is
    procedure Level_2 is
        procedure Level_3 is    

要求アイコン 以下の いずれかの場合は、ネストされたユニット (「別の本体」) について本体スタブを 使用します。

宣言部の構成

パッケージ仕様

OK アイコン パッケージ仕様の宣言部に含まれる宣言は以下の順序で配置しなければなりません。

1) パッケージ自体の名前変更宣言

2) インポートされるエンティティーの名前変更宣言

3) 「use」節

4) 名前付きの番号

5) 型とサブ型の宣言

6) 定数

7) 例外宣言

8) エクスポートされるサブプログラム仕様

9) もしあれば、ネストされたパッケージ

10) 密閉型

要求アイコン 複数の 主要な型を導入するパッケージについては、以下のように関連する宣言の複数の セットを持つとよい場合があります。

5) A に対する型とサブ型の宣言

6) 定数

7) 例外宣言

8) A に関する操作についてエクスポートされるサブプログラム仕様

5) B に対する型とサブ型の宣言

6) 定数

7) 例外宣言

8) B に関する操作についてエクスポートされるサブプログラム仕様

その他

要求アイコン 宣言部が 大きい (100 行を超える) 場合、小さなコメント・ブロックを用いて各種の セクションを区切ります。

パッケージ本体

OK アイコン パッケージ本体宣言の宣言部に含まれる宣言は以下の順序で配置しなければなりません。

1) 名前変更宣言 (インポートされるエンティティーについて)

2) 「use」節

3) 名前付きの番号

4) 型とサブ型の宣言

5) 定数

6) 例外宣言

7) ローカルのサブプログラム仕様

8) ローカルのサブプログラム本体

9) エクスポートされるサブプログラム本体

10) もしあれば、ネストされたパッケージ本体

その他の構造

OK アイコン サブプログラム本体、 タスク本体、ブロック・ステートメントなど、その他の宣言部は同じ一般パターンに従います。

コンテキスト節

OK アイコン インポートされるライブラリー・ユニットごとに 1 つの「with」節を使用します。with 節をアルファベット順に並べ替えます。「with」処理されたユニット上の「use」節が適切な場合、 対応する「with」節のすぐ後に続きます。プラグマ Elaborate については下記を参照してください。

詳細化の順序

OK アイコン 特定の効果を実現するために、 ライブラリー・ユニットの詳細化の順序に依存しないでください。

各 Ada 実装は、"Ada Reference Manual"「参考資料 [ISO87]」に記述されている非常に単純な規則を満たすものであれば、 詳細化順序を計算する方針を自由に選択できます。他とくらべて賢い方法を用いている実装もありますし (対応する仕様の後で可能なかぎり速やかに本体を詳細化するなど)、 それほど賢くなく (特に汎用のインスタンス化について)、非常に重大な移植性問題を引き起こす実装もあります。

プログラムの詳細化中に悪名高い「詳細化前のアクセス」エラー (通常は Program_Error 例外が発生) を起こす原因には主に以下の 3 つがあります。

task type T;
type T_Ptr is access T;
SomeT : T_Ptr := new T; -- 詳細化前のアクセス。

OK アイコン ある Ada コンパイラーから別の Ada コンパイラーへアプリケーションを移植する際の問題を回避するために、 プログラマーは、コードを再構築する (常に可能とは限らない) して問題を取り除くか、 以下の方法でプラグマ Elaborate を利用し、明示的に詳細化順序を制御しなければなりません。

以下の場合、ユニット Q のコンテキスト、節でプラグマ Elaborate は「with」節に現れる各ユニット P に適用しなければなりません。

さらに、型 T のオブジェクトの詳細化がパッケージ R 中の関数を呼び出すように、P が型 T をエクスポートする場合、Q のコンテキスト節は以下を含まなければなりません。

with R;
pragma Elaborate (R);    

これは Q の中に R への直接参照がない場合もあてはまります。

実際は、以下のように、パッケージ P が含まなければならない規則を記述する方が容易な場合があります (ただし、常に可能とは限りません)。

with R;
pragma Elaborate (R);    

パッケージ Q については単に以下のようになります。

with P;
pragma Elaborate (P);    

したがって、他動性による適切な詳細化順序が提供されます。


第 10 章

並行性

注意アイコンタスクの使用を制限します。

タスクは非常に強力な機能ですが、慎重に使用する必要があります。空間と時間のオーバーヘッドが大きい場合は、 配慮を欠いたタスクの使用が原因として考えられます。 システムの一部に加えた小さな変更が複数のタスクのセットの生存を完全な危機に陥れ、 資源の枯渇やデッドロックに至る場合があります。プログラムのタスク処理のテストとデバッグは困難です。したがって、 タスクの使用、その配置、相互作用はプロジェクト・レベルの決定になります。タスクが未熟なプログラマーによって隠れたところで使用されたり、 作成されたりすることは許されません。Ada プログラムのタスク処理モデルは可視で、理解可能でなければなりません。

並行ハードウェアの効果的なサポートがなければ、 並行性が真に必要な場合にのみタスクを導入しなければなりません。これは時間に依存するアクションを表す場 合です。定期的なアクティビティーまたはタイムアウトの導入、または割り込みや 外部メッセージの到着といった外部イベントに依存するアクションなどです。 タスクは、共通リソースに対するバッファー、キューイング、ディスパッチ 、同期アクセスといった他のアクティビティーを切り離すためにも導入する必要 があります。

OK アイコン 'Storage_Size 長さ節を用いてタスクのスタック・サイズを指定します。

同じ理由で、また、コレクションが長さ節を持たなければならない同じ状況下で (前述の「アクセス型」のセクションを参照)、 メモリーが貴重なリソースの場合はタスクのサイズを指定しなければなりません。 これを行うには、常にタスクを明示的に宣言された型で宣言します (長さ節は型にのみ適用可能だからです)。スタックを動的にサイジングするために関数呼び出しを行う場合があります。

メモ: 各タスクが必要とするスタックの容量を推測するのは非常に困難な場合があります。これを容易に行うために、 ランタイム・システムは「最高水準」メカニズムを備えることが可能です。

OK アイコン タスク本体中の例外ハンドラーを用いて、 タスクの例外的な停止を回避するか、少なくとも報告します。

例外を処理しないタスクは、たいていの場合は何の通知もなく停止します。実行可能であれば、 停止の本質、特に Storage_Error の報告を試みてください。これによりスタック・サイズの微調整が可能になります。この場合、 割り振り (基本要素 new) を、Storage_Error 以外の例外を再エクスポートする サブプログラム中でカプセル化する必要があることに注意してください。

OK アイコン プログラムの詳細化中にタスクを作成します。

同じ理由で、また、コレクションがプログラム詳細化中に割り振られなければならない同じ状況下で (前述の「アクセス型」のセクションを参照)、 プログラム起動時のごく初期にアプリケーションのタスク処理構造全体を作成しなければなりません。プログラムが数日後に停止してしまうよりは、 メモリーの枯渇により全く起動しない方がましです。

この後の規則の中で、サービス ・タスクとアプリケーション ・タスクは異なります。サービス・タスクは、 小さく、アルゴリズム的に単純なタスクであり、アプリケーション関連タスク間の「接着剤」として使用されます。サービス・タスク (中間タスク) の例としてはバッファー、 トランスポーター、リレー、エージェント、モニターなどがあり、通常、同期、分離、バッファー処理、待ちサービスを提供します。アプリケーション・タスクは、 その名前が示すように、アプリケーションの主要な機能に直接関連しています。

OK アイコン 混合されたタスクを避けます。 アプリケーション・タスクは純粋な呼び出し元として作成しなければならず、サービス・タスクは純粋な呼び出し先として作成しなければなりません。

純粋な呼び出し先は受け入れステートメントと選択的な待ちのみを含み、エントリー呼び出しがないタスクです。

OK アイコン エントリー呼び出しの図式で循環性を避けます。

これによりデッドロックのリスクを大幅に減らすことができます。循環性を完全に無くせない場合は、 少なくともシステムの安定状態では除去します。これら 2 つの規則は構造の読みやすさも向上させます。

注意アイコン 変数の共有を制限します。

隠れた 共有変数に特に注意してください。 例えば、パッケージ本体中に隠れていて、複数のタスクに可視的な基本要素により アクセスされる変数です。共有変数は、共通データ構造に対するアクセスの同期に関して、 コストがあまりに高すぎるという極端な状況で使用可能です。プラグマ Shared が有効であることを確認してください。

注意アイコン abort ステートメントの使用を制限します。

abort ステートメントは、この言語の最も危険で有害な基本要素の 1 つとして一般に認識されています。abort ステートメントを用いて無条件に (かつほとんど非同期に) タスクを終了させると、 指定されたタスク処理構造の動作を推察することがほとんど不可能となります。ただし、abort ステートメントが必要になる状況は非常に限定されています。

例: 下位サービスの一部にはタイムアウトの機能が提供されていません。タイムアウトを導入するただ 1 つの方法は、 補助エージェント・タスクにより提供されるサービスを使用して、エージェントからの応答を待ち (タイムアウトを使用)、 サービスが遅延時間内に提供されない場合に abort を用いてエージェントを kill することです。

abort は、停止する側と停止される側だけが影響を受ける可能性があることを示せれば使用できます。例えば、別のタスクが abort されるタスクを呼び出す可能性が全くない場合。

注意アイコン delay ステートメントの使用を制限します。

タスクを勝手に中断すると、重大なスケジューリングの問題を引き起こす場合があり、そうなると問題の追跡と修正が困難です。

注意アイコン 属性 'Count、'Terminated、'Callable の使用を制限します。

属性 'Count はおおまかな目安としてのみ使用しなければならず、その値がゼロかどうかに基づいてスケジューリングの決定をしてはいけません。なぜなら、待ちタスクの実際の数はこの属性が評価される時刻とその値が使用される時刻との間で変化する場合があるからです。

条件付きのエントリー呼び出し (または accept を持つ同等の構造) を使用して、待ちタスクがないことを確実にチェックします。

select
    The_Task.Some_Entry;
else
    -- 何か別のことを実行する。
end select;    

これは、以下よりも優先されます。

if The_Task.Some_Entry'Count > 0 then
    The_Task.Some_Entry;
else
    -- 何か別のことを実行する。
        end if;

属性 'Terminated は True になる場合のみ、また属性 'Callable は False になる場合のみ意味があるので、 利便性は非常に限定されます。システムのシャットダウン中にタスク間の同期を提供するために使用してはいけません。

注意アイコン優先度の使用を制限します。

Ada における優先度はスケジューリングに対して限定された影響を持ちます。特に、 エントリーを待っているタスクの優先度はエントリー・キューの順位付けまたは選択的な待機を行うためのエントリーの選択について考慮されません。これにより優先度の転換が起こる場合があります (「参考資料 [GOO88]」を参照)。 優先度はスケジューラーによって、 実行するタスクの中から次に実行するタスクを選択するためだけに使用されます。優先度の転換のリスクがあるため、相互排除の目的で優先度に依存しないでください。

エントリーのファミリーを使用することにより、エントリー・キューを複数のサブキューに分割することが可能であり、これにより、緊急性の概念を明示的に導入できることがよくあります。

優先度が必要ない場合は、どのタスクにも優先度を割り当てないでください。

OK アイコン タスクに優先度を割り当てた場合は、 アプリケーション中のすべてのタスクに優先度を割り当てます。

この規則は、プラグマ Priority を持たないタスクの優先度が定義されないので、必要です。

OK アイコン 移植性については、 優先レベルの数を小さく維持します。

サブ型 System.Priority の範囲は実装で定義されます。経験上、 実際に使用可能な範囲はシステムによって大きく異なります。さらに、優先度を集中して定義し、すべてのタスク中で整数リテラルを使用するのではなく、 優先度に名前と定義を設定するのはよい考えです。そうした集中的な System_Priorities パッケージの保有は移植性を容易にし、 前の規則とともに使用することですべてのタスク仕様の特定が簡単になります。

要求アイコン 循環タスク中で 漂流しないようにするには、delay ステートメントをプログラムし、処理時間、 オーバーヘッド、タスク優先使用を考慮します。

Next_Time := Calendar.Clock;
loop
    -- ジョブを実行する。
    Next_Time := Next_Time + Period;
    delay Next_Time - Clock;
end loop;    

Next_Time - Clock は負になる場合があることに注意してください。 これは循環タスクの実行が遅れていることを示します。サイクルを 1 つ落とすことが可能な場合があります。

要求アイコン スケジュール可能性を 保証するには、Rate Monotonic Scheduling アルゴリズム に従って循環タスクに 優先度を割り当てます。つまり、最も頻度の高いタスクに最も高い優先度を割り当てます。 (詳しくは 「参考資料 [SHA90]」を参照してください。)

要求アイコン モニターや バッファーなどの非常に高速な中間サーバーには比較的高い優先度を割り当てます。

ただし、その場合は、これらのサーバーが他のタスクを伴って自分自身をブロックしないことを確認してください。この優先度がプログラムの保守の際に尊重されるように、 コード中に記録します。

要求アイコン 「ジッター」の 影響を最小化するには、期間そのものではなく、タイム・スタンプする入力サンプル または出力データに依存します。

OK アイコン ビジーな待機 (ポーリング) を避けます。

タスクがむやみに何か実行すべきことをチェックするのではなく、遅延するか、選択またはエントリー呼び出しを用いて待機することを確認してください。

要求アイコン 各ランデブーについて、 少なくとも一方が待機し、一方のみが条件付きエントリー呼び 出しまたは 時間付きエントリー呼び出しを持つか、待機することを確認してください。

そうでない場合、特にループで、コードが競合状態になるリスクがあり、 ビジー待機とよく似た状態になります。このリスクは優先度の貧弱な使用により増大する可能性があります。

要求アイコン タスクを カプセル化する場合、それらの特徴の一部の可視性を高めておくようにしてください。

エントリー呼び出しがサブプログラム中で隠れている場合、 それらのサブプログラムの仕様を読む者がこのサブプログラムへの呼び出しがブロックする可能性があると気付くようにしてください。 さらに、待機に境界があるかどうかを指定します。ある場合は、上限の予測を提供します。命名規則を用いて、 可能性のある待機を指定します (前述の「サブプログラム」を参照)。

パッケージの詳細化、サブプログラムの呼び出し、汎用ユニットのインスタンス化がタスクをアクティブ化する場合、この事実がクライアントに可視になるようにします。

package Mailbox_Io is
    -- このパッケージは
    -- 外部メールボックスへのすべてのアクセスを
    -- 同期化する内部 Control タスクを詳細化する。
    procedure Read_Or_Wait
        (Name: Mailbox.Name; Mbox: in out Mailbox.Object);
        --
        -- ブロッキング (無限待機)。    

OK アイコン 選択的待機中のエントリー選択について、 特定の順序に依存しないでください。

エントリーにキューされたタスクの選択に何らかの公平さが必要な場合、 必要な順序で待機無しのキューを明示的にチェックした後、すべてのエントリー上で待機します。'Count を使用しないでください。

OK アイコン 同じ宣言部中で詳細化されたタスクについて、 特定のアクティベーション順序に依存しないでください。

特定の起動順序を探す場合は、特別な起動エントリーを持つランデブーを作成することにより実現しなければなりません。

OK アイコン タスクを正常に終了するように実装します。

アプリケーションの性質により一度アクティブ化されたタスクが永久に実行することが必要ないのであれば、タスクは、正常な完了に達するか、 終了の代替方法によって終了しなければなりません。これはマスターがライブラリー・レベルのパッケージについて実現不可能な場合があります。 なぜなら、"Ada Reference Manual" に終了の条件が規定されていないからです。

マスター依存の構造により整然とした終了ができない場合、タスクは、システムのシャットダウン中に呼び出される特別なシャットダウン・エントリーを提供し、待機しなければなりません。


第 11 章

エラー処理と例外

一般的な考え方として、例外はエラー (論理エラーとプログラミング・エラー、構成エラー、データ破損、リソースの枯渇など) に対してだけ使用します。一般的な規則は、通常の条件や、過負荷やハードウェア障害がない状態では、システムは例外を発生しないということです。

要求アイコン 例外を 使用して、論理エラーやプログラミング・エラー、構成エラー、データ破損、 リソースの枯渇を処理します。適切なログ・メカニズムにより、発生した位置を含め、できるだけ早く例外を報告します。

要求アイコン 特定の 抽象化からエクスポートされる例外の数を最小限にします。

大規模システムでは、各レベルで多数の例外を処理する必要があるため、コードの可読性や保守容易性が低下します。 例外処理によって、通常の処理が妨げられる場合もあります。

例外の数を最小限にする方法はいくつかあります。

OK アイコン 設計中に指定されない例外を伝えないでください。

OK アイコン 捕捉された 例外が再発生しないのであれば、例外ハンドラー中で when others 代替を 避けます。

これにより、このレベルで処理不可能な例外に干渉することなく、ローカルの内部処理ができます。

exception
    when others =>
        if Io.Is_Open (Local_File) then
            Io.Close (Local_File);
        end if;
        raise;
end;    

when others 代替を使用できる可能性があるもう 1 つの場所はタスク本体の最後です。

OK アイコン 発生頻度が高いと予想されるイベントに対して例外を使用しないようにします。

例外を使用して明らかにエラーでない状態を表すと、次のような不利益があります。

例えば、関数によって返される余分な値 (検索における Value_Not_Found など) の形では、例外を使用しないでください。 また、「out」パラメーターを持つプロシージャーを使用するか、Not_Found を表す特別な値を導入したり、返されるタイプを Not_Found の判別を持つレコードにパックします。

OK アイコン 例外を使用して制御構造を実装しないようにします。

これは、前の規則の特殊な場合です。例外を、「goto」ステートメントの形で使用しないでください。

要求アイコン 定義済みの 例外を捕捉する場合、それを発生させる構成の周りのごく小さなフレームに ハンドラーを配置します。

Constraint_Error、Storage_Error、などの定義済み例外はさまざまな場所で起こることがあります。こうした例外を特定の理由により捕捉する必要がある場合、 ハンドラーは以下のようになるべく限定されたスコープになければなりません。

            begin
    Ptr := new Subscriber.Object;
exception
    when Storage_Error =>
        raise Subscriber.Collection_Overflow;
end;    

OK アイコン 例外ハンドラーの終了は、 「return」ステートメントまたは「raise」ステートメントのいずれかを持つ関数中で行います。 そうでないと、呼び出し側で Program_Error 例外が発生します。

注意アイコンチェックの停止を制限します。

今日の Ada コンパイラーでは、チェックの停止によって得られる、潜在的なコード・サイズの削減と性能の向上はほんのわずかです。 したがって、チェックの停止は、性能のボトルネックとして識別される (測定による) ごく限られたコードの断片に制限しなければなりません。 システム全体に広く適用してはいけません。

当然ながら、後でだれかがチェック停止の決定を下すというありそうにない事態のためだけに余分である明示的な範囲および判別式のチェック処理を追加しないでください。 Ada の組み込み制約チェック機能を信用してください。

要求アイコン 例外を その宣言のスコープ外に伝えないでください。

これを行うと、クライアント・コードが明示的に例外を処理できなくなります。代わりに when others 代替を用いますが、これも十分に具体的でない場合があります。

この規則の当然の結果として、派生による型の再エクスポートの際、例えば名前変更により、 派生したサブプログラムが発生させる可能性がある例外の再エクスポートを考えてください。 そうでない場合、クライアントはもとの定義パッケージを「with」処理しなければなりません。

要求アイコン Numeric_Error と Constraint_Error は常に一緒に処理します。

Ada Board は、Numeric_Error を発生させるすべての状況で Constraint_Error を代わりに発生させなければならないと決定しています。

要求アイコン ステータス・ コードが適切な値を持つことを確認します。

サブプログラムが返したステータス・コードを「out」パラメーターとして使用する場合は、 サブプログラム本体の最初の実行可能ステートメントで、「out」パラメーターに必ず値を割り当てます。 規則的に、すべてのステータスをデフォルトで成功、またはデフォルトで失敗にします。例外処理を含め、サブプログラムが終了する可能性のある箇所をすべて考察します。

要求アイコン 安全性の チェックはローカルで行うようにし、クライアントが行うようにしてはいけません。

適切な入力を与えなければ、サブプログラムが間違った出力を生成する可能性がある場合は、 管理された方法で無効な入力を検出して通知するコードを、サブプログラム側に作成します。クライアントに適切な値を渡すように、 コメントで指示することはあてになりません。遅かれ早かれコメントが無視されるようになるのはほぼ確実であり、 無効なパラメーターが検出されないとデバッグの困難なエラーが発生します。

詳しくは、「参考資料 [KR90b]」を参照してください。


第 12 章

低レベル・プログラミング

このセクションでは、結果として移植性を損なう Ada 機能について説明します。それらは「Reference Manual for the Ada Programming Language」(参考資料 [ISO87]) の第 13 章で定義されていて、 コンパイラー別の機能は Ada コンパイラー・ベンダーにより提供される「付録 F」に記述されています。

表現節と属性

要求アイコン「Ada Reference Manual」の 付録 F を注意深く調べてください (また、十分理解していることを確認するために 小規模なテストを実行します)。

注意アイコン表現節の使用を制限します。

表現節は、複数の実装について統一的にサポートされません。表現節の使用には多数の落とし穴があります。したがって、システム中で勝手に使用してはいけません。

表現節は以下を行います。

表現節は以下のような状況で避けることが可能です。

例:

次の例を考えてください。

type Foo is (Bla, Bli, Blu, Blo);
for Foo use (Bla => 1, Bli =>3, Blu => 4, Blo => 5);    

type Foo is (Invalid_0, Bla, Invalid_2, Bli, Blu, Blo);    

OK アイコン 表現節を持つ型を明らかに実装に依存するコードを含むものとして識別されるパッケージにグループ化します。

OK アイコン レコード・レイアウト中に特定の順序を仮定しないでください。

OK アイコン レコード表現節の中では、 常にすべての判別式の配置を指定します。また、これはバリアントのすべてのコンポーネントを指定する前に実行します。

OK アイコン 調整節を避けます。

コンパイラーが適切に動作することを信頼します。コンパイラーはターゲットの調整制約を認識しています。プログラマーが調整節を使用すると、 後で調整競合が起こる可能性があります。

要求アイコン 制約されない 複合型にコンパイラーが生成するフィールドが存在することに注意してください。

レコード中: 動的フィールドのオフセット、変形節索引、制約されるビット、など

配列中: ドープ・ベクター

コンパイラーの詳細については付録 F を参照してください。「Ada Reference Manual」(参考資料 [ISO87]) の第 13 章の記述をあてにしないでください。

チェックされない変換

注意アイコン Unchecked_Conversion の使用を制限します。

Unchecked_Conversion のサポート範囲は Ada コンパイラーにより異なり、厳密な動作は、特に複合型とアクセス型に適用される場合に若干異なる場合があります。

OK アイコン Unchecked_Conversion のインスタンス化の中で、 ソースとターゲットの型が制約され、同じサイズであることを確認してください。

これは何らかの限定された移植性を実現し、ドープ・ベクターなどの実装で追加された情報に関する問題の発生を防ぐためのただ 1 つの方法です。 両方の型が同じサイズを持つことを確実にする方法の 1 つは、レコード表現節を持つレコード型に「ラップ」することです。

型を制約にする方法の 1 つは、制約が事前に計算される場合、「スキン」関数中でインスタンス化を行うことです。

要求アイコン 値またはタスクにアクセスするために Unchecked_Conversion を適用しないでください。

これはすべてのシステムでサポートされないだけでなく (例えば Rational 固有 コンパイラーなど)、 以下を仮定にしてもいけません。


第 13 章

まとめ

このセクションでは注意すべき最重要事項を要約します。

制限される機能 (注意アイコン):

絶対禁止事項 (要求アイコン)


参考資料

このマニュアルは「Ada Guidelines: Recommendations for Designer and Programmers」Application Note #15, Rev. 1.1, Rational, Santa Clara, Ca., 1990 [KR90a] から直接導き出されました。ただし、 このほかにも詳細な情報を扱う多数の文献があります。

BAR88 B. Bardin & Ch. Thompson 著 "Composable Ada Software Components and the Re-export Paradigm", Ada Letters, VIII, 1, Jan.-Feb. 1988, p.58-79.

BOO87 E. G. Booch 著 Software Components with Ada, Benjamin/Cummings (1987)

BOO91 Grady Booch 著 Object-Oriented Design with Applications, Benjamin-Cummings Pub. Co., Redwood City, California, 1991, 580p.

BRY87 D. Bryan 著 "Dear Ada," Ada Letters, 7, 1, January-February 1987, pp. 25-28.

COH86 N. H. Cohen 著 Ada as a Second Language, McGraw-Hill (1986), pp. 361-362.

EHR89 D. H. Ehrenfried 著 Tips for the Use of the Ada Language, Application Note #1, Rational, Santa Clara, Ca., 1987.

GAU89 M. Gauthier 著 Ada-Un Apprentissage, Dunod-Informatique, Paris (1989), pp. 368-370.

GOO88John B. Goodenough and Lui Sha 著 "The Priority Ceiling Protocol," special issue of Ada Letters, Vol., Fall 1988, pp. 20-31.

HIR92 M. Hirasuna 著 "Using Inheritance and Polymorphism with Ada in Government Sponsored Contracts", Ada Letters, XII, 2, March/April 1992, p.43-56.

ISO87 Reference Manual for the Ada Programming Language, International Standard ISO 8652:1987.

KR90a Ph. Kruchten 著 Ada Guidelines: Recommendations for Designer and Programmers, Application Note #15, Rev. 1.1, Rational, Santa Clara, Ca., 1990.

KR90b Ph. Kruchten 著 "Error-Handling in Large, Object-Based Ada Systems," Ada Letters, Vol. X, No. 7, (Sept. 1990), pp. 91-103.

MCO93 Steve McConnell 著 Code Complete-A Practical Handbook of Software Construction, Microsoft® Press, Redmond, WA, 1993, 857p.

MEN88 G. O. Mendal 著 "Three Reasons to Avoid the Use Clause," Ada Letters, 8, 1, January-February 1988, pp. 52-57.

PER88 E. Perez 著 "Simulating Inheritance with Ada", Ada letters, VIII, 5, Sept.-Oct. 1988, p. 37-46.

PLO92 E. Ploedereder 著 "How to program in Ada 9X, Using Ada 83", Ada Letters, XII, 6, November 1992, pp. 50-58.

RAC88 R. Racine 著 "Why the Use Clause Is Beneficial," Ada Letters, 8, 3, May-June 1988, pp. 123-127.

RAD85 T. P. Bowen, G. B. Wigle & J. T. Tsai 著 Specification of Software Quality Attributes, Boeing Aerospace Company, Rome Air Development Center, Technical Report RADC-TR-85-37 (3 volumes).

ROS87 J. P. Rosen 著 "In Defense of the Use Clause," Ada Letters, 7, 7, November-December 1987, pp. 77-81.

SEI72 E. Seidewitz 著 "Object-Oriented Programming with Mixins in Ada", Ada Letters, XII, 2, March/April 1992, p.57-61.

SHA90 Lui Sha and John B. Goodenough 著 "Real-Time Scheduling Theory and Ada," Computer, Vol. 23, #4 (April 1990), pp. 53-62.)

SPC89 Software Productivity Consortium: Ada Quality and Style-Guidelines for the Professional Programmer, Van Nostrand Reinhold (1989)

TAY92 W. Taylor 著 Ada 9X Compatibility Guide, Version 0.4, Transition Technology Ltd., Cwmbran, Gwent, U.K., Nov. 1992.

WIC89 B. Wichman 著 Insecurities in the Ada Programming Language, Report DITC137/89, National Physical Laboratory (UK), January 1989.


用語集

このマニュアルの中で用いられている用語のほとんどは 「Reference Manual for the Ada Programming Language」(参考資料 [ISO87]) の付録 D で定義されています。 その他の用語については以下に定義しています。

ADL: Ada as a Design Language。設計の各側面を表現するための Ada の使用方法を指します。PDL または Program Design Language (プログラム設計言語) ともいいます。

環境: 使用する Ada ソフトウェア開発環境。

ライブラリー・スイッチ: Rational 環境において、プログラム・ライブラリー全体に適用されるコンパイル・オプション。

モデル界: Rational 環境において、統一的なプロジェクト規模のライブラリー・スイッチ設定を捕捉するために使用される特殊なライブラリー。

可変: 判別式がデフォルト値を持つレコードの特性。可変型のオブジェクトにはその型の任意の値を割り当てることができます。判別式、したがって構造を変更する値も可能です。

スキン: 本体がリレーとしてのみ動作するサブプログラム。理想的にはただ 1 つのステートメントで構成されます。 同一のパラメーター・セットまたはパラメーターに対して変換可能なパラメーターを持つ、別のサブプログラムへの呼び出し。

PDL: Program Design Language (プログラム設計言語)。