<11> 手続きと関数 (標準 Pascal 範囲内での Delphi 入門)〔裏〕

# 11. 手続きと関数

**Modula-2** だと、結果を返しても返さなくても `PROCEDURE` です。

## 11.1. 手続き (Procedures)

### 11.1.1. パラメータリスト (パラメータ並び / Parameter list)

#### ・パラメータと引数

JIS X 3008:1994 ではパラメータの事を `引数` としていますが、元となった規格の ISO/IEC 7185:1990 では `Parameter` となっています。


|  | Pascal | 他言語 | 用語 |
|:---|:-:|:-:|:-:|
| 定義で渡されるもの | 仮パラメータ | 仮引数 | パラメータ |
| 呼び出しで渡されるもの | 実パラメータ | 実引数 | 引数 |


次の `x` は Pascal では `仮パラメータ` です。他言語では `仮引数` と呼ばれます。

```pascal
function f(x: Integegr): Integer;
```

次の `2` は Pascal では `実パラメータ` です。他言語では `実引数` と呼ばれます。

```pascal
v := f(2);
```

`仮 (formal-)` とか `実 (actual-)` という言葉を使わない場合、前者が `パラメータ` で、後者が `引数` となります。上のコードだと **「パラメータ `x` に渡された、引数 `2`」** という事になります。

**See also:**

 - [標準 Pascal の規格票と解説書を読んでみる (Qiita)](https://qiita.com/ht_deko/items/091661d6fa3d72700a56)

#### ・定数パラメータ
定数パラメータは Borland Pascal / Turbo Pascal 7.0 で導入されています。

### 11.1.2. 整合配列パラメータ (Conformant array parameters)

#### ・ANSI Pascal 

**ANSI Pascal** は **標準 Pascal (ISO 7185:1983) 水準 0** 相当の規格です。

整合配列パラメータは名前等価の考え方から外れている気がして、個人的には好きではありません。

**See also:**

 - [標準 Pascal の規格票と解説書を読んでみる (Qiita)](https://qiita.com/ht_deko/items/091661d6fa3d72700a56)

### 11.1.3. 再帰手続き (Recursive procedures)

### 11.1.4. 手続きパラメータ (Procedural parameters)

#### ・手続きパラメータに標準手続きを渡せない根拠
ISO/IEC 7185 および JIS X 3008 には「[標準手続き](https://qiita.com/ht_deko/items/15b27e00fac9d723d9f0#%E6%A8%99%E6%BA%96%E6%89%8B%E7%B6%9A%E3%81%8D-required-procedures)を実手続きパラメータとして渡す事は出来ない」とはどこにも書かれていないように思えるのですが、

> 6.6.3.4 Procedural parameters The actual-parameter (中略) shall be a procedure-identifier that has a defining-point contained by the program-block. 

> 6.6.3.4 手続き引数 実引数 (中略) は，手続き名でなければならない。この手続き名の定義位置は，プログラムブロックに含まれていなければならない。

とあります [^1]。[標準手続き](https://qiita.com/ht_deko/items/15b27e00fac9d723d9f0#%E6%A8%99%E6%BA%96%E6%89%8B%E7%B6%9A%E3%81%8D-required-procedures)はプログラムブロック内で定義されていないため、[標準手続き](https://qiita.com/ht_deko/items/15b27e00fac9d723d9f0#%E6%A8%99%E6%BA%96%E6%89%8B%E7%B6%9A%E3%81%8D-required-procedures)を実手続きパラメータとして渡す事はできません。

名前等価の考え方で行くと Delphi の手続き型を使ったやり方の方がスマートに思えます。

### (11.1.5.) オープン配列パラメータ (Open Array Parameters)

#### ・オープン配列パラメータの由来

オープン配列パラメータは **Modula-2** 由来です。High() 関数も **Modula-2** 由来ですが、**Modula-2** には LOW() 関数はありません。**Modula-2** のオープン配列パラメータの配列は常に 0 から始まるため LOW() は不要なのです。

オープン配列パラメータは Borland Pascal / Turbo Pascal 7.0 で導入されています。

**See also:**

 - [割と簡単に ’標準 Modula-2 / Oberon-2' を試してみたい (Qiita)](https://qiita.com/ht_deko/items/8e8be01f749915167a91)

#### ・Slice() 関数
`Slice()` は**オープン配列パラメータに直接渡す用途でのみ使える**特殊な関数です。

```pascal
program Solve;
var
  SliceMe: array [1..200] of Integer;

  procedure TakesArray(x: array of Integer);
  begin
  end;

begin 
  TakesArray(SLICE(SliceMe, 5));
end.
```

**See also:**

 - [System.Slice (DocWiki)](http://docwiki.embarcadero.com/Libraries/ja/System.Slice)

### (11.1.6.) 型可変オープン配列パラメータ (Variant Open Array Parameters)

### (11.1.7.) オープン配列コンストラクタ (Open Array Constructors)

### (11.1.8.) 型なしパラメータ (Untyped Parameters)

型なしパラメータは Turbo Pascal で導入されています。

### (11.1.9.) オープン文字列パラメータ (Open String Parameters)

### (11.1.10.) デフォルトパラメータ (Default Parameters)

ルーチンのデフォルトパラメータは Delphi 4 以降で利用可能です。

### (11.1.11.) ルーチンのオーバーロード (Overloading Routines)

ルーチンのオーバーロードは Delphi 4 以降で利用可能です。

### (11.1.12.) Exit() 手続き


#### ・Exit (Super Pascal の場合)
A.V. エイホらの『データ構造とアルゴリズム』で使われている疑似言語 **Super Pascal** では、同様の機能を持つ return() 文が使える事になっています。

#### ・Exit (Modula-2 の場合)
Exit() 手続きは **Modula-2** にもありますが、意味合いが異なります。

|  | Pascal | Modula-2 |
|:-:|:-:|:-:|
| Exit() / EXIT  | ルーチンから抜ける  | **LOOP～END** を抜ける |
| RETURN()  | N/A | ルーチンから抜ける |

**See also:**

 - [データ構造とアルゴリズム - 培風館の Pascal 関連書籍を読んでみる (Qiita)](https://qiita.com/ht_deko/items/65e84a12e0203da77337#%E3%83%87%E3%83%BC%E3%82%BF%E6%A7%8B%E9%80%A0%E3%81%A8%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0)


### (11.1.13.) Halt() 手続き

#### ・Halt (Modula-2 の場合)
Halt() 手続きは **Modula-2** にもありますが、**Modula-2** の HALT() にはパラメータがありません。

**See also:**

 - [割と簡単に ’標準 Modula-2 / Oberon-2' を試してみたい (Qiita)](https://qiita.com/ht_deko/items/8e8be01f749915167a91)

## 11.2. 関数 (Functions)

### 結果型 (Result Type)

### 結果 (Result)

#### ・Result 変数の由来

Result 変数は **Eiffel** 由来のようです。

#### ・結果 (UCSD Pascal の場合)
パラメータを受け取る Exit() 手続き自体は **UCSD Pascal** でも実装されていましたが、受け取るパラメータはルーチンでした。逆にパラメータのない Exit() はありませんでした。

```pascal
function Add(A, B: integer): Integer;
begin
  Add := A + B;
  Exit(Add);
end;
```

#### ・結果 (拡張 Pascal の場合)
**拡張 Pascal** では結果を保持する変数名を指定できます。ユーザー定義の Result 変数のようなものです。

```pascal
function Add(A, B: integer) = i: Integer;
begin
  i := A + B;
end;
```

**See also:**

 - [UCSD Pascal を触るためだけの UCSD p-System 操作ガイド (Qiita)](https://qiita.com/ht_deko/items/50c0cb0fd3cbafc1f8e1)
 - [ISO/IEC 10206:1991 Extended Pascal (ISO)](https://www.iso.org/standard/18237.html)

### 関数呼び出し (Function Call)

### 再帰関数 (Recursive functions)

### 11.2.1. 関数パラメータ (Functional parameters)

#### ・関数パラメータに標準関数を渡せない根拠

ISO/IEC 7185 および JIS X 3008 には「[標準関数](https://qiita.com/ht_deko/items/15b27e00fac9d723d9f0#%E6%A8%99%E6%BA%96%E9%96%A2%E6%95%B0-required-functions)を実関数パラメータとして渡す事は出来ない」とはどこにも書かれていないように思えるのですが、

> 6.6.3.5 Functional parameters The actual-parameter (中略) shall be a function-identifier that has a defining-point contained by the program-block. 

> 6.6.3.5. 関数引数 実引数 (中略) は，関数名でなければならない。この関数の定義位置は，プログラムブロックに含まれていなければならない。

とあります [^1]。[標準関数](https://qiita.com/ht_deko/items/15b27e00fac9d723d9f0#%E6%A8%99%E6%BA%96%E9%96%A2%E6%95%B0-required-functions)はプログラムブロック内で定義されていないため、[標準関数](https://qiita.com/ht_deko/items/15b27e00fac9d723d9f0#%E6%A8%99%E6%BA%96%E9%96%A2%E6%95%B0-required-functions)を実関数パラメータとして渡す事はできません。

名前等価の考え方で行くと Delphi の手続き型を使ったやり方の方がスマートに思えます。

### 11.2.2. 副作用 (Side effect)


## 11.3. 前方宣言 (Forward declaration)

Turbo Pascal の **forward** は 1.0～5.5 までは予約語でした。6.0 で指令になったようです。

**See also:**

 - [標準 Pascal と Turbo Pascal と Delphi の forward 指令 (Qiita)](https://qiita.com/ht_deko/items/8c51df5fbf5bc8c91d96)

## (11.4.) インライン展開 (Inline expansion)

## (11.5.) 手続き型 (Procedural Types)

#### ・手続き型の由来

手続き型 (Procedural Types) は **Modula-2** の手続き型 (Procedure Type) 由来だと思われます。

#### ・() の省略できないパラメータのない関数

[11.1.1.節](https://qiita.com/ht_deko/items/b93ac03bfee002f17137#1111-%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%83%AA%E3%82%B9%E3%83%88-%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E4%B8%A6%E3%81%B3--parameter-list)に次のような記述がありますが、例外があります。

```
パラメータのないルーチンの呼び出しでは ( ) を省略できます。
```

例えば次のような場合です。

```Pascal:ProcTypes.dpr
program ProcTypes;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  SW: Boolean;
  Proc: TProcedure;

procedure ProcA;
begin
  Writeln('A');
end;

procedure ProcB;
begin
  Writeln('B');
end;

function Func: TProcedure;
begin
  if SW then
    result := ProcA
  else
    result := ProcB;
end;

begin
  SW := True;
  Proc := Func;   // NG: 手続き型 Proc への Func の代入
  Proc := Func(); // OK: Func の実行結果の代入
  Proc;
end.
```

手続き型を返し、パラメータのない関数では `()` を省略できません。

### (11.5.1.) 手続き型定数とグローバル手続き型変数の初期化

# 索引
[:ramen:](https://qiita.com/ht_deko/items/b93ac03bfee002f17137) [ [← 10. ポインタ型〔裏〕](https://qiita.com/ht_deko/items/3be4294e82653fb234c4) ] [ [↑ 目次へ](https://qiita.com/ht_deko/items/46fcdbb11cdc58872160) ] [ [→ 12. テキストファイルの入出力〔裏〕](https://qiita.com/ht_deko/items/bbbd35ac89dfb2268c88) ]


[^1]: 『ISO/IEC 7185:1990』および『JIS X 3008:1994』より引用。