猫の小部屋 - ねこのこべや -

猫日誌 -2004-


2004年11月

1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

Topics

>>> [index] [next] [prev]


11月26日(金)

センス・オブ・プログラミング! を弄ぶ 〜リレーショナルデータベース編〜

センス・オブ・プログラミング! において、 なぜだか知らないけれどもリレーショナルデータベースの説明はおざなりです。 たとえば、

リレーショナルデータベースでは、データを表(table)で管理します。

と表現するあたり、猫は「うーん・・・」と思ってしまいます。 なぜなら「表」と「リレーション」は似ているけれど違うモノだからです。 初心者を混乱させないためだとも思うのだけれど(そしてそれは正しいことだとも思うのだけれど) こういう「嘘に近いホント」を教えてしまうあたり、

(前略)

それに対し、インタープリタは事前に一括翻訳するのではなく、 実行と同時に、1行ずつ部分的に機械語に翻訳する。

はっきりさせましょう。この説明は、完璧に間違っています。

インタープリタでは、ソース(または中間形式)を、インタープリタというプログラム自身が 解釈しながら実行します。インタープリタが、ソースから機械語への変換を行うこともありません。

なぁんて事を書いちゃう前橋さんらしくないわぁ(笑)とも思うのです。 (猫には同じレベルの嘘に見えるのだけれどにゃあ) というわけで、今回はリレーショナルデータベースです。

ちなみに、今回の内容は、「リレーショナル・データベースの世界」さんを参考にしています。 ・・参考というか、まんまです。(ごめんなさい。こんなん書こうと思いながら、 オリジナリティを追加出来るほど猫は関係データモデルに精通していません。)

リレーションは表じゃない!

リレーション、と言うと、TM NETWORKのHuman System を思い出す三猫です。 (猫はTMNのファンなのです)

♪出会えない ふたりのrelation 別々の朝 迎えてゆくように

辞書をひもとくと"relation"は「関係」「つながり」「間柄」「相関」という 意味だそうです。 リレーショナルデータベースの「リレーション」は正にこの"relation"。 言うならば「関係」を使ったデータベースのことを リレーショナルデータベースと言います。

では「リレーショナルデータベースで言う"関係"って具体的には何?」 「え〜、リレーショナルデータベースってテーブルでデータを管理するんじゃないの?」 と思われると思います。

確かにリレーショナルデータベースは表(テーブル)チックなデータ構造で、 RDBMSのクライアントツールなんかも十中八九データを表で表示します。 表とはこの場合、複数の項目で成り立ったレコードがどんどん増えていくデータ構造のことですが、 関連モデルと表はとても良く似ているものの、その概念は確かに違います。

リレーショナルデータベースの「関係」は「関係モデル(リレーショナルデータモデル)」に由来します。 この関連を簡単に説明してみます。

(グー, 松 ,男)                          // ← タプル

リレーショナルデータベースの良く言われる「レコード(行)」とは 関連モデルでは「タプル(組)」と言います。

タプルの中の要素毎に、とりうる値は決まっていそうです。 たぶんこんな感じ。

(
    グー,       ・・・ {グー, チョキ, パー}
    松,         ・・・ {松,竹,梅}
    男          ・・・ {男,女}
)

グーチョキバー、松竹梅、男女 の様なのを「アトリビュート(属性)」といい、 これらの属性がとりうる値の範囲(全てのとりうる値)を「ドメイン(定義域)」と言います。 うーん、なんだか良く聞くコンピュータ用語がそろってきたわ♪

では、考えられる全ての組み合わせのタプルを作ってみましょう

(グー   ,松 ,男)        (チョキ ,松 ,男)        (パー   ,松 ,男)
(グー   ,松 ,女)        (チョキ ,松 ,女)        (パー   ,松 ,女)
(グー   ,竹 ,男)        (チョキ ,竹 ,男)        (パー   ,竹 ,男)
(グー   ,竹 ,女)        (チョキ ,竹 ,女)        (パー   ,竹 ,女)
(グー   ,梅 ,男)        (チョキ ,梅 ,男)        (パー   ,梅 ,男)
(グー   ,梅 ,女)        (チョキ ,梅 ,女)        (パー   ,梅 ,女)

結構ありますね。うにゃうにゃ、全部はいらないです。 と、いうわけで必要な部分だけ抜き出してみました。

(チョキ ,梅 ,女)
(パー   ,松 ,男)
(グー   ,梅 ,男)
(グー   ,梅 ,女)
(チョキ ,松 ,男)
(パー   ,松 ,女)

これが「リレーション(関係)」です。 数学的に申しますと、

関係(Relation)をR 属性(Attribute)をAi、その定義域(Domain)をDiとしたとき、

R ⊆ (D1 × D2 × D3 ・・・ × Dn)	

つまり、関係Rは定義域D1,D2,・・・Dnの直積の部分集合である、と言うことなんだそうです。

表と関係モデルの「関係」

と、まぁ、難しくいってみたものの、 「リレーションとは表である」、と言った方が判りやすいわけで、

(グー   ,松 ,男)
(グー   ,松 ,女)
(グー   ,竹 ,男)
(グー   ,竹 ,女)
(グー   ,梅 ,男)
(グー   ,梅 ,女)
(チョキ ,松 ,男)
(チョキ ,松 ,女)
(チョキ ,竹 ,男)
(チョキ ,竹 ,女)
(チョキ ,梅 ,男)
(チョキ ,梅 ,女)
(パー   ,松 ,男)
(パー   ,松 ,女)
(パー   ,竹 ,男)
(パー   ,竹 ,女)
(パー   ,梅 ,男)
(パー   ,梅 ,女)
ジャンケンの手お寿司の格性別
グー
グー
グー
グー
グー
グー
チョキ
チョキ
チョキ
チョキ
チョキ
チョキ
パー
パー
パー
パー
パー
パー

のように、リレーショナルデータは表で表現した方が断然見やすく判りやすいものです。 しかし、表はリレーショナルデータモデルを程よく見せるビューであり、 (そう、MVCの「モデル」と「ビュー」の間柄なのです。) そのモデル自身を「表のようなモノ」と思っているとチョットしたブービートラップに填ることがあります。

これまで猫は関連を書くとき、綺麗に整列させて書きましたが、 関連はタプルがぽんぽんぽ〜んっと投げ込まれているフクロであるだけなので、 本当は

   (チョキ ,梅 ,女)     (パー   ,松 ,男)
(グー   ,松 ,男)
         (グー   ,梅 ,男)(グー   ,梅 ,女)     (チョキ ,松 ,男)

(チョキ ,竹 ,女)                                            (パー   ,松 ,女)

な感じの方がイメージに近いです。 とにかくタプルが詰まっていれば良い為、関係モデルではタプルに順序がありません。 プログラマチックに言えばシーケンシャルなデータ構造では無いのです。 同じように属性も順序を持っていません。各タプルは「じゃんけん」「お寿司の格」「性別」の属性が付いた要素を同じだけ持ってさえいれば良いのです。

順序のあるなしの他に、関係モデルと表では、タプル(行)の重複を許す/許さないという 大きな違いもあります。

ジャンケンの手お寿司の格性別
グー
グー
グー
グー
グー
グー

表はこの← ように、まったく同じ内容のレコードが重複しても「アリ」ですが、 関係の場合、タプルの重複は御法度です。 この「重複を許さない」という性質ゆえにリレーショナルデータベースは 上手にデータを扱うことが出来るのですし、 DBを知っているプログラマさんなら、まったく同じ内容のレコードが作れないことも 既に経験している「当たり前」のことかしら。

それでも、「"アクセス" と "エクセル" って何が違うの?」なぁんて思っている素人さんや RDBMSは単に効率の良く表を検索できるDBMSだと思っている方も居るわけで、 当たり前のようでもちょこっと説明しとくのは損ではないかしらね。

インターミッション (オブジェクトと関係データモデル)

オブジェクト指向言語においてオブジェクト(またはクラス)は連想配列により実装されることが多いです。 また、ドメインは「変数の型」とほぼ等しい概念ですし、この意味で「オブジェクト」と「タプル」は かなり近い関係にありそうです。

でも、「タプル」が「オブジェクト」たりうるには、定義域の要素に関係を含められる必要がありそうです。 (そして贅沢を言えば「関数」を要素として扱える必要もありますが、 オブジェクトの状態のスナップショットを撮るという意味ではいらないですにゃ。)

オブジェクトの状態のスナップショットを撮る場合、実は木構造のデータが便利です。 その点XMLはとても都合がよろしいのですが、現在のリレーショナルデータベースは木構造をそのまま表現することが出来ません。 なぜかというと、現在のリレーショナルデータベースは「一階述語論理」を基礎としているからです。 (決して、関係データモデルが木構造を扱えないわけではないです。)

って、いきなり出てきました「述語論理」。そういえばSQLでも聞くことの多い「述語」という言葉。 そう、述語論理とリレーショナルデータベースは切っても切れない中なのです。

論理を問うのが述語です

ん〜〜、、無理矢理繋げてしましました(笑)。無理して繋げたのです、早速本題にはいりましょう。

述語というと、

ボクは 走る。
 ↑      ↑
(主語) (述語)

なぁんてのを思い浮かべますが、 この場合の「述語」とは「論理値を返す関数」です。 プログラム言語で言うとtrue/falseを返すような「評価式」(if-else文やwhile文などの条件式ですね)に近いものですが、 述語(predicate)の場合は、「true / false / unkown」の3値を返すのが特徴です。

実はリレーショナルデータベースの世界、関係モデルの世界は、真理値が「真・偽・不明」から成り立つ3値論理に基づく世界なので、

「ジャンケンの手」は「グー」ですか?

という命題には真理値(「はい」「いいえ」「わかりません」)で答えることが出来るのです。 この命題(proposition)を記述する言語こそが(乱暴な言い方ですが) SQL文で、

おい、そこの「ホゲテーブル」。           //←「ホゲテーブル」という名前の「関係」
あんたの中で、

「ジャンケンの手」は「グー」である。   //←命題。各タプルが「はい」「いいえ」「わかりません」と答える

・・・な関係を、                         //←関係 = タプルの集合
ゴッソリよこすだわさっ!

と、関連(つまり、テーブルですね)に対して要求する、、という風に 個々のレコード(タプル)にアクセスするでななく、関連全体への操作を指示するのが特徴です。 これにより、リレーショナルデータベースはポインタの魔の手から (そう、Javaのようにポインタじゃないフリをするではなく完全に)逃れることができたのです。

(ちなみにこれで得られた関係は、 「ジャンケンの手」が「グー」な関係ですね♪)

NULL は VOID にあらず

述語は『「命題」に対して「真理値」を返す関数』のようなもので、 リレーショナルデータベースの礎である「関係モデル」の世界では、 「真理値」は 3値論理――「はい」「いいえ」「わかりません」から成り立ちます。 と、言うことは、リレーショナルデータベースの述語(「比較述語」とか「IN述語」とか「ALL述語」ですとか) はおのずと「わかりません」を返している事になります。

「え〜っ、RDBMSで "UNKNOWN" なんての見たことがない」? いえいえ、きっと見たことがあるハズ。 そう、DB設計では許すな許すなと言われる存在、NULLの、正体こそが UNKOWNです。

NULLは「どんな値なのか わかりません」ですから、もし、「ジャンケンの手」に NULLが入ったタプルがあるなら、

「ジャンケンの手」は「グー」ですか?

の答えは「グー」だか「チョキ」だか、はたまた「パー」だか、わからないのでわかりません、ですし、

「ジャンケンの手」は「NULL」と等しいですか?

の答えは「ジャンケンの手」は「わからないけど なんか」と等しいですか、と聞かれているも同然なので、 それこそわかりませんです。

(ここで注意すべきは「ジャンケンの手はわからないですか」とヒトは読んでしまいがちなところです。 "hoge = NULL" という命題に対し、 hogeがNULLの時も 答えが「はい」に成らないのは、 NULLが「わからない何か」を指すから・・なのですが、直感的にそういう風にヒトは読んだりしないのよね)

プログラム言語は殆どの場合 2値論理(命題に対し「真」か「偽」のみ返る)で成り立っていて、 NULL (例えばNULLポインタやNUL文字('\0')等) は、意味に置いて「何ない」を示します。 しかし、リレーショナルデータベースの世界は、3値論理(命題にたいし「真」か「偽」か「不明」のみ返る)であり、 NULLとは「不明」を表すため、命題の引数にNULLが紛れ込むと「わからない連鎖」が発生し、 プログラマ直感とは違う動き(ようするにバグですね)に成ってしまうことが往々にあります。 (そもそも、ベテランプログラマでさえ リレーショナルデータベースの世界の「NULL」が 真理値の一つであることを知らないことすら多いのです)

最後に、どれぐらい直感と異なるかを 真理値表で見てみましょう

(AND) true unk false
true true unk false
unk unk unk false
false false falsefalse
(OR) true unk false
true true true true
unk true unk unk
false true unk false
(NOT) NOT
true false
unk unk
false true

知らなかった方、「いままで良く無事にSQL文が書けてたわぁ・・・」って、ぞっとしませんでした? (猫はぞっとしました。(^^;) )

センス・オブ・プログラミング!唯一の大罪

SQLは欲しいデータを取得するための手続きではなく欲しいデータそのものを 記述します。プログラマさんが初めてSQLに触れたとき、きっと強い違和感を感じただろうと思うのですが、 それは他のほとんどの言語(構造化言語やオブジェクト指向言語もも含めて) は結局ミクロ的には手続きを記述するものなのに、SQLはまったく手続きが登場しないからです。

SQLは集合に対しこんな集合が欲しいよと記述するだけで、どうやってその集合を得るかは書けません。 というか、書いてはいけないのです。 SQLは「結果を得るための手続きを記述する」という低レベルなことはせずに 「結果そのもの」を記述する超高級言語です。 (これは「関係」という抽象度の高いデータモデルがあればこそ実現したものです。)

センス・オブ・プログラミング!では、

しかし、構造体とポインタによるデータ構造になれた人は、こう思うのではないでしょうか

「部コード」なんかじゃなくて、「部」へのポインタを持つべきなのでは?

正論です。しかし、リレーショナルデータベースでは、それを直接表現することは出来ません。

(中略)

リレーショナルデータベースは、ある意味、必要なときにゴリゴリ検索する「力任せデータベース」であるといえます。

の様に書かれています。たしかに、これは タプルの要素として関連を持ち込めないリレーショナルデータベースの制約によるものです。 しかし、たとえ木構造を実現できるRDBを作り出すにしても、そこにポインタの概念を持ち込んでは、 元も子もありません。だってリレーショナルデータベースが一生懸命追い出したのがソレなんですもの。

つらつらと書いてきました、リレーショナルデータベースの雑学ですが、 猫がいったい何が言いたいのかというと、「センスが一つたりないかしら?」ということ。 「SQLは"手続き" をまったく書かない言語」「3値論理」「RDBのデータ構造の本質は "テーブル" ではなく "関連"」。 こういう事を知らないプログラマはホントに多いですが、コレを知っているか否かって 良いプログラムを書けるセンスの一つになる、と猫はおもいます。

なによりまずいわぁと思うのが「リレーショナルデータベースでは、それを直接表現することは出来ません。」のくだり。 ここは正しくは「リレーショナルデータベースでは、それを直接表現することはしません。だと、 猫はおもうのよねぇ。

せっかくのセンス・オブ・プログラミング!なのですから、 ここら辺のセンスにも触れて欲しかったわぁ、と思うのですが、 「一見不便そうなリレーショナルデータベースもそれなりに必然性があると言えましょう。」など、 「リレーショナルデータベースはポインタが無いから痛し痒しだなぁ」という雰囲気に充ち満ちています。

ポインタが無いことを責めるかのような空気の漂う センス・オブ・プログラミング!ですが、 ポインタはデータの在処を指し示すもの。リレーショナルデータベースは、 「データの位置」から解放されるために関係モデルを使っているのですから、 ポインタがないのがいいのですよ、くらいのことは言うべきです。

ポインタが思い通りに弄べるようになると、 データ構造とそれを操作するアルゴリズムを考えるのが楽しくなってきます。 そういう楽しみは、良いプログラマとなるためには良い鍛錬の機会なのですが、 なまじフォース ポインタ が強力なためその暗黒面にひきづられ、 ポインタより抽象度の高い概念ですら「非効率」と言ってしまう・・・。

センス・オブ・プログラミング!の中で唯一暗黒面をちらつかせる リレーショナルデータベースの項は、 めずらしくオビワン前橋さんらしからぬ所業よねぇ、と思うのです。

参考文献
リレーショナル・データベースの世界

(参考にした・・というより ほとんどパクリのようなモノです。ごめんなさい。 素晴らしいできばえで、目から鱗です。大変オススメですよ♪)

|++ month top ++|

11月19日(金)

猫はかつて、最長不倒関数を関数分割したら、 「読みにくくするな」とそこの会社のSEさんに言われたことがあります

彼曰く、ソースの上から下へ順番に読んでいけない関数分割は、 とても読みにくいソースなんだそうです。 その会社はCOBOL文化が支配していて、彼はCOBOLerなのでしたが、 開発していたのはASPを使ったWebアプリケーションです。 ああ、もう、勉強しない技術者は嫌い、とその日は一日中起こっていました。 (ええ、書き直させられたのです。) 猫のCOBOLer嫌いはその瞬間に始まったのでした。

というわけで、COBOLには罪はないけれど猫はCOBOLerが嫌いなのです。 「良いプログラムを書こう」と勉強したり、努力したりする姿勢がまったく見られない、 そんなプログラマと呼ぶのもはばかれる人たちが多いという現実は、 Pythonのパラドックスの逆パターンよね、と思うのです。

センス・オブ・プログラミング! を弄ぶ 〜構造化プログラミング編〜

しかし罪の子はCOBOLerだけではありません。 (いえ、Visual Basican もそうだ・・と言うわけではないですよ) CやJavaの開発でも、可読性のために最適なサイズで関数を分割することに 理解を示さないプログラマが居ます

ダイクストラさんが提唱した構造化プログラミングは、 読みやすく、理解しやすいプログラムを作る為のプログラミング手法です。 人はただ数が多いだけで何がなんだかよくわからなくなります。 だからプログラムの「難しさ」が同じ程度でも「規模」が大きくなるだけで、 とたんに人間の管理能力の限界を超えてしまい、プログラムを読んでも 「正しく動くこと」を理解できなく成ってしまいます。

ダイクストラさん曰く、「良いプログラムとは正しく動くだけでなく、 正しく動いていることが解りやすいプログラム。」であるわけで、 構造化プログラミングとはそのためにあるのです。 構造化プログラミングとは、

構造化プログラミングとは
  • 目的:大規模プログラムのソースコードを、容易に正しさが解るようにすること。
  • 概要:「プログラム」と「データ」を構造化する。(特に、階層構造を持たせる)
  • 構造化の効能:
    1. 見かけの規模を人間の管理能力内に落とし込める
    2. 小さなプログラムの固まりそれぞれの正しさを証明していけば、 おのずとそれらを組み合わせた大きなプログラムの固まりも正しさを証明できる。
  • 主な手法:
    1. フロー制御にgoto文を使わず、制御構造(順次・選択・反復) を再起的、階層的に用いる。
    2. 段階的詳細化(トップダウン法)を用いる。(処理の抽象度に従い階層構造を作る)
    3. カプセル化(詳細な処理を隠蔽しする。結果的に相互依存を減らす)

の、様なモノです。ちなみにこの階層化された箇条書きですが、 構造化ドキュメント、なぁんて呼ばれます。構造化プログラミングは 乱暴に言えばこれのプログラミング版で、 プログラムに文章のように「第一章、第二項、第一節」という 段階的に詳細になるトップダウンのツリー構造を持たせることで可読性を上げることです。

章立てのしっかりした文章は全体の見通しがよくなり、 ずらずらずら・・・と無秩序に書き出された文章よりも文意が読み取りやすいです。 同じように適切に構造化されたプログラムは、規模が大きくなっても その文意、つまり意図する処理を読み取りやすいです。 可読性があがれば「間違えている」ということを読み取る可能性も高くなります。 また、構造単位毎に「正しさ」を証明すればそれを積み上げたモノも「正しい」ことになります。

これが構造化プログラミングの概略ですが、 構造化プログラミングですが、なぜだか世間では誤解している人が多く 「goto文を使わずに 「順次」「選択 (if-else文)」「反復(while文)」のみを使って プログラムを作ること」だと思っている人が多いです。 猫としては

構造化プログラミングとは、プログラムを三大論理構造(「順次」「選択」「反復」)のみで構成する プログラミング技法である。

という本があればそれはトンデモ本だと断言します! だってそう書くってことは、どうせダイクストラさんの原著を読んでいないでしょう。 そういうリファレンスを読まずに平気で本にしちゃう方の本は信用ならないからです。

って、あれ・・・? センス・オブ・プログラミング!にもそう書いてある・・・・。

構造化プログラミングって何ですか?

構造化プログラミングとは大規模なプログラムをどのように書けば良いプログラムにできるか、という手法です。 良いプログラムとは、人間がプログラムを理解しやすいプログラムです。 人間が理解できるとは、正しく動くことを理解できることです。 (つまり、読んでみて「フミフミ・・・あれ、コレ間違ってるんじゃない」とかサッと解るようなプログラムです。)

ヒトの処理能力には限界があります。特に「ちょっとことをたくさん覚えておくのが難しい」というのは 脳の偉大な欠点の一つです。 (「覚えておく」部分だけを外部に任せてしまう「そろばん」を使うと 圧倒的な計算能力を得られるのですから、それがいかにボトルネックか、解ると思います。)

というわけで、長大なプログラムはヒトの管理能力の限界ゆえに、 大きいと言うただそれだけで訳が解からんちんになってしまいます。 そんなヒトが大規模プログラムを開発するためには、単純に数を減らせば良いんです。 とは言っても、大きなものを使うのに数を減らせとは本末転倒、それが出来れば苦労しません。 だから、人間は「抽象化」つまり 本質のみ取り出して見かけのボリュームを下げることで、 人間が理解できるサイズにシェイプアップするのです。

オブジェクト指向だとか構造化プログラミングだとかは、 乱暴に言ってしまえば人間の認識テクニックである「抽象化」を プログラミングに適用して、「如何にプログラムの見かけの規模を小さくするか」という手法です。 で、今回扱う構造化プログラミングでは、主に段階的詳細化を言う手法で 見た目の規模を小さくするため、プログラムを構造化します。

それって具体的にはどうやるの?

と、いうわけで、 構造化プログラミングは主な抽象化の手段として階層化を行います。 より抽象的なものをトップに、ボトムに下るにつれだんだんと詳細に、それを一本の根を持つツリー構造にして プログラムの流れを表現する手法です。・・・って言葉でいってもわかりにくいですね。 つまり、

                                                                      ┌・ファイル選択ダイアログを開く
                                ┌ ・ユーザにファイルパスを問合せる →│・[OK]or[キャンセル]ボタン入力を待つ
                                │     |                              │      + [OK]ならば、ファイルパスを取得
                                │     |                              └      + [キャンセル]なら、ファイルパス=無し
                                │     +(パス無しなら処理終了)(return)
                                │                                    ┌・パスから拡張子を取り出す
・テキストファイルを表示する→  │ ・テキストファイルか確認する ──→│・拡張子が "txt"か判定する
                                │     |                              │      + "txt"ならば確認結果はOK
                                │     |                              └      + "txt"でなければ確認結果はNG
                                │     +(確認結果がNGなら処理終了)(return)
                                │                                    ┌・パスを元にファイルオープン(API)
                                │ ・ファイルオープン ───────→└      + ファイルポインタがNULなら取得失敗
                                │     +(取得失敗なら、処理終了)(return)
                                │                                    ┌・キャンバスを取得
                                │                                    │                                      ┌・キャンパスの左上にブラシを移動
                                │                                    │                                      │  ┌(繰り返し)
                                │                                    │                                      │  │・ファイルから1行読み込みを試みる
                                │                                    │                                      │  │      + 読めなかったら繰り返し終了
                                │                                    │                                      │  │                                      ┌・ブラシをキャンパスの一番左に移動
                                │                                    │                                      │  │                                      │  ┌(繰り返し)
                                │                                    │                                      │  │                                      │  │・一文字読み込む
                                │                                    │                                      │→│                                      │  │    + 読み込めなかったら繰り返し終了
                                └ ・フォームにテキストを表示する ─→│・ファイルの中身をキャンパスに描画 → │  │・1行分の文字を順番に描画 ─────→│→│・読み込んだ文字をブラシで描画
                                                                      │                                      │  │                                      │  │・ブラシを一文字分左に移動
                                                                      │                                      │  │                                      └  └(繰り返し)
                                                                      │                                      │  │・ブラシを1文字の高さ分下へずらす
                                                                      │                                      └  └(繰り返し)
                                                                      │・ブラシを解放
                                                                      │・キャンパスを開放
                                                                      └・キャンパスの内容をフォーム描画に反映

こうですっ!

ダイクストラさんは、巨大なプログラムを扱うには人間の能力は不足していると言います。 確かに上のリストから階層構造のみをとってしまった、コレ(↓)

・ファイル選択ダイアログを開く
・[OK]or[キャンセル]ボタン入力を待つ
      + [OK]ならば、ファイル名を取得
      + [キャンセル]なら、パス無し →(パス無しなら処理終了)goto ERROR
・パスから拡張子を取り出す
・拡張子が "txt"か判定する
      + "txt"ならば確認結果はOK
      + "txt"でなければ確認結果はNG →(確認結果がNGなら処理終了)goto ERROR
・パスを元にファイルオープン(API)
      + ファイルポインタがNULなら取得失敗→(取得失敗なら、処理終了)goto ERROR
・キャンバスを取得
・キャンパスの左上にブラシを移動
┌(繰り返し)
│・ファイルから1行読み込みを試みる
│      + 読めなかったら繰り返し終了
│・ブラシをキャンパスの一番左に移動
│┌(繰り返し)
││・一文字読み込む
││    + 読み込めなかったら繰り返し終了
││・読み込んだ文字をブラシで描画
││・ブラシを一文字分左に移動
│└(繰り返し)
│・ブラシを1文字の高さ分下へずらす
└(繰り返し)
・ブラシを解放
・キャンパスを開放
・キャンパスの内容をフォーム描画に反映

:ERROR

を、一目で見て何をやっているかを理解するのは難しいわねぇ・・(^^;)

人間が一目で正しいを理解できる様にするために、1度に目に入るボリュームを小さく絞ることが必要で、 そのためにプログラムに階層構造を持たせましょうよ・・というのが構造化プログラミングの本質です。

「階層」を成り立たせるには?

階層を成り立たせるには一つの条件があります。それは「階層を下ったところから上る」です。 ・・・って絵を見れば一目瞭然ですね。構造化プログラミングでは、必ず 「入ったところから出る」必要があります。 なので、「入ったところから出てこない」フロー制御が書ける goto文は、 構造化プログラミングにとっては、邪魔者です。

ダイクストラさんは、構造化プログラミングを成立させるためには、 「入り口が一つ、出口が一つ」の構造をブロックのように 積み重ねればOKよ、・・ということで、三大制御構造「順次 (=単に文が並んでいるだけ)」「選択(=if-else文)」「反復(while文)」を使って プログラムを作ればいいよ、、 と書きました。

この三大制御構造は、前の二つは「数え上げ(全てのパターンを網羅する)」という方法、 最後の反復は「数学的帰納法」で正しさを証明できます。 そうやって一つ一つの制御構造を証明していけば、 全体に正しくなります。 入口・出口が一つづつなら、前後の制御構造に関わらず、 内部の正しさは保証されます。正しい制御構造を数珠つなぎにすれば、 あ〜ら不思議、全体が正しくなってしまうわけです。

この性質は階層化したプログラムを作る場合にはとても便利です。 なので、ダイクストラさんは 構造化プログラミングをする際の具体的な手段の一つとして、 三大制御構造のみを用いてプログラムを記述することを提唱しました。

人が解りやすい構造

ここで、現代の目に戻って言うならば、 構造化されたプログラムの一つのブロックが十分にカプセル化されていることこそ、 構造化プログラミングに必要な用件である、と言えます。 三大制御構造以外を用いても、 階層を成す一つのブロックのカプセル化さえ保たれるならば、 構造化プログラムの部品としての資格は十分です。

現在では、関数の途中returnや、while文中のcontinue文やbreak文といった、 構造化プログラムの部品としての用件を満たしながらも、 三大制御構造とはチョット逸脱した便利な部品が提供されています。 goto文だって、十分な小ささを持ったカプセル化されたブロックの中で 使うのならば、構造化を壊すことなく使えます。

逆に、三大制御構造のみで記述されていたとしても、

function	superRobot changeGetter( superMachene eagle ,superMachene jaguar , superMachene bare )
{

    superRobot  getterRobo = null;      /* ゲッターロボ取得バッファ     */


    if( eagle.isReady == true )         /* イーグル号準備よし           */
    {
        if( jaguar.isReady == true )    /* ジャガー号準備よし           */
        {
            if( bare.isReady == true )  /* ベアー号準備よし             */
            {
                /* 決めぜりふを言う     */
                print( "チェェェェェンジッ! ゲッタァァァアァッ!!" );

                /* 各マシンが変形する   */
                eagle.tranceForm();
                jagger.tranceForm();
                bare.tranceForm();

                /* 合体する             */
                getterRobo  = new superRobot( eagle ,jagger ,bare );
            }
        }
    }

    reutrn( getterRobo );
}

では、ネストが深くって人間がプログラムの構造を把握にくいです。 (こういう実行条件をどんどんネストしてくプログラムって、 下手なプログラマさんが良く書きます。(TT) えぅえぅ) この階層構造をさっきのようにツリービューしてみると、こんな感じです。

チェンジゲッター → イーグル号の準備OK→ ジャガー号の準備OK → ベアー号の準備OK →┌・決め台詞を言う
                                                                                  │・イーグル号変形
                                                                                  │・ジャガー号変形
                                                                                  │・ベアー号変形
                                                                                  └・合体する

・・これって、人間が把握している「チェンジゲッターという概念」の構造とは違うんじゃない? 確かに階層構造には成っていますが、人に解りやすくするために階層化してる・・・には当てはまらないです。 たとえ三大制御構造のみで書かれていたとしてもこれを構造化されているとは言いません!

チェンジゲッターの概念としては、

チェンジゲッター →┌・各ゲッターマシンの準備OK? →┌・イーグル号準備OK?
                   │                              │・ジャガー号の準備OK?
                   │                              └・ベアー号準備OK?
                   │・決め台詞を言う
                   │・各ゲッターマシン変形  ──→┌・イーグル号変形
                   │                              │・ジャガー号変形
                   │                              └・ベアー号変形
                   └・合体する

じゃないかしら? これをコーディングすると、

function	superRobot changeGetter( superMachene eagle ,superMachene jaguar , superMachene bare )
{

    superRobot  getterRobo = null;              /* ゲッターロボ取得バッファ     */


    /* 各ゲッターマシンの準備がOK? */
    if( eagle.isReady  != true )                /* イーグル号           */
    {
        return( null );
    }
    if( jaguar.isReady != true )                /* ジャガー号           */
    {
        return( null );
    }
    if( bare.isReady    != true )               /* ベアー号             */
    {
        return( null );
    }

    /* 決め台詞を言う */
    print( "チェェェェェンジッ! ゲッタァァァアァッ!!" );

    /* 各マシンが変形する */
    eagle.tranceForm();
    jagger.tranceForm();
    bare.tranceForm();

    /* 合体する  */
    getterRobo  = new superRobot( eagle ,jagger ,bare );

    reutrn( getterRobo );
}

な、感じになるでしょうか。 いわゆる途中returnです。

「三大制御構造のツリー構造 = 構造化プログラム」と思っている人は これを「構造化プログラミングじゃない」と言うかもしれません。 でも、人のための構造化プログラミングなんです。 「三大制御構造のみを使う」というのは、「入ったところから戻ってくる」という 構造を守るための手段に過ぎません。

構造化プログラミングの精神は 「人が認識する抽象構造を段階的詳細化で描くこと」なので、 猫はコチラこそがより構造化プログラミングしてると断言します。

コメントによる構造化

三大制御構造のうちの一つ、「順次」は、実はただ単に 文が並んでいるだけのことです。 ただ単に並んでいるだけなので、なかなか順次を集めて作った構造を コードだけではっきりと一つの構造なのだよ、と判別させるのは 難しいモノがあります。

う〜ん、こういうのいちいち関数にしてたら大変だしぃ、でも 散文的に並んでると読みにくいばかりか、 他のプログラマさんがいじるときに、猫の意図する構造をぶっ壊しちゃうかもしれないしぃ・・、 と悩むコトもあるかもしれません。 けどけど、こういうときの定番は、順次が集まって出来たブロックに、 コメントで名前を付けて書いてあげることなんです。

さっきのプログラムでは、

/* 決め台詞を言う */ print( "チェェェェェンジッ! ゲッタァァァアァッ!!" );
/* 各マシンが変形する */ eagle.tranceForm(); jagger.tranceForm(); bare.tranceForm();
/* 合体する */ getterRobo = new superRobot( eagle ,jagger ,bare );

と、いう風に構造化しましたが、コメントと空白行以外で、 この文の羅列に抽象かされた固まりを示すものはありません。

この手のコメントは、構造化文章の見出し行(たとえば、「1.トラックボールの歴史」みたいな)に相当します。 このコメントがあることで、

  • このコードブロックの目的が何なのかを宣言することで、 拡張時にコードの分離を乱すようなソースの挿入にたいして抑止力になる。
  • ヒトがコードを眺めるとき、一行づつよまなくても、見出しコメントだけを拾うことで、 高速に目的コード部位を探せる

という効果が生まれます。

例えば、変形の手続きについて、テストしてみたら 「あっ、ロケット噴射しっぱなしだと変形のときに内部メカが焦げちゃうじゃん」 ということに気が付いたとしましょう。 その場合、

「ロケットエンジンを切る」→「変形する」→「再びロケット噴射」

という手続きになります。これは、「変形する」ブロックに含まれるべき「変形前準備」「変形事後処理」であって、 「変形」大ブロックの中に入れて欲しい手続きなのです。 そのためにも順次のみでつくられた「変形」ブロックをブロックだと明示する必要が あるって言うわけです。

(と、コウイウ事を意識して入れられるか否かが構造化プログラミングをしてるかしてないか、 なのですけどね〜。プロと名乗っていながら出来ないヒトがあまりにも多いのが現状です(TT) )

関数での構造化

構造化プログラミングとは、章立てされた文章(構造化文書)に良く似ています。 構造化プログラミングの構造は人間のための構造なので、 構造に対し適切な名前が付いているのがモアベターです。

コメントで構造を示すやりかたは、お手軽でよいのですが、 強制力はありません。なんと言っても構造の内と外のデータの入出力について、 構造内のソースを全部見なくちゃダメ、というのも段階的抽象化という意義からは、 チョット弱いなぁと思います。コンピュータ側が構造を認識できないのも問題かもしれません。

そんなわけで、構造化プログラミングでは、関数による構造のパッケージングを提唱しています。 もともと関数は複数箇所に共通のコードをパッケージングするものなのですが、 構造に適切な名前を付けられ、(呼び出し側の)見た目のコード量を減らせて、データの入出力も限定する関数は 「段階的詳細化な構造」を表現するのにピッタリです。

余談ですが、関数でカプセル化し、情報を隠蔽することを 原著のなかでは「モジュール化」と呼んでいますが、 時代の流れは恐ろしいモノ・・・、今は関数レベルでモジュールと呼べるような 規模とは遠く離れてしましました。(最早ファイル単位でもモジュールとして役者不足・・。) ・・ああ、オブジェクトが出来るわけです(TT)

大誤解

そもそも三大制御構造のみを使うことは、 プログラムを構造化する手段であって、決して定義ではありません。

今回のテーマは「人間に解りやすい階層構造 = 段階的詳細化した構造」を プログラムに持たせることが構造化プログラムですっ! ――と言いたかったので、そっちに重点を置きましたが、 もうチョット論理的アプローチで 説明するなら、「構造化プログラミング」中のダイクストラさんの弁をもって 三大制御構造のみを用いることが、必要十分用件でないことを説明することも出来ます。

三大制御構造を用いる理由は、 正しさを数珠繋ぎに出来ることで、全体として正しく出来るためなのですが、 個々の制御構造の中身の正しさの証明は、 「数え上げ」と「数学的帰納法」に頼ることになります。

ところが、ダイクストラさんは構造化プログラミングの中で「数え上げが有効なのは プログラムのサイズが十分に小さいときだけである」と口を酸っぱくして 言ってます。 つまり、三大制御構造だけで出来ているプログラムでも、階層化が十分でないと、 ダイクストラさんが構造化プログラムの目的とした、 「大規模でも正しいことが容易に証明できるプログラム」を実現することが出来ません。 この状態のプログラムは構造化プログラミングたり得ないのは自明の理です。

にもかかわらず、 goto文や行番号全盛時代に与えられた 「三大制御構造のみをつかってプログラムをつくる」というインパクトの強さから、 三大制御構造のみを用いて記述することさえ出来れば、 プログラムが構造化されている、なぁんて短絡的な解釈が世の中に蔓延し、 本当はプログラムを構造化する手段の一つに過ぎなかった 「三大制御構造のみを使ってプログラムを記述すること」が、いつの間にか 構造化プログラミングの定義のように扱われるようになってしまいました。

結果、構造化されていないプログラムを平気でかくプログラマはちまたにあふれかえり、 しかも自身が構造化プログラミングすら出来ていないことを認識することも出来ないという 最悪な状況が、生まれてしまいました(TT)

センス・オブ・プログラミング!

センス・オブ・プログラミング!を読んでいると、 「構造化プログラミング」の定義をよく知らないんじゃないかしら、と思わせる 言い回しが結構あります。 でも、この本の中で良いプログラミング手法として取り上げれていること ――長い関数は書かないようにしましょう、とか―は、 かなりの面で構造化プログラミングのそれと一緒です。

実は、内容だけを見るならば、 センス・オブ・プログラミング!は、かなり優れた構造化プログラミングのテキストです。 読んだ人がそれを「構造化プログラミング」だとは思わないというのが難ですが(^^;)、 解りやすくて説得力が出るように工夫されている点は、かなりオススメです。

ただ、それでも猫が許せないのがただ一つ、

しかし――実のところ、いまの時代、構造化プログラミングをことさら意識する必要はないでしょう。 いまどきのまともなプログラミング言語を使えば、特に意識しなくても自然に構造化プログラミングになるからです。

のくだりです。ここだけは絶対見過ごせません。

|++ month top ++|

11月12日(金)

更新がぱたりと止まってしまった三猫です。

お仕事がとてもハードになってきたことが主たる原因ですが、 日曜は休めていますし、決して時間がないわけではないのです。

日頃ちょっと有能なシステムエンジニア(自称)と息巻いている猫ですが、 脳内理想と異なり、スーパーな仕事量をスーパーな勢いでこなすことが 実は出来ないことが判明した結果、大変なことになってしまいました。 (増長した自意識を摘み取れるのはとても良いことです。)

その差を埋めるためには頑張るしかないため、 猫はとてもとても頑張っていて、たとえるならばそれは100m走の勢いで走り続けるマラソンの様。 ぜぇぜぇ、はぁはぁ・・・。歩きたいよぉ・・。ゴールがみえないよぉ。えうえう。 と喘いでいる今日この頃です。

センス・オブ・プログラミング! を弄ぶ 〜コメント編〜

というわけで、今月の猫はプログラマモードなので(M-x programer-mode)プログラマらしく プログラミングなネタを振ってみることにします。

猫の好きなテクニカルライター (ぱ)さんこと前橋和也さんが 最近センス・オブ・プログラミング!と言う本を出しました。 内容としては職業プログラマのテクニックをギュッと凝縮した感じで、 プログラム言語がわかるだけのプログラミングオタクさんと、 保守性をちゃんと視野にいれた職業プログラマを分ける一線を教えてくれる貴重な本です。

プログラム言語を理解できればプログラマというかというと、決してそうではありません。 プログラム言語が使えるということは、大工さんでいうところの「のこぎりが使いこなせる」とかそういうことで、 道具をつかってシステムをどう作り上げるか、というテクニックは別にあるのです。

プログラム言語の入門書は、あくまで言語の入門書で、言語の使い方+αしか教えてくれませんし、 サンプルソースもちゃんとしたシステムになっていません。 だから、なかなか現場での経験をしていない「プログラマ志願者」が 独習だけで真のプログラマになるのは難しい世の中だったりするわけです。

そんな中で、なかば「口伝」とかしている「真のプログラマに必要なスキル」を 書籍という形にまとめてくれたのが本書です。 なんとなく暇つぶし(いや、暇じゃないので現実逃避でしょうか・・)用に買った本書ですが、 読み進めるウチに、猫も後輩を育てるときに良くいう言い回し、注意することなどに ひょっと出くわし「ああ、ううん、こんなこというねぇ」と にやにやしながら読んでしまいました。うん、オススメです。

オタクの習い性

この手のカテゴリの本では、決定版だと猫も太鼓判を押すセンス・オブ・プログラミング!ですが、 猫もプログラマの端くれです、気になる記述や納得に行かない記述もあります。

もっとも多くは重箱の隅だったりして、 そういうのを突っつくのが愉しいのがオタクさんというヤツです。 猫も立派にオタクさんなので、突っつきたい衝動にあらがうことが出来ません。 まぁ、たまには(?)重箱の隅をつつくのもいいよね、ということで、 お遊び半分つっついてみることにしました。つんつん。

識別子のコメント

と、言うわけで、第一回は「コメント」です。(センス・オブ・プログラミング!では、になります。)

センス・オブ・プログラミング!の中で、前橋さんは、「コメント」をこのように説明しています。

コメントを山のように入れるより、どうせならコメントなんかなくても読めるプログラムを書くように心がけるべきでしょう。

確かに、カーニハンさんのプログラミング作法のなかでも、同じようのなスタンスで コメントを解説していますし、 ハッカーよりのプログラマさんに「識別子の名前を適切につけることで コメントが無くても読みやすいプログラムを書ける。その上で 足りない分はコメントで補う」というスタンスは、人気が高いように思われます。

しかし、猫はこれには大いに疑問を感じます。 だってあたしたち日本人なんですよっ!

識別子と日本語

センス・オブ・プログラミング!では、以下の例を出して 識別子の定義(変数宣言、関数定義文など)にそれの名前を記すコメントの ばかばかしさを説いています。

無駄なコメントの例として私がよく挙げるのは、以下のようなモノです。
int user_id;  /* ユーザーID */
このコメントを見て無駄であると思えない人は、どこか感覚が壊れています。

確かに、「user_id」=「ユーザーID」であることが判らないなんて、 どこかが壊れています。それはまったくその通りです。

でも猫をみて、ちょっとずるいな、と思ってしまいました。 この例は「識別子の説明コメントは不要」と言う結論のための例です。意図的すぎて鼻につきます。 だって、「ユーザーID」ってカタカナ語じゃないですか。 「ユーザーID」の様な英語由来のカタカナ読みを例に「おなじって判るでしょ」と説くのは 例外をもって一般を説いているので、卑怯です。

識別子の命名は元々難しいものなのですが、日本人の場合「英語がわからない」という問題がそれに輪をかけてしまいます。 識別子として理想なのは「誰もが知っている英単語で、意味を取り違えない様につける」ことです。 たとえピッタリの意味の単語があろうとも、知られていない単語を使えばそれは 識別子から意味や用法を類推することが不可能ということに他なりません。

たとえば、

int trackball_presence;

という変数が、いったい何を示しているのか、 万人が判るとは言えません。もちろん辞書を引っ張り出せば誰でも判るのですが、 コードを読む最中にいちいち辞書をひっぱらいださせられるくらいなら、

int trackball_presence;         /* トラックボールの有無         */

みたいにコメントを付けといて、と思うのが普通じゃないかしら。

またよく知られる英単語で構成したとしても、 日本人の平均英語学力はあまり高くないので、 その意味が非常に曖昧になることは避けられません。

例えば「max_ball_count」て、何のことだと思います? きっと「いちばん大きいボール」の数なのか、一番大きい「ボールの数」なのか、 解釈が揺れるんじゃないかしら。

これは命名の不手際で「もっと良い名前を付けましょう」という事なのかもしれません。 (実際そのように言われます。) 大玉の数なら「number_of_max_ball」とか「n_max_ball」とかなのでしょう。(・・・多分(^^;) 英語苦手です) しかし、何より問題視しなければならないのは、日本人はこういう名前に違和感を覚えないことです。

違和感を覚えないなら、「よくない」名前を量産しがちです。そしてそれを防ぐのは無理でしょう。 識別子に日本語が使えない以上、猫は 大規模開発では「識別子の定義や宣言には原則コメントをつける」というガイドラインを設けたほうが良い と考えます。

コメント不要論を輸入しても良いのか

実は上手にプログラムを書けば、かなりの部分でコメントは不要です。 それは事実ですし、そういうソースになるようにプログラマは努力すべきです。

でも、英語圏の方がそういうのと、日本人のプログラマがそういうのって 同次元で語ってはいけないんじゃないかしら、と猫は思います。 それは先ほど述べた「不自由な英語でピッタリ名前とつけること」 「ピッタリな名前をちゃんとそういう風に読み取れること」が難しいからなのですが、 こんな説明をしても納得されないのがプログラマだとも思います。

ですので、百聞は一見にしかず、とりあえず何も言わずにこのソースを見てください。

#定義
■人間とは
 ・名前
 ・趣味
 ・挨拶する〜「こんにちは」と言う。
 ・自己紹介する〜「{名前}です。趣味は{趣味}です。」と表示。

■音楽家とは +人間
 ・担当楽器
 ・挨拶する〜「どもども」と言う
 ・演奏する〜「ドミソー」をMML演奏。
 ・自己紹介する〜
   「{名前}です。担当は{担当楽器}です。」と表示。

#利用
トモコとは人間
トモコの名前は「友子」
トモコの趣味は「読書」
トモコが自己紹介する

アイコとは音楽家だ
アイコの名前は「aiko」
アイコが自己紹介する 

これは、日本語プログラム言語「なでしこ」の リファレンスのサンプルソースを引用したものです。 このソース、どこからどう見てもプログラムのようには見えないのですが、 「とは」というキーワードをつかい、「人間」クラスと「音楽家」クラスを定義している、 歴としたソースファイルです。

さて、センス・オブ・プログラミング!のコメント論に戻って、

 ・担当楽器            #担当する楽器

とコメントをつけることを無駄であると思えない人は、確かにどこか感覚が壊れています。(断言)

ひまわり系の言語は、日本語プログラム言語の中でも富に自然言語によく似ていますが、 英語を母国語とする方には、BasicやPythonといった言語のソースコードは、このように見えているハズですし、 CやJavaだって多かれ少なかれ、――そう、日本人が漢文をなんとなぁく拾えるかのように、 パッパッパッ、と脳に単語が飛び込んでくると思います。

つまり、英語圏の人がプログラム言語のソース言語を読む場合、 脳内にある「自然言語の認識エンジン」を活用できる、という大きな強みがあるのです。 そして、適切な名前付けは、「自然言語エンジン」の認識効率を上げる役割をするはずですし、 逆に「(自然言語とプログラム言語の)認識エンジンの切り分け」を行っていないわけですから、 コメントがソースに溶け込んでしまい、コメントが多いと読みづらく感じるでしょう。

おそらく母国語と似てもにつかないプログラム言語をつかう日本人プログラマと、 英語圏のプログラマでは、プログラムを読むときの脳の動きはまったく違います。

さて、その英語を母国語とする文化の方でも、 コメントが話題になるのは、識別子の名前を縮めるから、というのも大きいのではないでしょうか? これはたかが24文字しか文字を持たない為、名前を作ると ガンガン文字数が増えてしまう英語特有の問題です。 長い名前は「じゅげむじゅげむ・・・」ですし、「じゅげ公」では何がなんだかわからないですし、 で、英語プログラミングにおける伝統ある難しい問題なのです。

この問題に対し、例えば、カーニハンとパイクのプログラミング作法では

  • グローバルな変数名は省略しないで書く
  • ローカルな変数名は省略した方が良い

と提言しています。 ソースファイルは人間に読まれるモノですから、 書くとき大変、と言う理由で縮めるのは言語道断なのですが、 長い識別子を扱う式が読みにくいのもまた事実で、可読性の面からも 「名前」が難しいのが英語です。

はっきり言って名詞の創作能力において日本語はピカイチです。 日本語であれば、このような問題は生じません。 また、RPNな文法はスタックとの親和性が高く、 あくまで推測ながら構文解析を低コストで出来そうです。実はプログラム言語の土台として 日本語は向いて居るんじゃないかしら。

と、まぁ話が脱線しましたが、 プログラム言語は人間のために作られています。 ですので、自然言語をベースとすることが多いわけですが、 それがプログラマの常用自然言語の認識エンジンが働く言語出ない場合、 それを補う目的でもコメントを使うべきだ、と猫は考えているよ、というわけです

おまけ:

今回例としてつかった「なでしこ」のソースコードをメジャーな言語に置き換えてみます。

  • 実は元の なでしこソースにはバグがあるのですが、引用なのでそのまま放置してあります。 コチラの移植版では直してあります。
  • テキスト演奏については架空のモジュール(名前空間) "クジラ飛行机" 内のクラス "さくら" があるモノとしました。

まずは、これを日本語識別子のままC#に置き換えてみると、

using System;
using クジラ飛行机.さくら;               // 「クジラ飛行机.さくら」は誰かが作ってるとします。

public class 人間
{
    public string 名前;
    public string 趣味;

    public virtual void 挨拶する( void )
    {
        System.Consol.WriteLine( "こんにちは" );
    }

    public virtual void 自己紹介する( void )
    {
        System.Consol.WriteLine( "{0}です。趣味は{1}です" ,名前 , 趣味 );
    }
}

public class 音楽家 :人間
{
    public string 担当楽器
    public override  void 挨拶する( void )
    {
        Sytem.Consol.WriteLine( "どもども" );
    }

    public void 演奏する( void )
    {
        さくら.MML演奏( "ドミソー" );            // さくら.MML演奏()はどっかで誰かが作ってるとする(^^;
    }

    public override void 自己紹介する( void )
    {
        System.Consol.WriteLine( "{0}です。担当は{1}です" ,名前 ,担当楽器 );
    }
}

// 利用 〜C#では、必ずクラスを作らねばならない
//
publid class メイン
{

    // エントリポイント(最初に実行される所)は
    // C#では Main() と決まっています。
    //
    public static int Main (void )
    {
        人間    トモコ  = new 人間();
        トモコ.名前     = "友子";
        トモコ.趣味     = "読書";
        トコモ.自己紹介する();

        音楽家  アイコ  = new 音楽家();
        アイコ.名前     = "aiko";
        アイコ.担当楽器 = "オーボエ";
        アイコ.自己紹介する();
    }
}

うーん、イマイチ読みやすくはないですね。 では、次はPyhonで。

From クジラ飛行机 import さくら

class 人間:
    名前    =""                  # こんな書き方は、
    趣味    =""                  # ホントはしません(^^;

    def 挨拶する( self ):
         print "こんにちは"

    def 自己紹介する( self ):
         print "%sです。趣味は%sです。" %(self.名前 ,self.趣味)

class 音楽家 (人間):
    担当楽器    =""              # やっぱりこんな書き方はしません

    def 挨拶する( self ):
        print "どもども"

    def 演奏する( self ):
        さくら.MML演奏( "ドミソー" )

    def 自己紹介する( self ):
        print "%sです。担当楽器は%sです" %(self.名前, self.趣味)

# 利用
トモコ = 人間()
トモコ.名前 = "友子"
トモコ.趣味 = "読書"
トモコ.自己紹介する()

アイコ = 音楽家()
アイコ.名前     = "aiko"
アイコ.担当楽器 = "オーボエ"
アイコ.自己紹介する()

こちらはかなり「なでしこ」に近くなります。(と言うか、なでしこの方がPythonを真似ているのだけれど・・) でも、Pythonは日本語識別子は出来ませんので、こんなソースは書けないのですが・・・。

ちなみに、フツーの(英語チックな)プログラム言語では、 多くの日本人プログラマは、 コメント部分が浮かび上がってくる様な感覚を覚えるていると思いますが、 この日本語版Pythonでは、ベターッとした感じがしませんか?

たぶん、これが英語圏の人が言う「コメントがあると読みにくい」に繋がる感覚だと思うのです。

|++ month top ++|

SEO [PR] おまとめローン 冷え性対策 坂本龍馬 動画掲示板 レンタルサーバー SEO