dhrnameのブログ

プログラミング関連を語るよ

大学教授にも理解できないたった19行のコード

 結論から言うと、構造化プログラミングには、大学教授ですら理解できないようなコードが存在する。しかも、それはたったの数十行である。

 今回はそのコードを紹介するとともに、「ソフトウェアの専門家を育てること」の重要性を訴えていきたい。読者はこの記事の後半で紹介するコードがなぜ理解不能となるのか、ぜひとも、その理由を考えてもらいたい。

定義

 まず、用語の定義を行う。

 「クラス」と「オブジェクト」の2つの用語は「構造化プログラミング」*1の定義に従う。

特殊な実例(instance)が集まったクラス(class)なのである。いい換えると、動的システムに現れる現象を、現象のクラスとしてひとまとめにし、それぞれのクラスをプログラム部分として記述しようというのである。
(「構造化プログラミング」日本語版199ページより引用)
 
存在し続けるブロックの実例のもとになる手続きをクラス(class)という。そして、その実例をそのクラスの対象(object)という。
(「構造化プログラミング」日本語版202ページより引用)
 
 また、技術者たちが「メソッド」と呼んでいるものと「this」の定義は、構造化プログラミングに従うものとする。この記事では「メソッド」の代わりに「(手続きの)遠隔識別子(remote identifier)」という言葉を用いる。
 
G5 :- new Gauss(5); G7 :- new Gauss(7);
……
G5.integral(F, A, B) …… G7.integral(F, A, B) ……手続き integralが対象の外部から何度も使われることを想定している。
(「構造化プログラミング」日本語版207ページより引用)
 
find: if x = val then this tree 
(中略)
findの本体の中に現れる表現
 this tree
は、そのときに扱っている節、すなわち所属物 find の、この特定の実例を所有している参照を値としようとするものである。たとえば、Xの手続き find が関数呼び出し
 X.find(x)
で呼び出され、X.val = xであると、関数の値はX自身を指す参照値である。

(「構造化プログラミング」日本語版218ページより引用)

 
 構造化プログラミングの「サブクラス」はややこしい*2ので、例示にとどめておく。
"truck", "bus", "car"は、クラスvehicleの部分クラス(subclass)と考えてよいであろう。
(「構造化プログラミング」日本語版228ページより引用)

理解不能なコード

 構造化プログラミングのSIMULA67に似た疑似コードを用いる。わかりやすくするためにコードの右端には行番号を付けてある。

 あらかじめ、公正さのために言っておくと、

  • 疑似コードはエラーを起こさない
  • コード中のB() < Aはダイクストラ連接(クラスの継承)
  • コメントは遠隔識別子の返り値を示す

1:  class A() {

2:     this.x = 0;

3:     int procedure p() {

4:       return x;

5:     }

6:     goto L;

7:  }

 

8:  class B() < A{

9:      L: this.x = this.x + 1;

10:    int procedure pp() {

11:        return this.x;

12:    }

13: }

14: objB :- new B();

15: objB.p();  // 1

16: objB.pp()  // 1

 

17: objA :- new A();

18: objA.p();  // 1

19: objA.pp()  // 1

ちょっとした解説

 B < Aなのだから、ダイクストラ連接により、14行目におけるnew B()の計算の順序は、

A:{

  2: this.x = 0;

  3: int procedure p() {...}

}

B:{

  9: this.x = this.x + 1;

  10: int procedure pp() {...}

}

となる。

 17行目におけるnew A()の計算の順序は、6行目のgoto文さえなければ、

A:{

  2: this.x = 0;

  3: int procedure p() {...}

}

と、ただ単にブロックAが実行されるのみである。

 しかし、クラスAのインスタンスobjAから、遠隔識別子を呼び出そうとすると、goto文のジャンプにより、奇妙なことが起きる。

 遠隔識別子ppは本来クラスAに属さない*3手続きのはずである。それなのに、objA.pp()と呼び出せるのである。

 この疑似コードは、計算が問題なく実行できるものの、goto文のせいで、ダイクストラの連接(クラスの継承)が不適当なのである。

 よって、ダイクストラが指摘した連接を用いる「抽象化(Abstraction)」も困難である。つまり、大学教授はおろか、すべての人間にとって理解不能なコードなのだ。

ソフトウェアの専門知識が必要

 正直なところ、構造化プログラミングは、数学と計算論とプログラミングを学べば対処できるものではない。もっと膨大な基礎研究を踏まえた上での、より深い知見が必要だ。

 そのために、ソフトウェアの専門家を育てることが重要なのである。

*1:「構造化プログラミング」(ダイクストラ/ホーア/ダール 共著、 野下/川合/武市 共訳、サイエンス社、1975年8月)英語版は

Structured Programming : O.-J. Dahl, E. W. Dijkstra, C. A. R. Hoare : Free Download, Borrow, and Streaming : Internet Archive

*2:サブクラスに関するダイクストラ階層(hierarchy)の説明はまた別の機会にしたい

*3:クラスAのブロックの中に手続きppは入っていない