Object Pascal "超" 強い静的型付け⾔語の魅⼒
ODC 2022 - D会場
Learn Languages 2022

2022/09/03 初版 細川 淳

アジェンダ• 今回は型を切り⼝に Object Pascal を紹介します。
• ⾃⼰紹介• 最近の Delphi の紹介• Pascal の紹介– 概要・歴史– 型の紹介• Object Pascal の紹介– 概要・歴史– 型の紹介• 動的な型の導⼊
Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 2

⾃⼰紹介

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 3

⾃⼰紹介• 細川 淳– 株式会社シリアルゲームズ 取締役– Embarcadero MVP (Delphi MVP)
– Twitter: @pik

東京ゲームショウ2022

ビジネス ソリューション コーナー

4-N33

– 技術領域• Windows / macOS / iOS / Android• 画像処理• 通信処理• UI / UX 研究– 好きな⾔語• Object Pascal• C#• Dart
シリアルゲームズ公式キャラクター
シリア

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 4最近の Delphi の紹介

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 5最近の Delphi• 最近の Delphi

Delphi で作ったモバイルアプリ– 開発販売はエンバカデロ・テクノロジーズ（Embarcadero Technologies)
ウェルカムページ
設計画⾯

Delphi で開発できるプラットフォーム
・Windows
・macOS・Linux・iOS・Android
Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 6

最近の Delphi• 最近の Object Pascal を使える唯⼀と⾔って良い環境– FreePascal など他にも Object Pascal を使える⾔語はありますがDelphi の後追いになります• 無料の Community Edition があります– ライセンス違反が多かったため現在 Community Edition は１つ前のバージョン 10.4 が提供されています• 興味を持ったら使って⾒てください
https://www.embarcadero.com/jp/products/delphi/starter

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 7

Pascal 編

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 8

注意事項• 注意事項– 講演者は「純粋な Pascal」を触ったことがないため「Turbo Pascal」基準で書いています。
– 純粋な Pascal や Pascal の系譜については@ht_deko さんの Qiita の記事が詳しいです• このスライドの作成にも多くのアドバイスをいただきました
ありがとうございます

Twitter: @ht_deko

Pascal へのオブジェクト指向拡張の歴史と Delphi
https://qiita.com/ht_deko/items/ff2d90c9174290583377

標準 Pascal 範囲内での Delphi 入門
https://qiita.com/ht_deko/items/e2796788c65c2cda1de5
Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 9

Pascal の紹介•

Pascal の特徴– 1970 年誕⽣ (52歳︕)– ニクラウス・ヴィルト (Niklaus Wirth) 博⼠が制作• Pascal を初めとしてプログラミング⾔語（Modula-2 など）を多数制作
名著「アルゴリズム＋データ構造＝プログラム」等があります– 特徴• ALGOL をベースに⾔語仕様を簡素化 / LL(1) ⽂法• ⼤⽂字と⼩⽂字を区別しません• 予約語と指令– 指令はコンテキストによって予約語相当に• 戻り値は関数名に値を代⼊します– Pascal では「戻り値」ではなく「結果」と呼びます– 再帰がやりづらいため Turbo Pascal では
Result 変数が導⼊されています– 教育⽬的• Pascal で Pascal を実装できます⇒ Bootstrapping• ⾮常に強い静的型け⾔語
Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 10

Pascal の紹介• 型 (Turbo Pascal 準拠)
– 単純型

• 順序型
• 実数型

– ⽂字列型• 特殊な Char の配列– 255 ⽂字まで格納可能– 構造化型• record 型– 共⽤体も record で定義できる– ポインタ型– 集合型– ファイル型• Delphi になってからは使われることはほぼ無い

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

// FizzBuzz
program FizzBuzz(out);
type
TRange = 1.. 100; // 部分範囲型
var
I: TRange;
S: String;
begin
for I := Low(TRange) to High(TRange) do
begin
S := '';
if I mod 3 = 0 thenS := 'Fizz';
if I mod 5 = 0 thenS := S + 'Buzz'; // 標準 Pascal では不可
if S = '' thenStr(I, S);
Writeln(S);
end;
end.

PAGE 11

Pascal の紹介• 順序型– 順序のある値• ⽐較演算 (<, >, = など) 可能• 特殊な定義済み関数を使えます– Ord– Pred / Succ
– Low / High

順序値
前・次の値
最⼩値・最⼤値– Pascal における順序型
• 整数型
• ⽂字型

– Turbo Pascal では
0〜255 の⽂字コード(処理系依存)• 論理型（︕）– False.. True

program TypeSample(out);
type
TRange = 1.. 100;// 部分範囲型
TEnum = (Cat, Dog, Fox); // 列挙型
var
I: Integer; // 整数型
C: Char; // ⽂字型
B: Boolean; // 論理型
E: (Nyaa, Wan, Kon); // 列挙型
begin
for C := 'A' to 'Z' do
Writeln(C); // ⼤⽂字を出⼒
for C := 'A' to 'Z' do
Writeln(Ord(C)); // ⽂字コードを出⼒
for C := 'A' to 'Z' do
if C > 'G' then // G より上のみ出⼒Writeln(C);
end.

• 列挙型

– ユーザー定義の列挙値• 部分範囲型– 既存の順序型の部分範囲

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 12

Pascal の紹介• 集合型– Pascal はライブラリではなく⾔語の機能として「集合」を扱えます。
• 値は順序型• Turbo Pascal での要素数は 256 個まで– 要素数は処理系依存– 集合の演算意味

数学

Pascal相当＝=

if A = B then ...

不⼀致

≠

<>

if A <> B then ...

部分集合

⊂

<=

if A <= B then ...

上位集合

⊃

>=

if A >= B then ...

所属

∈

in

if A in X then ...

和集合

∪

+

if A + B <> [] then ...

差集合

＼

-

if A - B = [] then ...

積集合

∩

*

if A * B <= X then...

例

program SetSample(out);var
Alpha: set of 'a'.. 'z';
A: Char;begin// [] は集合構成⼦
Alpha := ['f', 'o', 'x'];
A := 'f';
if A in Alpha thenWriteln('属しています'); // 表⽰される
A := '0';
if A in Alpha thenWriteln('属しています'); // 表⽰されない// 追加
Alpha := Alpha + ['c', 'a', 't'];
A := 'a';if A in Alpha thenWriteln('属しています'); // 表⽰される
end.

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 13• 演算⼦– 強い静的型付け⾔語のため実数と整数の演算⼦が異なる部分があります︕– 除算• 実数 R := F / 2;
• 整数 I := N div 2;– 剰余• 実数 未サポート• 整数 I := N mod 2;

var
I: Integer;
R: Real;begin
I := 20;
R := 4.2;
I := I div 2; // OK
R := I / 2; // OK
R := I div 2; // OK
I := R div 2; // NG
I := R / 2; // NG
end.

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 14

Pascal の紹介• 型の代⼊互換性– 代⼊や演算できるのは同じ型のみ• Cast すれば代⼊できます

C / C++ は型が違っても代⼊できる
int main(int argc, _TCHAR* argv[]){
int a = 0;bool b = true;a = b; // 型が違っても代⼊できる
printf("%d\n", a);

代⼊や演算できるのは同じ型か範囲が拡張される場合

char c = 'a'; // c の場合 char は整数型
c = c + b; // 型が違っても演算できる
printf("%c\n", c);}

Pascal は型が違うと基本的には代⼊できない
program TypeSample2(out);var
I: Integer; // 整数型
B: Boolean; // 論理型
R: Real; // 実数型 (Object Pascal では⾮推奨)
begin
I := 0;
B := True;
R := 4.5;
I := B; // エラー
R := I; // 実数の表現範囲の⽅が整数より広いため OK
end.
Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 15

Object Pascal 編

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 16

Object Pascal の紹介•

Object Pascal の特徴– 1990 年誕⽣ (Turbo Pascal 基準)• Apple Object Pascal– ラリー・テスラーのチームとニクラウス・ヴィルト博⼠が Object Pascal を開発 (1985)• Turbo Pascal– Turbo Pascal 5.5 で Object 指向拡張が導⼊されました– アンダース・ヘルスバーグ（Anders Hejlsberg）が開発» 後に Delphi, C#, TypeScript を開発︕

– 単純な構造 (?)• C++ のような多重継承はありません• C++ の Template 相当の Generics や演算⼦オーバーロード、Java の interface 相当の機能は後から追加されました• 今では実は少し複雑かも…︖– インライン変数宣⾔の導⼊– 柔軟な強い静的型付け⾔語

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 17

Object Pascal の紹介• 柔軟な強い静的型付け⾔語– type の拡張• 既存の型を新しい型として定義できます– RTTI (RunTime Type Information)• 実⾏時型情報があります• リフレクションが使える (拡張 RTTI)– 動的なこともできちゃう︕︖
type// 既存の型を新しい型として宣⾔できる
TInt = type Integer;
procedure Foo(var V: TInt);
begin
Writeln(V);
end;
begin
var I: Integer := 0;Foo(I); // エラー！
end.
Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

uses
System.Rtti, FMX.Types;
type
TFoo = classprivate var FBar: Integer;
end;
begin
var Foo := TFoo.Create;try
var RT := SharedContext.GetType(Foo.ClassType);var Bar := RT.GetField('FBar');Bar.SetValue(Foo, 1);
Writeln(Foo.FBar); // 1 が出⼒される
finally
Foo.Free;end;
end.
PAGE 18

Object Pascal の紹介• インライン変数宣⾔– コンパイラバージョン 33.0 以降 (Delphi 10.3 以降)– Pascal は構⽂がブロック構造となっています• 変数宣⾔は変数宣⾔ブロックで宣⾔する仕組みでした– Object Pascal ではインライン変数宣⾔が可能• 厳格な型があるため右辺値から左辺値の型を推測できます（型推論）// Pascal の場合
const// 定数ブロック// Pascal の定数に型は指定できない
Quux = 5.2;
var// 変数ブロック
Foo: Integer;
Bar: Integer;
Baz: String;
Quux: Real;begin
Foo := 100;
Bar := 200;
Baz := 'Cat';end.
Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

// インライン変数宣⾔と型推論
begin// インライン変数宣⾔（型指定）
var Foo: Integer := 100;// インライン変数宣⾔（型推論）var Bar := 200;
var Baz := 'Cat';// インライン定数宣⾔ (型指定: 型付き定数)
const Quux: Single = 5.2;// インライン定数宣⾔ (型推論)
const Qux = 4.2;
end.

PAGE 19

Object Pascal の紹介• Object Pascal で追加された型の⼀部(Delphi 11 Alexandria までに)– クラス型(class)– インターフェース型(interface)– メタクラス型– ⾼度なレコード型 (record)– 動的配列 (array of)– ⻑い⽂字列型 (string)– メソッドポインタ型– 無名メソッド型– Variant 型– などなどなど

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

他の⾔語ではあまり聞かない
型があるな〜︖

PAGE 20

Object Pascal の紹介

•

class

– ヒープ領域にメモリを取ります– property 機構の存在– アクセス制御
アクセス制御範囲

strict private

⾃分⾃⾝

private⾃分⾃⾝, 同⼀Unit

strict protected

⾃分⾃⾝, 継承先

protected

⾃分⾃⾝, 継承先, 同⼀Unit

public誰でもpublished

超誰でも︕(RTTI が⽣成される)

Object Pascal は C++ のような Friend はありません。
代わりに Unit Friend と呼ばれる機構があります。
同⼀ Unit 内では private / protected 関係なく⾒えちゃう︕
それを防ぐのが strict 指令です。
published は RTTI が⽣成されるため「外」から⾒えるようにできます。
IDE は published 指定されたプロパティを編集できるようにしています（右図）。
Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 21Object Pascal の紹介•

class 例type
TFoo = classprivate class var // クラス変数を宣⾔できます
FBar: String;private var// こちらは普通のフィールド変数 (var は省略可)
FQuux: Integer;
protected
procedure Baz;procedure SetQuux(AValue: Integer);function GetQux(const AIndex: Integer): String;procedure SetQux(const AIndex: Integer; AValue: String);
publicconstructor Create; reintroduce; // Object Pascal のコンストラクタは⾃由に名前を決められます
destructor Destroy; override;
property Quux: Integer read FQuux write SetQuux; // property の実体には変数やメソッドを指定できます
publishedproperty Qux[const AIndex: Integer]: String read GetQux write SetQux; default;
end;
begin
// コンストラクタを呼び出す事でヒープにメモリを確保し初期化されます
var Foo := TFoo.Create;try
Foo[0] := 'Hello'; // default 指定された property は名前を省略できます
finally
Foo.Free; // 確保されたメモリを解放
end;
end.

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

この形は良く使うので
try / ctrl + j
で⼀発で呼び出せます(Live Template)

PAGE 22

Object Pascal の紹介• メタクラス– クラスを表す型– 多態性を実現する⽅法の１つ• ファクトリで⽣成するインスタンスの型を動的に変更するなど

type
TFoo = classpublicprocedure Bar; virtual;end;
TBaz = class(TFoo)
publicprocedure Bar; override;end;// メタクラスの宣⾔ (ただし今回は未使⽤）
TFooClass = class of TFoo;
procedure TFoo.Bar;
begin
Writeln('TFoo');end;
procedure TBaz.Bar;
begin
Writeln('TBaz');end;

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

begin// 型推論で⾃動的に class of TFoo のメタクラスになります
var FooClass := TFoo;
var Foo := FooClass.Create;
try
Foo.Bar; // TFoo が出⼒されされます
finally
Foo.Free;end;// TFoo を継承したクラスなら代⼊可能
FooClass := TBaz;
Foo := FooClass.Create;
try
Foo.Bar; // TBaz が出⼒されます
finally
Foo.Free;
end;
end.

PAGE 23

Object Pascal の紹介•

無名メソッド型– Pascal では考えられませんが、直接メソッドを渡せるようになりました• でも型に厳格なので型を定義しないと使えません– Pascal としては完全に異端ですが即時関数も定義できるようになりました…

type// 無名メソッドの型定義
TSampleProc =reference to function(const A: Integer): Integer;// TSampleProc 型の関数を受取る
procedure Foo(const AProc: TSampleProc);
begin
Writeln(AProc(2));
end;
begin
// TSampleProc 型の関数を直接書ける
Foo(function(const A: Integer): Integer
begin
Result := A * A;
end
);

begin
var B :=
(function(A: Integer): Integer begin Result := A * 2; end)(3);
Writeln(B);end.

JavaScript みたい

Readln;end.
Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 24

Object Pascal の紹介• 動的配列型– 通常配列は指定した要素数を増減できませんが、
Object Pascal の動的配列は要素数を増減できます︕– array of と書き、要素数を指定しなければ動的配列になります• 通常は array [0.. 9] of Integer などと要素数を指定します– SetLength ビルトイン関数でサイズを変更します• サイズが⼤きくなっても今までのデータは保持されます– 集合の様に⾜し算でサイズを変更する事も可能ですvar
Foo: array of String; // array はインライン変数宣⾔では定義できない
begin
var Bar: TArray<String>; // array of T となっている Generics を使える
var S := ['Cat', 'Dog', 'Fox']; // 型推論で S は ⾃動的に array of String 型になる
Writeln(S[0]); // Cat が出⼒される
S := S + ['Bear', 'Turtle'];Writeln(S[3]); // Bear が出⼒される
SetLength(S, 10); // 確保されたメモリは初期化される（既存のデータがある場合は保持される）
Writeln(S[9]); // 空⽂字が出⼒される
end.
Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 25

Object Pascal の紹介•

⻑い⽂字列型– 参照カウントで管理されます• メモリは⾃動廃棄されます• 同じ⽂字列であればコピーをしないため⾮常に⾼速です（参照カウントが１つ増えます）• ⽂字列の加算も⾮常に⾼速です– ⽂字列⻑の最⼤値は 4GB• Pascal の String は 255⽂字– Object Pascal の⽂字列は多種• UnicodeString– 現在の String は UnicodeString のエイリアスです• AnsiString– かつて String のエイリアスだった⽂字列型です– 現在はコードページ指定に使えるように拡張されています• ShortString– Turbo Pascal の⽂字列
– 短い⽂字列型と⾔われます• などなど– コードページ指定で⽂字列型を⽣成できる
type
UTF8String = type AnsiString(65001); // UTF-8
SJISString = type AnsiString(932); // Shift-JIS
EUCJString = type AnsiString(20932); // EUC-JP
Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 26

Object Pascal の紹介• ⽂字列の⾃動変換– ⻑い⽂字列は代⼊時に⾃動的にコードページ変換が⾛ります
type
SJISString = type AnsiString(932); // Shift-JIS
UTF8String = type AnsiString(65001); // UTF-8
EUCJString = type AnsiString(20932); // EUC-JP
begin
var S := AnsiString('あいうえお'); // AnsiString のデフォルトは Shift-JIS// SJIS 以外は⾃動的にコードページ変換が⾛ります
var SJIS: SJISString := S;
var UTF8: UTF8String := S;
var EUCJ: EUCJString := S;// どれも⽂字化けせずに表⽰されます
Writeln('SJIS: ', SJIS);
Writeln('UTF8: ', UTF8);
Writeln('EUCJ: ', EUCJ);
end.

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 27

Object Pascal の紹介• ⽂字配列の⾃動変換– ⽂字の配列は String に代⼊できちゃう– Null 終端⽂字列も相互に変換できちゃう…

• C/C++ のライブラリを呼び出すのが⾮常に簡単

uses
Winapi.Windows;
procedure Sample;var
C: array [0.. 2] of Char;begin
C := 'Cat'; // ⻑さが合っている⽂字列は代⼊可能// 静的配列は⽂字列に変換可能
var S: String := C;
Writeln(S);

・・・?
・・・?

// PChar として型変換すると Null 終端が⾃動的に付く…
MessageBox(0, PChar(S), '', MB_OK);// Null 終端⽂字列を代⼊されると 0 までを⽂字列として認識します
var A := PChar('Foo'#0); // Pascal は数字の前に # を付けると Char 型になる
Writeln(A, ' ', Length(A)); // Foo 3 と表⽰される
end;

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 28

動的な型の導⼊

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 29

Pascal の紹介• 動的な型の導⼊– 逆転の発想– 型に厳格なんだったら型さえあればいいんでしょ︕• 「動的な型」っていう型を定義しちゃえばいい• 「型がない型」っていう型を定義しちゃうと︖

型を動的にしたいなら…
「型無し」や「動的」という「型」を定義しちゃえばいいのでは…︕︖

begin// 動的な型 Variant
var V: Variant := 'Foo';// ⽂字列が⼊っていた所に整数を⼊れられる
V := 1;
Writeln(V); // 1 が出⼒される
end.
// 引数の型を明⽰しなければ型無し型になる
procedure Foo(const A);
begin
Writeln(Integer(A));
end;
begin
var I := 1; // 型推論で Integer になる
Foo(I);
end.

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 30

Object Pascal の紹介• Variant (動的型)– ⼤体なんでも⼊る型• レコード，集合，静的配列，クラス，クラス参照，およびポインタを除く• メモリを多く消費します• 処理速度は遅い– 型に厳格とはなんだったのか…
begin
var V: Variant := 100;
Writeln(V);V := 'Foo';
Writeln(V);V := False;
Writeln(V);V := 12.5;
Writeln(V);V := False;
var Foo: String := V; // 左辺の型に⾃動的に変換されます
Writeln(Foo);// ⽂字列として False と表⽰されます
end.
Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 31

Object Pascal の紹介• TValue (動的型レコード)– Variant の軽量版
– ⾔語ではなく RTL で実装されています• System.Rtti• Variant は⾔語として実装されています– 型情報が⼿に⼊るので型情報を⽤いて処理を分岐したりできます
uses
System.Rtti;
begin
var A: TValue := 1; // 何でも代⼊できる
Writeln(A.AsInteger);
A := True;
Writeln(A.ToString);
if A.IsOrdinal thenWriteln('Ordinal');end.

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 32

Object Pascal の紹介• const (型無し型）– 型がない︕– 使う時は型を指定します• 変数のアドレスが渡っています• 渡ってくる型を知っている必要があります

procedure Sample(const A);
begin
try
Writeln(Integer(A));
except on E: Exception do
Writeln(E.ToString);
end;
end;
begin
var P := 100;
Sample(P); // 変数のアドレスを渡すため単純型の即値は渡せない
Sample('あいうえお'); // 最初の 32 ビットが出る
end.

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 33

Object Pascal の紹介• array of const (型無し型の配列）– 型がな…ある︕– array of const は array of TVarRec の糖⾐構⽂– 様々な型の値を受取るために使われます• C の printf のような関数を作るために使われます– TVarRec は型情報を持っている record (共⽤体）• 定義は System.pas (RTL)

procedure Sample(A: array of const);
begin
for var i := 0 to High(A) do
if A[i].VType = vtInteger then // 型情報を使って整数型だけ表⽰する
begin
Writeln('Integer: ', A[i].VInteger);
end;
end;
begin
Sample([5, 'あいうえお', True, nil]); // 5 だけ出⼒される
end.

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 34

まとめ

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 35

まとめ• Object Pascal– Pascal 由来の強い静的型付け⾔語– 型に対する柔軟さもある• 現実を⾒てる︕– 他の⾔語にない珍しい機能もあります• メタクラスや動的配列、⻑い⽂字列型など– Delphi 10.4 Community Edition で
Object Pascal の機能を試せます︕• https://www.embarcadero.com/jp/products/delphi/starter– 最新版 Delphi 11.1 Alexandria では更に機能強化が⼊っています。
• ２進数の即値や数値セパレータなど

Copyright © 2022 SERIALGAMES Inc. All Rights Reserved.

PAGE 36

End of document.