オブジェクト指向
プログラミング入門
ソフトウェア基礎講座 第9回
2011年4月7日
服部健太
契約が破られるとき:
例外処理
2011/4/7 オブジェクト指向プログラミング入門 9 3
例外処理の基本概念
 失敗
 異常シグナルを発生させてしまったり,終了時に
事後条件や不変表明に違反していたり,別のルー
チンを呼び出す際に事前条件を満たさなかった場
合
 例外
 ルーチンコールの失敗を引き起こす可能性のある
実行時イベント
 例外はルーチンの失敗を引き起こすが,例外を捉えて回
復することも可能である
2011/4/7 オブジェクト指向プログラミング入門 9 4
例外の原因
例外はルーチン r の実行中に,次のいずれかの状況の結果として起こる.
E1 ● a.f という修飾つきの特性呼び出しで, a が void であることが分かった
場合.
E2 ● 拡張されたターゲットに void の値をアタッチしようとした場合.
E3 ● ある操作の実行でおきた異常条件が,ハードウェアかオペレーティン
グシス
  テムによって検出された場合.
E4 ● 失敗するルーチンを呼んだ場合.
E5 ● r の事前条件が入口で満たされていないことが分かった場合.
E6 ● r の事後条件が出口で満たされていないことが分かった場合.
E7 ● クラス不変表明が入口か出口で満たされていないことが分かった場合
.
E8 ● ループ不変表明が from 句の後かループ本体の繰返し後に満たされてい
な
  いことが分かった場合.
E9 ● ループ本体の繰返しで,ループ不変表明が減少していないことが分
かった
  場合.
定義:例外の起きるケース
2011/4/7 オブジェクト指向プログラミング入門 9 5
失敗の原因
 失敗と例外の定義は互いに再帰的である.
 失敗は例外から生じる
 呼び出しを行なったルーチンにとって,例外発生源の 1 つ
は呼び出しルーチンの失敗である
ルーチンの実行中に例外が起き,ルーチンがその例外から回復しない場合に
限り,そのルーチンコールは失敗となる.
定義:失敗するケース
ルーチンの失敗によって,そのルーチンの呼び出し側に例外が発生する.
失敗と例外
2011/4/7 オブジェクト指向プログラミング入門 9 6
例外処理:やってはいけない方法
 C-Unix の例:
 signal を使った例外処理
 signal の発生した場所が分からないから回復でき
ない
 setjmp と longjmp で対応可能ではある
 Ada の例:
 例外を捕捉してメッセージを出力し,リターンす
る
 呼び出し側が気がつかない
2011/4/7 オブジェクト指向プログラミング入門 9 7
例外処理の原則
 リトライ:だめだったら別の方法を試す
 契約は満たされる
 失敗:契約を満たすことを断念する
 呼び出し側が例外を受け取ることを確認する(もみ消さない)
 整合の取れた実行状態(不変表明を満たす状態)を復旧する
ルーチンの実行中に起こった例外を処理するには,正しいやり方が 2 つある
.
R1 ● リトライ:例外となる状態を変更し,ルーチンを最初から実行し直そ
うとする.
R2 ● 失敗(組織的パニックとしても知られる):環境をきれいにし,実行
を終了し
  て呼び出し側に失敗を報告する.
加えて,オペレーティングシステムのシグナルから生じる例外(例外の分類
では E3 のケース)の中には,まれなケースとして,偽の警報を返してもよ
い場合がある.すなわち,その例外は無害であるとして,例外が発生したと
ころからルーチンの実行を再開する.
制御された例外処理の原則
2011/4/7 オブジェクト指向プログラミング入門 9 8
例外メカニズム
 救助と再開
 rescue 句:例外発生時に実行される
 retry 命令:ルーチン本体がはじめから再開される
routine is
do
body
rescue
rescue_clause
end
 実際に試さずに失敗する方法
Rescue 句の実行が, retry 命令を実行せずに終了した場合,現在ルーチンの
呼び出しは失敗となる.
失敗の原則
2011/4/7 オブジェクト指向プログラミング入門 9 9
例外処理例:脆弱な入力
Maximum_attempts: INTEGER is 5 -- 断念する前に整数入力を試す回数
get_integer is
-- 最大 Maximum_attempts 回まで,整数を読もうとする
local
attempts: INTEGER
do
if attempts < Maximum_attempts then
print(“ 整数を入力して下さい:” )
read_one_integer
integer_was_read := True
else
integer_was_read := False
attempts := attempts + 1
end
rescue
retry
end
2011/4/7 オブジェクト指向プログラミング入門 9 10
例外処理例:ハードウェアあるいは
オペレーティングシステムの例外か
らの回復 例外を引き起こすイベント
 シグナル群,オーバーフロー,アンダーフロー,不可能な I/O 操作,不正命
令,メモリ不足 , etc.
 理論的にはこのような状態は表明違反と見なすことができる.
 例:
quasi_inverse(x: REAL): REAL is
-- 可能なら 1/x ,さもなくば 0
local
division_tried: BOOLEAN
do
if not division_tried then
Result := 1/x
end
rescue
division_tried := True
retry
end
2011/4/7 オブジェクト指向プログラミング入門 9 11
例外処理例:ソフトウェアのフォル
トトレランスに対するリトライ
 ユーザ要求を処理するエディタの例:
execute_one_command is
-- ユーザから入力を受け付け,可能であれば,
  -- 対応するコマンドを実行する.
do
“ ”ユーザ要求を解析
“ ”要求に応える適切なコマンドを実行
rescue
message(“ ”残念ながら,この命令に失敗しました )
message(“ ”どうか別の命令を試してください )
message(“ ”これが失敗だったことを作者に報告してください )
“ ”エディタの状態を正常に戻すための命令群
retry
end
2011/4/7 オブジェクト指向プログラミング入門 9 12
rescue 句の仕事
 rescue 句の仕事は例外を処理し,ルーチン本体か呼び出し側に
制御を戻すことであって,契約を保証することではない.
  C3 ● {True} Rescuer {INV}
失敗にいたる rescue 句の正当性規則
  C4 ● {True} Retryr {INV and prer}
リトライにいたる rescue 句の正当
性規則
  C2 ● すべてのエクスポートルーチン r と有効な引数の任意の集合に対し
て,次
  の式が満たされている.
{prer(xr) and INV} Bodyr {postr(xr) and INV}
定義:クラスの正
しさ
2011/4/7 オブジェクト指向プログラミング入門 9 13
高度な例外処理
 例外クエリ(クラス EXCEPTIONS )
 例外コードを問い合わせる
 開発者例外
 整数のコードと対応する名前の文字列からなる
trigger(code: INTEGER; message: STRING)
-- 例外として現在のルーチンの実行を中断
 構文解析アルゴリズムでの使用例
 構文エラー時に開発者例外を投げる
 if...then…else 構造によって制御構造が複雑にならずに
済む
継承入門
2011/4/7 オブジェクト指向プログラミング入門 9 15
例:多角形と長方形
class POLYGON creation
…
feature
perimeter: REAL is -- 周囲の長さ
do … end
display is -- スクリーンに多角形を表示する
do … end
rotate(center: POINT; angle: REAL) is -- center を中心に angle だけ回転す
る
do … end
translate(a, b: REAL) is -- 水平に a, 垂直に b 移動する
do … end
feature {NONE} – 実装
vertices: LINKED_LIST[POINT]
invariant
same_count_as_implementation: count = vertices.count
at_leaset_three: count>= 3
end
2011/4/7 オブジェクト指向プログラミング入門 9 16
例:多角形の回転
rotate(center: POINT; angle: REAL) is
-- center を中心に angle だけ回転する
do
from
vertices.start
until
vertices.after
loop
vertices.item.rotate(center, angle)
vertices.forth
end
end
2011/4/7 オブジェクト指向プログラミング入門 9 17
例:多角形の周囲の長さ
perimeter: REAL is
local
this, previous: POINT
do
from
vertices.start; this := vertices.item
check not vertices.after end – at_least_three の結果
until
vertices.is_last
loop
previous := this; vertices.forth; this := vertices.item
Result := Result + this.distance(previous)
end
Result := Result + this.distance(vertices.first)
end
2011/4/7 オブジェクト指向プログラミング入門 9 18
長方形
 長方形は多角形の一種であり,多くの共通し
た特徴を持っている
 移動,回転,表示を行なうことができる
 独自の特性や性質,操作法を持っている
 対角線,角度は直角,周囲の長さは簡単に計算で
きる, etc.
 長方形クラス RECTANGLE をクラス
POLYGON の後継者として定義する
 POLYGON のすべての特性がデフォルトで後継者
クラスでも同じように利用できるようになる
2011/4/7 オブジェクト指向プログラミング入門 9 19
長方形の例
class RECTANGLE inherit POLYGON
redefine perimeter end
creation make
feature
make(center: POINT; s1, s2, angle: REAL) is
do … end
feature -- アクセスする
side1, side2: REAL -- 2辺の長さ
diagonal: REAL -- 対角線の長さ
perimeter: REAL is
do
Result := 2 * (side1 + side2)
end
invariant …
end
2011/4/7 オブジェクト指向プログラミング入門 9 20
基本的な慣習と用語
クラス C の子孫( descendant )とは, C 自身を含み, C から直接的また
は間接的に継承するクラスを指す(形式的にいえば, C もしくは,再帰的
に C の後継者の子孫)
クラス C の真の子孫( proper descendant )とは, C 自身を除く子孫を
指す.
クラス C の祖先( ancestor )とは, C が A の子孫である場合の A を指す
.
クラス C の真の祖先( proper ancestor )とは, C が A の真の子孫である
場合の A を指す
継承の用語
POLYGON
RECTANGLE
 継承の関係 perimeter
diagonal
perimeter++ ~継承している
2011/4/7 オブジェクト指向プログラミング入門 9 21
不変表明の継承
class RECTANGLE inherit POLYGON
…
invariant
four_sides: count = 4
first_side: (vertices.i_th(1)).distance(vertices.i_th(2)) = side1
second_side: (vertices.i_th(2)).distance(vertices.i_th(3)) = side2
…
end
 B が A から継承されたということは, B のインスタンスすべて
が, A のインスタンスとも見なされることを意味する.
クラスの不変表明は,自分の invariant 句に表される表明と親の不変表明
(もし存在すれば)との論理積 and となる
不変表明の継承規
則
2011/4/7 オブジェクト指向プログラミング入門 9 22
継承と生成
make_polygon (vl: LINKED_LIST[POINT]) is
require vl.count >= 3
do
… vl の item …によって多角形の表現を初期化する
ensure
-- 頂点と vl は同じ item を持つ
end
 親の生成プロシージャは後継者の生成プロシージャと同じであ
る必要はない
 生成プロシージャの役割はクラスの不変表明を構築することで
あり,通常,後継者の不変表明は親よりも強くなる可能性があ
る.
親クラスから継承された特性の生成状態(生成プロシージャであろうとなか
ろうと)には,後継者の生成状態は含まれていない.
生成の継承規則
2011/4/7 オブジェクト指向プログラミング入門 9 23
多相性
 多相的アタッチメント
 「多相性( polymorphism )」とはいくつかの形態を取る
能力を意味する.
 多相性によって実行時に異なる型のオブジェクトが変数に
アタッチできるようになるが,すべて静的な宣言によって
制御される
 p:POLYGON; r:RECTANGLE; t:TRIANGLE
 f(p:POLYGON) is do … end
 この時,次の代入や引数渡しは正しい
 p := r; p:= t; f(r); f(t)
 多相的な代入と呼ばれる.
 p にあたるエンティティを多相的エンティティと呼ぶ
 r := p といった逆方向への代入は許されない
2011/4/7 オブジェクト指向プログラミング入門 9 24
多相的にアタッチされる間に正確に
何が起こるか?
 参照がアタッチし直されるだけ
 実行時にオブジェクトが変質してしまうわけではない.
 多相的アタッチメントはアタッチ先が参照型である場合のみ有
効
 拡張型の場合,オブジェクトの中身を上書きすることを意味す
るが,通常,フィールドの数が異なるため,それは不可能.
p
r
(POLYGON)
(RECTANGLE)
O1
O2
(before)
(after)
p := r
2011/4/7 オブジェクト指向プログラミング入門 9 25
多相的データ構造
 次のような多角形の配列があるとする
poly_arr: ARRAY[POLYGON]
 poly_arr には, POLYGON の子孫であれば配列要素に代入できる
p:POLYGON; r:RECTANGLE; s:SQUARE; t:TRIANGLE
poly_arr.put(p, 1); poly_arr.put(r, 2)
poly_arr.put(s, 3); poly_arr.put(t, 4)
 多相的データ構造を導入することで,総称性と継承を使い,柔軟性と
安全性を最大にするという目的を達成することができる.
(TRIANGLE)
(POLYGON)
(RECTANGLE)
(SQUARE)
4
3
2
1
2011/4/7 オブジェクト指向プログラミング入門 9 26
継承のための型付け
 静的型付けによって,実行時に型の不整合が起きないことをコ
ンパイル時に保証できる
 型の整合性
 p: POLYGON; r: RECTANGLE
 以下の呼び出しは正しい
 p.perimeter, p.vertices, p.translate(…), p.rotate(…)
 r.diagonal, r.side1, r.side2
 r.vertices, r.translate(…), r.rotate(…)
 r.perimeter
 以下の特性呼び出しは間違い
 p.side1, p.side2, p.diagonal
ファンクションコール x.f において, x の型がクラス C に基づいているとき
,特性 f は, C の祖先の1つで定義されていなければならない.
特性呼び出し規則
2011/4/7 オブジェクト指向プログラミング入門 9 27
多相性の制限
 B が A の子孫であり, Y が X の子孫であるとき, B[Y] は A[X]
に適合する
 より特殊なものからより一般的なものへは代入可能であるが,
逆は不可能である.
U の基本クラスが T の基本クラスの子孫であるとき,型 U は型 T に適合す
る.また,総称的に派生された型においては, U のすべての総称パラメー
タは, T の対応する総称パラメータに(再帰的に)適合しなければならない
.
定義:適合性
( conformance )
アタッチ先 x とアタッチ元 y のアタッチメント(すなわち,代入 x := y ,も
しくは,仮引数 x のルーチンコールで,実引数が y の場合)は, y の型が x
の型に適合する場合にのみ許される.
型の適合性規則( Type Conformance Rule )
2011/4/7 オブジェクト指向プログラミング入門 9 28
インスタンス,静的な型と動的な
型
p1, p2: POLYGON; r: RECTANGLE
create p1 …; create r …; p2 := r
 POLYGON の直接インスタンスは p1 のみ
 静的な型:エンティティを宣言するのに使われた型
 動的な型:実行時にアタッチされたオブジェクトの型
 動的な型は再アタッチメント操作によって変更され得る
クラス C の直接インスタンスとは, C の厳密な定義に従い,生成命令
create x を通して作成されたオブジェクト,もしくは,再帰的に, C の直接
インスタンスをコピーしたものを指す.ただし, x は型 C に属する.
C のインスタンスとは, C の子孫の直接インスタンスを指す.
定義:直接インスタンスとインス
タンス
型 T で宣言されたエンティティは,実行時に T のインスタンスにアタッチ
され得る.
静的および動的な型の整合性
2011/4/7 オブジェクト指向プログラミング入門 9 29
型を強要したいとき
 どうしても継承に反した代入をせざるを得な
い特殊な状況もある
 例:特定の型であると公表されたオブジェクトを
ネットワークを通して受け取る場合
 オブジェクトのもとになるものを制御できないので,ア
クセス前に型を確認する必要がある
 試行代入
 r ?= p
 「もしオブジェクトの型が r に対して許される型
であるならば代入をしなさい.さもなくば r を
void にしなさい」
2011/4/7 オブジェクト指向プログラミング入門 9 30
多相的生成
 T に真の子孫 U があると仮定
x:T
create {U} x -- U の直接インスタンスが生成
create {U} x.make(…)
 生成型
 生成命令によってつくられるオブジェクトの型
 例:
f: FIGURE
…
if chosen_icon=rectangle_icon then
create {RECTANGLE} f
elseif chosen_icon = circle_icon then
create {CIRCLE} f
else
…
end
2011/4/7 オブジェクト指向プログラミング入門 9 31
動的束縛
 複数バージョンを持つルーチンを多相的エンティティで実行し
たらどうなるか?
p:POLYGON
…
if chosen_icon = rectangle_icon then
create {RECTANGLE} p.make(…)
elsif chosen_icon = triangle_icon then
create {TRIANGLE} p.make(…)
…
end
x := p.perimeter
 どのバージョンの操作を使うかはオブジェクトの動的形式に
よって決定される.
2011/4/7 オブジェクト指向プログラミング入門 9 32
暫定特性と暫定クラス
 任意の図形を移動する
transform(f: FIGURE) is
do
f.rotate(…)
f.translate(…)
end
 FIGURE は全図形を網羅した相対的なものなので, rotate や
translate を実装することができない...
 何もしない rotate や translate を書いておくことは危険である
 かといって特性が無いと,型チェックにひっかかる
 特性を暫定とする
rotate(center: POINT; angle: REAL) is
-- center を中心に angle だけ回転する
deferred end
FIGURE
OPEN_
FIGURE
CLOSE_
FIGURE
・・・
・・・
2011/4/7 オブジェクト指向プログラミング入門 9 33
再定義と有効化
 再定義:すでに実装されている特性を真の子孫で実
装し直すこと
 redefine 句が必要
 有効化:親の暫定特性を具体的に実装すること
 redefine 句は不要
再宣言元→
先↓
暫定 有効
暫定 再定義 未定義化
有効 有効化 再定義
特性を再宣言するとは,特性を再定義,または有効化することである.
定義:再宣言( redeclaration )
2011/4/7 オブジェクト指向プログラミング入門 9 34
暫定クラス
 FIGURE の宣言
deffered class FIGURE feature
rotate(…) is
… …前述した暫定特性の宣言
… 他の feature 群の宣言
end -- クラス FIGURE
暫定特性を持つクラスを暫定クラス,暫定クラスでないクラスを有効クラス
とする.
定義:暫定クラス( deferred class )と有効クラス
( effective class )
暫定クラスの宣言には,(有効クラスを示す単なるクラスと区別するため
に) 2 語のキーワード deferred class を使うこととする.
暫定クラス宣言規則
2011/4/7 オブジェクト指向プログラミング入門 9 35
暫定クラスを使って何をするか?
 暫定クラスの直接インスタンスは存在しない
 f が FIGURE であった場合,生成命令 create f… は間違い
であり,コンパイラにはねられる
 ただし, create {RECTANGLE} f は OK
 暫定特性と暫定クラスの意味を限定する
 他のすべてのクラスと同様,暫定クラスでは不変表明を,
暫定特性では事前条件や事後条件を持つことができる
生成命令の生成型は暫定型になり得ない.
暫定クラスの非インスタンス化規則
2011/4/7 オブジェクト指向プログラミング入門 9 36
再宣言の方法
 ファンクションを属性として再宣言できる
 逆は成り立たない
 ファンクションに対して代入はできないので
 クラス C に属性 a が存在し, C のあるルーチンに次が含まれ
ていたとする
 a := some_expression
 C の子孫で a をファンクションで再定義しようとしたら,そ
のルーチンは適用不可能となる.
 再定義の本体に,オリジナル版を参照するための簡
単な記述を入れることができる
 親バージョンの特性を呼び出す予約語 Precursor
 再定義されたルーチンでのみ利用可能
2011/4/7 オブジェクト指向プログラミング入門 9 37
継承の意味
 モジュールの観点
 再利用技術としてとびきり有効
 型の視点
 「 is-a 」関係( Every B is an A )
 型に対する値という観点では,集合の包含関係となる.
 A のインスタンスに適用可能なすべての操作が B のインスタンスで
も適用可能である
 継承と分散
 動的束縛によって,特定の知識を特定の部分に閉じ込めること
ができるようになる
 あるクラスを変更したからといって,他のクラスに影響を及ぼさな
い
 表現の独立性
 present := t.has(x) , t に応じて, has の適切なバージョンが使
われる
 拡張性と特殊化のパラドクス
 クラスをモジュールとみるか型とみるかの違い
2011/4/7 オブジェクト指向プログラミング入門 9 38
暫定クラスの役割
 抽象データ型に戻る
 表明を加えることで,抽象データ型に近くなる
 振る舞いクラス
 部分的な実装としての暫定クラス
 いくつかの ADT の異形態に共通する動作を捕える
 例:暫定クラス SEQUENTIAL_TABLE : TABLE の has 特性は,
暫定特性群, start, after, forth, item のみで実装できる
 穴の開いたプログラム
 部分的にユーザーが中身を決める余地がある
 vs. サブルーチンライブラリ
 分析と全体設計のための暫定クラス
 抽象的かつ厳密に分析,設計を行い,スムーズに(同じ言
語を通して)実装まで移行することが可能となる.
次回予定
 日時: 2011年4月14日(木)13:
00~14:30
 場所: LB 2F/A 会議室
 内容:多重継承
2011/4/7 オブジェクト指向プログラミング入門 9 39

オブジェクト指向入門9

  • 1.
  • 2.
  • 3.
    2011/4/7 オブジェクト指向プログラミング入門 93 例外処理の基本概念  失敗  異常シグナルを発生させてしまったり,終了時に 事後条件や不変表明に違反していたり,別のルー チンを呼び出す際に事前条件を満たさなかった場 合  例外  ルーチンコールの失敗を引き起こす可能性のある 実行時イベント  例外はルーチンの失敗を引き起こすが,例外を捉えて回 復することも可能である
  • 4.
    2011/4/7 オブジェクト指向プログラミング入門 94 例外の原因 例外はルーチン r の実行中に,次のいずれかの状況の結果として起こる. E1 ● a.f という修飾つきの特性呼び出しで, a が void であることが分かった 場合. E2 ● 拡張されたターゲットに void の値をアタッチしようとした場合. E3 ● ある操作の実行でおきた異常条件が,ハードウェアかオペレーティン グシス   テムによって検出された場合. E4 ● 失敗するルーチンを呼んだ場合. E5 ● r の事前条件が入口で満たされていないことが分かった場合. E6 ● r の事後条件が出口で満たされていないことが分かった場合. E7 ● クラス不変表明が入口か出口で満たされていないことが分かった場合 . E8 ● ループ不変表明が from 句の後かループ本体の繰返し後に満たされてい な   いことが分かった場合. E9 ● ループ本体の繰返しで,ループ不変表明が減少していないことが分 かった   場合. 定義:例外の起きるケース
  • 5.
    2011/4/7 オブジェクト指向プログラミング入門 95 失敗の原因  失敗と例外の定義は互いに再帰的である.  失敗は例外から生じる  呼び出しを行なったルーチンにとって,例外発生源の 1 つ は呼び出しルーチンの失敗である ルーチンの実行中に例外が起き,ルーチンがその例外から回復しない場合に 限り,そのルーチンコールは失敗となる. 定義:失敗するケース ルーチンの失敗によって,そのルーチンの呼び出し側に例外が発生する. 失敗と例外
  • 6.
    2011/4/7 オブジェクト指向プログラミング入門 96 例外処理:やってはいけない方法  C-Unix の例:  signal を使った例外処理  signal の発生した場所が分からないから回復でき ない  setjmp と longjmp で対応可能ではある  Ada の例:  例外を捕捉してメッセージを出力し,リターンす る  呼び出し側が気がつかない
  • 7.
    2011/4/7 オブジェクト指向プログラミング入門 97 例外処理の原則  リトライ:だめだったら別の方法を試す  契約は満たされる  失敗:契約を満たすことを断念する  呼び出し側が例外を受け取ることを確認する(もみ消さない)  整合の取れた実行状態(不変表明を満たす状態)を復旧する ルーチンの実行中に起こった例外を処理するには,正しいやり方が 2 つある . R1 ● リトライ:例外となる状態を変更し,ルーチンを最初から実行し直そ うとする. R2 ● 失敗(組織的パニックとしても知られる):環境をきれいにし,実行 を終了し   て呼び出し側に失敗を報告する. 加えて,オペレーティングシステムのシグナルから生じる例外(例外の分類 では E3 のケース)の中には,まれなケースとして,偽の警報を返してもよ い場合がある.すなわち,その例外は無害であるとして,例外が発生したと ころからルーチンの実行を再開する. 制御された例外処理の原則
  • 8.
    2011/4/7 オブジェクト指向プログラミング入門 98 例外メカニズム  救助と再開  rescue 句:例外発生時に実行される  retry 命令:ルーチン本体がはじめから再開される routine is do body rescue rescue_clause end  実際に試さずに失敗する方法 Rescue 句の実行が, retry 命令を実行せずに終了した場合,現在ルーチンの 呼び出しは失敗となる. 失敗の原則
  • 9.
    2011/4/7 オブジェクト指向プログラミング入門 99 例外処理例:脆弱な入力 Maximum_attempts: INTEGER is 5 -- 断念する前に整数入力を試す回数 get_integer is -- 最大 Maximum_attempts 回まで,整数を読もうとする local attempts: INTEGER do if attempts < Maximum_attempts then print(“ 整数を入力して下さい:” ) read_one_integer integer_was_read := True else integer_was_read := False attempts := attempts + 1 end rescue retry end
  • 10.
    2011/4/7 オブジェクト指向プログラミング入門 910 例外処理例:ハードウェアあるいは オペレーティングシステムの例外か らの回復 例外を引き起こすイベント  シグナル群,オーバーフロー,アンダーフロー,不可能な I/O 操作,不正命 令,メモリ不足 , etc.  理論的にはこのような状態は表明違反と見なすことができる.  例: quasi_inverse(x: REAL): REAL is -- 可能なら 1/x ,さもなくば 0 local division_tried: BOOLEAN do if not division_tried then Result := 1/x end rescue division_tried := True retry end
  • 11.
    2011/4/7 オブジェクト指向プログラミング入門 911 例外処理例:ソフトウェアのフォル トトレランスに対するリトライ  ユーザ要求を処理するエディタの例: execute_one_command is -- ユーザから入力を受け付け,可能であれば,   -- 対応するコマンドを実行する. do “ ”ユーザ要求を解析 “ ”要求に応える適切なコマンドを実行 rescue message(“ ”残念ながら,この命令に失敗しました ) message(“ ”どうか別の命令を試してください ) message(“ ”これが失敗だったことを作者に報告してください ) “ ”エディタの状態を正常に戻すための命令群 retry end
  • 12.
    2011/4/7 オブジェクト指向プログラミング入門 912 rescue 句の仕事  rescue 句の仕事は例外を処理し,ルーチン本体か呼び出し側に 制御を戻すことであって,契約を保証することではない.   C3 ● {True} Rescuer {INV} 失敗にいたる rescue 句の正当性規則   C4 ● {True} Retryr {INV and prer} リトライにいたる rescue 句の正当 性規則   C2 ● すべてのエクスポートルーチン r と有効な引数の任意の集合に対し て,次   の式が満たされている. {prer(xr) and INV} Bodyr {postr(xr) and INV} 定義:クラスの正 しさ
  • 13.
    2011/4/7 オブジェクト指向プログラミング入門 913 高度な例外処理  例外クエリ(クラス EXCEPTIONS )  例外コードを問い合わせる  開発者例外  整数のコードと対応する名前の文字列からなる trigger(code: INTEGER; message: STRING) -- 例外として現在のルーチンの実行を中断  構文解析アルゴリズムでの使用例  構文エラー時に開発者例外を投げる  if...then…else 構造によって制御構造が複雑にならずに 済む
  • 14.
  • 15.
    2011/4/7 オブジェクト指向プログラミング入門 915 例:多角形と長方形 class POLYGON creation … feature perimeter: REAL is -- 周囲の長さ do … end display is -- スクリーンに多角形を表示する do … end rotate(center: POINT; angle: REAL) is -- center を中心に angle だけ回転す る do … end translate(a, b: REAL) is -- 水平に a, 垂直に b 移動する do … end feature {NONE} – 実装 vertices: LINKED_LIST[POINT] invariant same_count_as_implementation: count = vertices.count at_leaset_three: count>= 3 end
  • 16.
    2011/4/7 オブジェクト指向プログラミング入門 916 例:多角形の回転 rotate(center: POINT; angle: REAL) is -- center を中心に angle だけ回転する do from vertices.start until vertices.after loop vertices.item.rotate(center, angle) vertices.forth end end
  • 17.
    2011/4/7 オブジェクト指向プログラミング入門 917 例:多角形の周囲の長さ perimeter: REAL is local this, previous: POINT do from vertices.start; this := vertices.item check not vertices.after end – at_least_three の結果 until vertices.is_last loop previous := this; vertices.forth; this := vertices.item Result := Result + this.distance(previous) end Result := Result + this.distance(vertices.first) end
  • 18.
    2011/4/7 オブジェクト指向プログラミング入門 918 長方形  長方形は多角形の一種であり,多くの共通し た特徴を持っている  移動,回転,表示を行なうことができる  独自の特性や性質,操作法を持っている  対角線,角度は直角,周囲の長さは簡単に計算で きる, etc.  長方形クラス RECTANGLE をクラス POLYGON の後継者として定義する  POLYGON のすべての特性がデフォルトで後継者 クラスでも同じように利用できるようになる
  • 19.
    2011/4/7 オブジェクト指向プログラミング入門 919 長方形の例 class RECTANGLE inherit POLYGON redefine perimeter end creation make feature make(center: POINT; s1, s2, angle: REAL) is do … end feature -- アクセスする side1, side2: REAL -- 2辺の長さ diagonal: REAL -- 対角線の長さ perimeter: REAL is do Result := 2 * (side1 + side2) end invariant … end
  • 20.
    2011/4/7 オブジェクト指向プログラミング入門 920 基本的な慣習と用語 クラス C の子孫( descendant )とは, C 自身を含み, C から直接的また は間接的に継承するクラスを指す(形式的にいえば, C もしくは,再帰的 に C の後継者の子孫) クラス C の真の子孫( proper descendant )とは, C 自身を除く子孫を 指す. クラス C の祖先( ancestor )とは, C が A の子孫である場合の A を指す . クラス C の真の祖先( proper ancestor )とは, C が A の真の子孫である 場合の A を指す 継承の用語 POLYGON RECTANGLE  継承の関係 perimeter diagonal perimeter++ ~継承している
  • 21.
    2011/4/7 オブジェクト指向プログラミング入門 921 不変表明の継承 class RECTANGLE inherit POLYGON … invariant four_sides: count = 4 first_side: (vertices.i_th(1)).distance(vertices.i_th(2)) = side1 second_side: (vertices.i_th(2)).distance(vertices.i_th(3)) = side2 … end  B が A から継承されたということは, B のインスタンスすべて が, A のインスタンスとも見なされることを意味する. クラスの不変表明は,自分の invariant 句に表される表明と親の不変表明 (もし存在すれば)との論理積 and となる 不変表明の継承規 則
  • 22.
    2011/4/7 オブジェクト指向プログラミング入門 922 継承と生成 make_polygon (vl: LINKED_LIST[POINT]) is require vl.count >= 3 do … vl の item …によって多角形の表現を初期化する ensure -- 頂点と vl は同じ item を持つ end  親の生成プロシージャは後継者の生成プロシージャと同じであ る必要はない  生成プロシージャの役割はクラスの不変表明を構築することで あり,通常,後継者の不変表明は親よりも強くなる可能性があ る. 親クラスから継承された特性の生成状態(生成プロシージャであろうとなか ろうと)には,後継者の生成状態は含まれていない. 生成の継承規則
  • 23.
    2011/4/7 オブジェクト指向プログラミング入門 923 多相性  多相的アタッチメント  「多相性( polymorphism )」とはいくつかの形態を取る 能力を意味する.  多相性によって実行時に異なる型のオブジェクトが変数に アタッチできるようになるが,すべて静的な宣言によって 制御される  p:POLYGON; r:RECTANGLE; t:TRIANGLE  f(p:POLYGON) is do … end  この時,次の代入や引数渡しは正しい  p := r; p:= t; f(r); f(t)  多相的な代入と呼ばれる.  p にあたるエンティティを多相的エンティティと呼ぶ  r := p といった逆方向への代入は許されない
  • 24.
    2011/4/7 オブジェクト指向プログラミング入門 924 多相的にアタッチされる間に正確に 何が起こるか?  参照がアタッチし直されるだけ  実行時にオブジェクトが変質してしまうわけではない.  多相的アタッチメントはアタッチ先が参照型である場合のみ有 効  拡張型の場合,オブジェクトの中身を上書きすることを意味す るが,通常,フィールドの数が異なるため,それは不可能. p r (POLYGON) (RECTANGLE) O1 O2 (before) (after) p := r
  • 25.
    2011/4/7 オブジェクト指向プログラミング入門 925 多相的データ構造  次のような多角形の配列があるとする poly_arr: ARRAY[POLYGON]  poly_arr には, POLYGON の子孫であれば配列要素に代入できる p:POLYGON; r:RECTANGLE; s:SQUARE; t:TRIANGLE poly_arr.put(p, 1); poly_arr.put(r, 2) poly_arr.put(s, 3); poly_arr.put(t, 4)  多相的データ構造を導入することで,総称性と継承を使い,柔軟性と 安全性を最大にするという目的を達成することができる. (TRIANGLE) (POLYGON) (RECTANGLE) (SQUARE) 4 3 2 1
  • 26.
    2011/4/7 オブジェクト指向プログラミング入門 926 継承のための型付け  静的型付けによって,実行時に型の不整合が起きないことをコ ンパイル時に保証できる  型の整合性  p: POLYGON; r: RECTANGLE  以下の呼び出しは正しい  p.perimeter, p.vertices, p.translate(…), p.rotate(…)  r.diagonal, r.side1, r.side2  r.vertices, r.translate(…), r.rotate(…)  r.perimeter  以下の特性呼び出しは間違い  p.side1, p.side2, p.diagonal ファンクションコール x.f において, x の型がクラス C に基づいているとき ,特性 f は, C の祖先の1つで定義されていなければならない. 特性呼び出し規則
  • 27.
    2011/4/7 オブジェクト指向プログラミング入門 927 多相性の制限  B が A の子孫であり, Y が X の子孫であるとき, B[Y] は A[X] に適合する  より特殊なものからより一般的なものへは代入可能であるが, 逆は不可能である. U の基本クラスが T の基本クラスの子孫であるとき,型 U は型 T に適合す る.また,総称的に派生された型においては, U のすべての総称パラメー タは, T の対応する総称パラメータに(再帰的に)適合しなければならない . 定義:適合性 ( conformance ) アタッチ先 x とアタッチ元 y のアタッチメント(すなわち,代入 x := y ,も しくは,仮引数 x のルーチンコールで,実引数が y の場合)は, y の型が x の型に適合する場合にのみ許される. 型の適合性規則( Type Conformance Rule )
  • 28.
    2011/4/7 オブジェクト指向プログラミング入門 928 インスタンス,静的な型と動的な 型 p1, p2: POLYGON; r: RECTANGLE create p1 …; create r …; p2 := r  POLYGON の直接インスタンスは p1 のみ  静的な型:エンティティを宣言するのに使われた型  動的な型:実行時にアタッチされたオブジェクトの型  動的な型は再アタッチメント操作によって変更され得る クラス C の直接インスタンスとは, C の厳密な定義に従い,生成命令 create x を通して作成されたオブジェクト,もしくは,再帰的に, C の直接 インスタンスをコピーしたものを指す.ただし, x は型 C に属する. C のインスタンスとは, C の子孫の直接インスタンスを指す. 定義:直接インスタンスとインス タンス 型 T で宣言されたエンティティは,実行時に T のインスタンスにアタッチ され得る. 静的および動的な型の整合性
  • 29.
    2011/4/7 オブジェクト指向プログラミング入門 929 型を強要したいとき  どうしても継承に反した代入をせざるを得な い特殊な状況もある  例:特定の型であると公表されたオブジェクトを ネットワークを通して受け取る場合  オブジェクトのもとになるものを制御できないので,ア クセス前に型を確認する必要がある  試行代入  r ?= p  「もしオブジェクトの型が r に対して許される型 であるならば代入をしなさい.さもなくば r を void にしなさい」
  • 30.
    2011/4/7 オブジェクト指向プログラミング入門 930 多相的生成  T に真の子孫 U があると仮定 x:T create {U} x -- U の直接インスタンスが生成 create {U} x.make(…)  生成型  生成命令によってつくられるオブジェクトの型  例: f: FIGURE … if chosen_icon=rectangle_icon then create {RECTANGLE} f elseif chosen_icon = circle_icon then create {CIRCLE} f else … end
  • 31.
    2011/4/7 オブジェクト指向プログラミング入門 931 動的束縛  複数バージョンを持つルーチンを多相的エンティティで実行し たらどうなるか? p:POLYGON … if chosen_icon = rectangle_icon then create {RECTANGLE} p.make(…) elsif chosen_icon = triangle_icon then create {TRIANGLE} p.make(…) … end x := p.perimeter  どのバージョンの操作を使うかはオブジェクトの動的形式に よって決定される.
  • 32.
    2011/4/7 オブジェクト指向プログラミング入門 932 暫定特性と暫定クラス  任意の図形を移動する transform(f: FIGURE) is do f.rotate(…) f.translate(…) end  FIGURE は全図形を網羅した相対的なものなので, rotate や translate を実装することができない...  何もしない rotate や translate を書いておくことは危険である  かといって特性が無いと,型チェックにひっかかる  特性を暫定とする rotate(center: POINT; angle: REAL) is -- center を中心に angle だけ回転する deferred end FIGURE OPEN_ FIGURE CLOSE_ FIGURE ・・・ ・・・
  • 33.
    2011/4/7 オブジェクト指向プログラミング入門 933 再定義と有効化  再定義:すでに実装されている特性を真の子孫で実 装し直すこと  redefine 句が必要  有効化:親の暫定特性を具体的に実装すること  redefine 句は不要 再宣言元→ 先↓ 暫定 有効 暫定 再定義 未定義化 有効 有効化 再定義 特性を再宣言するとは,特性を再定義,または有効化することである. 定義:再宣言( redeclaration )
  • 34.
    2011/4/7 オブジェクト指向プログラミング入門 934 暫定クラス  FIGURE の宣言 deffered class FIGURE feature rotate(…) is … …前述した暫定特性の宣言 … 他の feature 群の宣言 end -- クラス FIGURE 暫定特性を持つクラスを暫定クラス,暫定クラスでないクラスを有効クラス とする. 定義:暫定クラス( deferred class )と有効クラス ( effective class ) 暫定クラスの宣言には,(有効クラスを示す単なるクラスと区別するため に) 2 語のキーワード deferred class を使うこととする. 暫定クラス宣言規則
  • 35.
    2011/4/7 オブジェクト指向プログラミング入門 935 暫定クラスを使って何をするか?  暫定クラスの直接インスタンスは存在しない  f が FIGURE であった場合,生成命令 create f… は間違い であり,コンパイラにはねられる  ただし, create {RECTANGLE} f は OK  暫定特性と暫定クラスの意味を限定する  他のすべてのクラスと同様,暫定クラスでは不変表明を, 暫定特性では事前条件や事後条件を持つことができる 生成命令の生成型は暫定型になり得ない. 暫定クラスの非インスタンス化規則
  • 36.
    2011/4/7 オブジェクト指向プログラミング入門 936 再宣言の方法  ファンクションを属性として再宣言できる  逆は成り立たない  ファンクションに対して代入はできないので  クラス C に属性 a が存在し, C のあるルーチンに次が含まれ ていたとする  a := some_expression  C の子孫で a をファンクションで再定義しようとしたら,そ のルーチンは適用不可能となる.  再定義の本体に,オリジナル版を参照するための簡 単な記述を入れることができる  親バージョンの特性を呼び出す予約語 Precursor  再定義されたルーチンでのみ利用可能
  • 37.
    2011/4/7 オブジェクト指向プログラミング入門 937 継承の意味  モジュールの観点  再利用技術としてとびきり有効  型の視点  「 is-a 」関係( Every B is an A )  型に対する値という観点では,集合の包含関係となる.  A のインスタンスに適用可能なすべての操作が B のインスタンスで も適用可能である  継承と分散  動的束縛によって,特定の知識を特定の部分に閉じ込めること ができるようになる  あるクラスを変更したからといって,他のクラスに影響を及ぼさな い  表現の独立性  present := t.has(x) , t に応じて, has の適切なバージョンが使 われる  拡張性と特殊化のパラドクス  クラスをモジュールとみるか型とみるかの違い
  • 38.
    2011/4/7 オブジェクト指向プログラミング入門 938 暫定クラスの役割  抽象データ型に戻る  表明を加えることで,抽象データ型に近くなる  振る舞いクラス  部分的な実装としての暫定クラス  いくつかの ADT の異形態に共通する動作を捕える  例:暫定クラス SEQUENTIAL_TABLE : TABLE の has 特性は, 暫定特性群, start, after, forth, item のみで実装できる  穴の開いたプログラム  部分的にユーザーが中身を決める余地がある  vs. サブルーチンライブラリ  分析と全体設計のための暫定クラス  抽象的かつ厳密に分析,設計を行い,スムーズに(同じ言 語を通して)実装まで移行することが可能となる.
  • 39.
    次回予定  日時: 2011年4月14日(木)13: 00~14:30 場所: LB 2F/A 会議室  内容:多重継承 2011/4/7 オブジェクト指向プログラミング入門 9 39