Delphi の例外処理〔裏〕

# はじめに

先日『[Delphi の例外処理](https://qiita.com/ht_deko/items/3e8c9822e7c1de1e552d)』という記事を書きましたが、今回はその番外編となります。
Delphi の例外処理の~~パクリ元~~...じゃなかった、何からインスパイアされたのかを探る記事です。

# 元ネタ

**Delphi** の例外処理の元ネタは **Ada** だと思われます。

## ■ Ada の例外処理

例外処理を行うには `Exceptions` モジュールが必要です。

```ada
With Ada.Exceptions; Use Ada.Exceptions;
```

### 例外型の宣言
例外用の変数を用意する必要があります。

```ada
  EExcepton: exception;
```

### raise 文

```ada
raise EExcepton with "Error Message";
```

**with** 以降は省略可能です。

### 例外文

大雑把に言えば

```ada
  begin
    -- 文リスト
  exception
    -- 例外ブロック
  end;
```

となります。**例外ハンドラ**は

```ada
when [識別子 ":"] 例外型識別子 {"|" 例外型識別子} => 文
```

となります。`例外型識別子` の部分には **others** というキーワードを使う事もできます。具体的なコードは次のようになります。

```ada:test.adb
With Ada.Text_IO; Use Ada.Text_IO;  
With Ada.Integer_Text_IO; Use Ada.Integer_Text_IO;
With Ada.Exceptions; Use Ada.Exceptions;
 
procedure Program is
  EExceptonA, EExceptonB, EExceptonC, EExceptonD: exception;
begin
  -- 任意の処理
  begin
    raise EExceptonA with "Excepton Message"; -- ここを EExceptonB / C / D とかに変えてみてね
  exception
    when EExceptonA | EExceptonB =>
      Put_Line("Excepton A or B"); 
    when EExceptonC =>
      Put_Line("Excepton C");
    when E: others =>
      Put_Line(Exception_Message(E)); 
      raise;
   end;
end Program;
```

例外型を `| (or)` で結合できる事以外は **Delphi** の例外処理とよく似ていますね。

※ 上記コードは [IDEONE](https://ideone.com/iQqOHp) で試す事ができます。

## ■ Turbo Modula-2 の例外処理
**Modula-2** の言語仕様には例外処理が含まれていないのですが、**Turbo Modula-2** [^1] には独自拡張として例外処理が追加されています。**Ada** の例外処理のサブセットみたいな感じです。

### 例外の宣言
例外はあらかじめメインブロックの外で宣言しておく必要があります。

```
例外宣言 = 
  "EXCEPTION" 識別子 {"," 識別子} .
```

**Turbo Pascal** や **Delphi** のラベル宣言のようなものです。

```pascal
MODULE Program1;

EXCEPTION 
  EExceptonA, EExceptonB, EExceptonC, EExceptonD;

BEGIN
  
END Program1.
```

### RAISE 文

```pascal
RAISE EExceptonA , 'Excepton Message';
```

カンマ 以降は省略可能です。

### 例外文
**Turbo Modula-2** の例外文は **Turbo Pascal** や **Delphi** の **Initialization** セクションのようなもので、モジュールやルーチンの最後に例外ブロック (**EXCEPTION** セクション) が置かれます。**Ada** とは異なり、例外処理する領域としない領域を分ける事はできません。

```
例外ハンドラ = 
  "EXCEPTION" 例外 ["|" 例外 ]
  [ "ELSE" 文 ] .
```

ちょっと混乱しますが、**Turbo Modula-2** では **EXCEPTION** セクションを`例外ハンドラ`と呼ぶようです。

```pascal
MODULE Program1;

EXCEPTION 
  EExceptonA, EExceptonB, EExceptonC, EExceptonD;

BEGIN
  
EXCEPTION
  （* 例外ブロック *)
END Program1.
```

例外ブロックで処理されなかった例外は **ELSE** セクションで処理できます。

```pascal
MODULE Program1;

EXCEPTION 
  EExceptonA, EExceptonB, EExceptonC, EExceptonD;

BEGIN
  
EXCEPTION
  （* 例外ブロック *)
ELSE
  （* 未処理例外 *)
END Program1.
```

**例外ハンドラ**は次のようになります。

```
例外 = 
  識別子リスト ":" 文 .   

識別子リスト = 
  識別子 {"," 識別子} .
```

ちょっと混乱しますが、**Turbo Modula-2** では例外ハンドラを`例外`と呼ぶようです。

**Modula-2** の **CASE** 文によく似ており、カンマで区切って複数の例外を指定する事も出来ます。

```pascal:Program1.mod
MODULE Program1;

EXCEPTION 
  EExceptonA, EExceptonB, EExceptonC, EExceptonD;

BEGIN
  RAISE EExceptonA , 'Excepton Message';
EXCEPTION
  EExceptonA, EExceptonB:
    WRITELN('Excepton A or B')|
  EExceptonC:
    WRITELN('Excepton C');
ELSE
  WRITELN('Excepton Others');
END Program1.
```

CP/M-80 版の **Turbo Modula-2** にもちゃんと例外処理が実装されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/44209a7c-03d3-8c52-16d1-8a5151e9675e.png)
**恐るべし、Borland！**

# おわりに

**Delphi** の例外型はクラスなので、派生によってグループ化ができます。このため「例外を **Ada** のように`or 結合` したり **Turbo Modula-2** のように `カンマ区切り` できなくとも問題はない」といった判断だったのかもしれませんね。


**See also:**

 - [Ada (Wikipedia)](https://ja.wikipedia.org/wiki/Ada)
 - [Modula-2 (Wikipedia)](https://ja.wikipedia.org/wiki/Modula-2)
 - [DelphiとPascal - 25年の歴史 (Embarcadero)](https://embarcadero.com/jp/delphi-stories/25-years-of-delphi-and-history-of-pascal)

[^1]: PIM3 準拠。