K.Maebashi's BBS

ご自由に書き込んでください。雑談も可。
テスト書き込みの類はテスト用掲示板にどうぞ

[日付順表示] [日付順インデックス] [スレッド順インデックス]

新規投稿 | 開設者ホームページへ戻る | ヘルプ

[737] Re:プログラミングの入門用言語
投稿者:(ぱ)
2007/02/20 02:13:25

>えーと、以前の言及には気づいていませんでした。 ちょっと検索してみました。 # この掲示板には検索機能はないですが、今のところ # http://kmaebashi.com/bbs/list.php?boardid=kmaebashibbs&range=800 # とかやると過去の全発言が表示されるのでブラウザ内検索。 # もっと発言が増えてくると破綻しますが… そのうちガードをかけないと… 「一度や二度ではない」は言い過ぎだったようです。2回ですね。 このへんとか。 http://kmaebashi.com/bbs/list.php?boardid=kmaebashibbs&from=372&range=1 >私はゲームプログラミングにはうといのですが、Javaで「継承やオー >バーライドやインタフェースやスレッドを知らなければならない」 >というのは、 > > * やろうとしていることが実は複雑である > * Javaの提供するモデルとやろうとしていることが合ってない いくらなんでもボールがマウスを追いかけるくらいが複雑だとは思えないので、 Javaに関して言えば、「Javaの提供するモデルとやろうとしていることが合ってない」 のだと思います。もちろんこれは用途次第で、ダイアログを使うビジネスアプリケーション ならJavaのモデルでよいわけです。 ただ、Javaの場合、もともとWebページの飾り付け用の言語として世間に投入された はずで、にもかかわらずこのモデルはどうよ? とは思います。これは言語ではなく ライブラリの問題ですけど。 また、Javaの場合、たかがhello, worldでも、classとかpublic static void mainとか System.outとかの謎の言葉が出てきます。これはライブラリでなく言語の問題でしょう。 これを見ておっかなく思う初心者はいるかもしれません。が、実は「決まり文句」と 思っておけば済むことかもしれませんし、クラスがあってもhello, worldを1行で 書ける言語は可能です(Rubyのように)。 たとえばクラスが難しいものだとしても、初心者にクラスが見えないのなら、 初心者向け言語からクラスを外す理由にはなりません。その点で、[731] のyuyaさんの 指摘は的を射ていると思います。 ということで、私もおおむね説得されているわけですが、 a)初心者だからといって入門書を最初から順番にやっていくだけとは限らない。  雑誌に載っていたりネットに転がっているコードを読むこともあるだろう。 b)初心者だってライブラリは使うしマニュアルも読む。 ということは言ってよいと思います。Javaでhello, worldを書くとき、System.outは 決まり文句と思っていればよいかもしれませんが、これを決まり文句と思っている間は APIリファレンスが引けません。 また、C++だと入門書の最初のページでcoutとか使ってるかもしれませんが、 これをちゃんと理解するには演算子のオーバーロードを知らなきゃいけませんし、 ちょっとコレクションを使おうとするとSTLが出てきてtemplateを知らなくては いけなくなったりします。STLでなく(危険を承知で)Cの配列を使おうと決心したと しても、既存の、ゲームを作るのにすごく便利なライブラリが、引数にSTLの vectorを要求してたりして。 そういえば、話としてはずれますが、最初にCを勉強したときには (c = getchar()) != EOF がおっかなく見えたことを思い出しました。 >「削ることによってわかりやすくなる」という意見はよく聞きます >が、実際は「適切なモデル(or 機能)を提供することによってわか >りやすくなる」のであって、削ることだけが能じゃないと思います。 もちろん、なんでもかんでも削ればよいと思っているわけではないです。
[この投稿を含むスレッドを表示] [この投稿を削除]
[736] Re:プログラミングの入門用言語
投稿者:まつもと
2007/02/20 02:13:25

>書き込みありがとうございます。正直、ちょっとびっくりです。 ># ていうかここでMatzにっきにリンクしたのは一度や二度ではないのですが、 ># この話題で書き込みいただけるのはびっくりというか。 えーと、以前の言及には気づいていませんでした。 >> * サンプルで扱おうとしている概念そのものが難しい >> * サンプルの作者が難しく表現してしまった >> >>のいずれかで、それを言語のせいにするのはどうかと思います。 > >たとえば、私が[719]で書いた「マウスを追いかけるボールのプログラム」には、 >初心者がおっかなく思う機能はそんなにないと思います。「サンプルで扱おうと >している概念そのものが難しい」わけではないのではないでしょうか。 >でも、同じことをJavaでやろうと思ったら、継承やオーバーライドやインタフェースや >スレッドを知らなければならないわけです。以下のページは、そういう意図で >書きました。 私はゲームプログラミングにはうといのですが、Javaで「継承やオー バーライドやインタフェースやスレッドを知らなければならない」 というのは、 * やろうとしていることが実は複雑である * Javaの提供するモデルとやろうとしていることが合ってない のいずれかなのではないのですか。だとすると、検討すべきことは 初心者におっかない機能を取り除くことではなく、もう一歩踏み出 して、やろうとしていることを簡潔に記述できる高レベルなものを 提供することではないでしょうか。それが文法なのかライブラリな のかは知りませんが。 >という意見が出ていますが、「とりあえずオブジェクト指向は要らんな。」 >「構造体も要らん。」「変数は全部グローバル。」という意見には賛同しないものの、 >初心者にとっておっかない機能を除きつつ、それなりに実用に使える「落としどころ」 >は、どこかにあるんじゃないかと私は思っているわけです。 「削ることによってわかりやすくなる」という意見はよく聞きます が、実際は「適切なモデル(or 機能)を提供することによってわか りやすくなる」のであって、削ることだけが能じゃないと思います。
[この投稿を含むスレッドを表示] [この投稿を削除]
[735] Re:「投稿」ボタン
投稿者:(ぱ)
2007/02/20 02:13:25

>プレビュー画面で >「『投稿』ボタンをクリックすると、投稿されます。」 >と言いつつボタンが「送信」になってますね(^^;)  修正しました。ついでに、前から気になっていた、「ちゃんと改行を入れたかどうかチェックしてください」という文言を削除しました。  以前の仕様では、<pre>で囲んでいたので改行を入れないと困ったことになりましたが、今は<tt>で囲んでいるので、改行を入れる必要はなくなったためです。 # 引用しにくい気はしますが、画面幅が不明なとき、改行は入れない方がよいという # 面もあるので、今後はそのへんは投稿者にお任せしますです。
[この投稿を含むスレッドを表示] [この投稿を削除]
[734] Re:プログラミングの入門用言語
投稿者:(ぱ)
2007/02/20 02:13:25

>であって、前橋さんが問題としている >(2)「初心者向きでない機能を使わないと初心者向けのサンプルが書けないこと」 うむむ。確かにそうですね。Javaで、ちょっとしたゲームを作るのが大変なのは 「初心者向きでない機能を使わないと初心者向けのサンプルが書けないこと」の方に 相当します。 私自身、考えがまだまとまっていないのですが、 「初心者向きでない機能があると、それは相当な高確率でプログラムに  顔を出す。たとえその機能を使わずともプログラムが書けたとしても」 というのでなければ、初心者向きでない機能を言語から外す理由にはなりませんね。 問題はこの命題が真かどうかですが。初心者向きでない機能があるが、それを使わずとも 初心者が満足する程度のプログラムが書ける言語を仮定して、 a)初心者向けの本などのサンプルプログラムで、わざわざ初心者向きでない  機能を使っているとしたら、その本の著者がアホ。 b)初心者がベーシックマガジンの投稿プログラムを解読しようとするケースはどうか。  これだと、初心者向きでない機能が使われていることもありそう。 c)ライブラリとかで初心者向きでない機能が使われていて、それを知らないと  重要なライブラリが使えない、とか。 b), c)みたいなケースもあるかなあ、とも思いますが… 現状のJavaScriptプログラマの大半は、たとえばクロージャを知らなくても 幸せにやってるわけで、確かにいらん心配のようにも思います。
[この投稿を含むスレッドを表示] [この投稿を削除]
[733] Re:正規表現関連の関数の質問
投稿者:タイガー
2007/02/20 02:13:25

>私のお勧めサイトというと、ここの参考URLですかねえ。 >http://kmaebashi.com/programmer/devlang/array.html ありがとうございます。 1回は既に読んでいたのですが、頭に入っていなかったので 何回も読み直してみます。 >あと、紙ものの資料では、大昔の情報処理学会誌に「ごみ集めの基礎と最近の動向」 >というのがあって、とてもよかったのですが、現在では入手不能だと思います。 >私はというと会社で該当の情報処理学会誌が捨てられる直前に気が付いて、 >コピーしておいたのですが、その後数回の引越しで現在行方不明です…だめだめ。 もったいないですね。でも今回の記事に生かせているのでは ないでしょうか。 >>以下の本を購入しようと思ったのですが、(ぱ)さんは読んだことありますか? >> >>http://www.amazon.co.jp/exec/obidos/ASIN/0471941484/qid=1136566955/sr=1-1/ref=sr_1_10_1/250-0589622-2949018 > >すみません、読んでないです。 有名らしいのですが、読んでなかったのですね。 GCに関してあまり勉強せずにできているなんてすごいですね。 また、投稿します。ありがとうございました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[732] 「投稿」ボタン
投稿者:yuya
2007/02/20 02:13:25

ひさしぶりに投稿してみて初めて気づいたんですが、 プレビュー画面で 「『投稿』ボタンをクリックすると、投稿されます。」 と言いつつボタンが「送信」になってますね(^^;) つまらんこと言ってすみません。
[この投稿を含むスレッドを表示] [この投稿を削除]
[731] Re:プログラミングの入門用言語
投稿者:yuya
2007/02/20 02:13:25

こんにちは。 まつもとさんが「あまり問題にならない」と書いているのは (1)「言語が初心者向きでない機能を持つこと」 であって、前橋さんが問題としている (2)「初心者向きでない機能を使わないと初心者向けのサンプルが書けないこと」 とは別なのではないでしょうか? 私自身は(1)はまつもとさんと同様に「問題にならない」と思いますし、 (2)は前橋さんと同様に「そりゃ問題である」と思います。
[この投稿を含むスレッドを表示] [この投稿を削除]
[729] Re:プログラミングの入門用言語
投稿者:(ぱ)
2007/02/20 02:13:25

書き込みありがとうございます。正直、ちょっとびっくりです。 # ていうかここでMatzにっきにリンクしたのは一度や二度ではないのですが、 # この話題で書き込みいただけるのはびっくりというか。 >>これにはいまいち賛同しかねるんですよねえ。サンプルで見かけるプログラムで >>「初心者向きでない機能」が使われていると、おっかなく思う初心者は大勢いそうです。 おっかなく思う初心者がいるから言語からその機能を抜くとすれば、以下の問題が 発生すると思います。 a)おっかなく思うような難しい概念を抜きにして、ゲームとかを作りたいと思う  初心者が達成したい要件を実現できるかどうか。 b)おっかなく思うような難しい概念を抜きにして、上級者の要件を満たせるかどうか。 おっかない機能を抜いても、a), b)の両方を満たしているのであれば、文句なしだと 思います。そりゃ本当の上級者は別の言語を使ったほうが「よりよい」かもしれませんが、 そういう「よりよい」言語との間に十分な「のりしろ」があるなら、初心者も シームレスに移行できるのではないでしょうか。 >>こちらにある、「「初心者(だけ)のための言語」ってのは駄目だと思っている」 >>という意見にも賛成します。 これ↑に矛盾すると思われるかもしれませんけど、要は程度問題で、いずれツールの 移行を余儀なくされるとしても、その時の抵抗が少ないのであれば、許容されるのでは ないでしょうか。HSPやN88BASICはこのへんが… # と言いつつ、HSPやN88BASICで苦労した経験は、その後他の言語のありがたみを # 理解するのに有用かもしれない、とも思ったりもします。この苦労を知らずに # 大人になると、「グローバル変数が便利だったから、あちこちで使った。」に # なりかねないわけで。 > * サンプルで扱おうとしている概念そのものが難しい > * サンプルの作者が難しく表現してしまった > >のいずれかで、それを言語のせいにするのはどうかと思います。 たとえば、私が[719]で書いた「マウスを追いかけるボールのプログラム」には、 初心者がおっかなく思う機能はそんなにないと思います。「サンプルで扱おうと している概念そのものが難しい」わけではないのではないでしょうか。 でも、同じことをJavaでやろうと思ったら、継承やオーバーライドやインタフェースや スレッドを知らなければならないわけです。以下のページは、そういう意図で 書きました。 http://kmaebashi.com/zakki/zakki0027.html#lang イベントリスナを実現するために内部クラスや匿名クラスを使うのは 「サンプルの作者が難しく表現してしまった」のかもしれませんが、それ以外の点に ついては、Javaでは避けようがないでしょう。 >それに初心者がおっかなく思う危険のある機能を取り除いた言語っ >てのは、結局実務に役立たずで学ぶ価値のない言語になりそうです。 まつもとさんも、Cが「実務に役立たずで学ぶ価値のない言語」とは思いませんよね? 現状でCが難しいのは、実行時のチェックがないためとんでもないバグが出ることと、 宣言の構文やポインタと配列の妙な交換性にあると私は思っています。 前者は多少効率を犠牲にすれば回避できる話ですし、後者は単なる言語のバグです。 こういう点を改良したCもどきは作れると私は思っていて、crowbarは、ある意味 その実装のひとつのつもりです(型無しだったり、プロトタイプベースだったり、 クロージャがあったりするのはアレですが)。 こちらにも、 http://www.rubyist.net/~matz/20040925.html#c05 | 文字列型が違和感なく扱えて、便利そうな関数がもっと多くて(?)、引数が常に値渡しであるC言語最強、と思う。 という意見が出ていますが、「とりあえずオブジェクト指向は要らんな。」 「構造体も要らん。」「変数は全部グローバル。」という意見には賛同しないものの、 初心者にとっておっかない機能を除きつつ、それなりに実用に使える「落としどころ」 は、どこかにあるんじゃないかと私は思っているわけです。
[この投稿を含むスレッドを表示] [この投稿を削除]
[728] Re:プログラミングの入門用言語
投稿者:まつもと
2007/02/20 02:13:25

>ただ、 >| 初心者と言えども言語の全ての機能を一度にマスターする必要はない。 >| よって言語が初心者向きでない機能を持つことは、あまり問題にならない。 > >これにはいまいち賛同しかねるんですよねえ。サンプルで見かけるプログラムで >「初心者向きでない機能」が使われていると、おっかなく思う初心者は大勢いそうです。 「おっかなく思う」かもしれませんが、その原因は * サンプルで扱おうとしている概念そのものが難しい * サンプルの作者が難しく表現してしまった のいずれかで、それを言語のせいにするのはどうかと思います。 それに初心者がおっかなく思う危険のある機能を取り除いた言語っ てのは、結局実務に役立たずで学ぶ価値のない言語になりそうです。
[この投稿を含むスレッドを表示] [この投稿を削除]
[727] Re:オブジェクト指向「初」入門
投稿者:CES
2007/02/20 02:13:25

この人たちは、どんなソフトウェアかによらず適用できる、万能の分析手法でも求めているんだろうか… そんなものがありゃ誰も苦労しねぇっつうの。
[この投稿を含むスレッドを表示] [この投稿を削除]
[726] Re:オブジェクト指向「初」入門
投稿者:CES
2007/02/20 02:13:25

>CESさんいわく > >>「is-a である関係が、LSP を満たすように作れ」と言っているのです。 > >それじゃあ「CESさん言うところのis-a」がLSPを満たすのは当たり前ですわな。 >そう定義したんだから。 「LSP を満たす関係が is-a である」とは言っていませんよ(そう言っているのは kit さんです)。 結果的にはそうなりますが、それは is-a の定義ではありません。 じゃあ is-a の定義は何なんだって話になりますが、言い換える言葉が見つかりませんね。is-a は is-a です。「A is-a B」は「AはBの一種」です。これがもっともシンプルかつ的確ではないですか。 以前に、ソフトウェアは「分析→設計→実装」の3段階で作られると言う話をしました。 俺の言う「is-a」の関係を決めるのは分析段階、LSP を満たすように作るのは設計段階の話です。 それで設計段階になって、LSP がどうしても満たせなくなったらどうするか? LSP を捻じ曲げて is-a を固持しろなんていってません。分析からやり直すのです。 ちょっと古い投稿を引用すが… [658] > 設計を見直す=分析のしなおし、だよん。って。 その通りではないですか。 あるプロジェクトに直面した時、「AはBの一種である」とも「AはBの一種ではない」とも、どちらの考え方もできます。 どちらが適切なのかを選ぶのが「分析」というプロセスですよ。 >我々は、設計段階で、どういう継承関係にすればうまくいくかを知りたい >ため、設計原則を求めているわけです。 そこで機械的に従えばいいガイドラインを求めるのは、分析プロセスの放棄ですよ。 >>1:オブジェクトが is-a であると仮定した。 >>2:LSP に照らし合わせたらうまく行かなかった。 >>  (照らし合わせるまでも無く判断できる場合もある) >>3:実はオブジェクトは is-a じゃなかったんだ。だから継承関係にはしない。 > >こちらも同様です。is-aの定義が「うまくいくかどうか」で決定されるんなら、 >「うまくいくようにやりなさい」と言ってるだけのことで、結局何も言って >いないのです。 そうですよ。 「どうすればうまく行くのか」は、その場合に応じて変わるのですから、それ以外に言いようが無いではありませんか。 こんな記事見つけました(Wikipedia - 「継承」) http://ja.wikipedia.org/wiki/%E7%B6%99%E6%89%BF > 一般的に、AがBを継承する場合、A is a B. (AはBの一種である)という > 意味的な関係(is-a関係)が成り立つ。従って、同じふるまいを持つから > と言って、意味的に無関係なクラス間に継承関係を持たせるのは適切でない > 場合が多い。 だそうですよ。
[この投稿を含むスレッドを表示] [この投稿を削除]
[725] Re:オブジェクト指向「初」入門
投稿者:(ぱ)
2007/02/20 02:13:25

あんまりkitさんに押し付けておくのも申し訳ないのでちょっとだけ書きますが。 >>ところが、CES さんは、「継承してうまく動くような関係が is-a である。 >>したがって、継承してうまく動くような関係に対して、継承を当てはめれ >>ば良い」と言ってるに過ぎないわけです。これは見て分かるようにトート >>ロジーに過ぎず、設計の指針としては、全く役に立たないわけです。 このkitさんの言葉がすべてだと思いますがね。 >違います。 >「どういう関係が is-a であるか」については言及していません。 だから、それが問題なんだってば。既に指摘されているじゃないですか。 [715] >なぜなら、CES さんは、is-a という関係が具体的にどうあるべきかを一切述べ >ていないからです。 CESさんいわく >「is-a である関係が、LSP を満たすように作れ」と言っているのです。 それじゃあ「CESさん言うところのis-a」がLSPを満たすのは当たり前ですわな。 そう定義したんだから。 >1:オブジェクトが is-a であると仮定した。 >2:LSP に照らし合わせたらうまく行かなかった。 >  (照らし合わせるまでも無く判断できる場合もある) >3:実はオブジェクトは is-a じゃなかったんだ。だから継承関係にはしない。 こちらも同様です。is-aの定義が「うまくいくかどうか」で決定されるんなら、 「うまくいくようにやりなさい」と言ってるだけのことで、結局何も言って いないのです。
[この投稿を含むスレッドを表示] [この投稿を削除]
[724] Re:オブジェクト指向「初」入門
投稿者:CES
2007/02/20 02:13:25

あといくつか、最初の方の書き込みに対するレス。 俺が「オブジェクトの is-a は LSP よりも優先されるべきだ」と言ったのは、「まずオブジェクトの is-a で判断し、次に LSP で判断すべきだ」という意味です。 その結果、最初に「is-a」とした判断が誤っていたというケースがあるのは既に言っています。 そのような場合でも、LSP を捻じ曲げて、断固、最初の「is-a」に固執すべきだと言った覚えはありません。 そして、まず「(常識的なオブジェクトの)is-a で判断する」のは、kit さんも同じであると [715] で書かれています。しかし、そう書かれたのはここが初めてです。 俺はてっきり「オブジェクトの is-a は問題にしなくていい。LSP だけで継承関係を判断すればいい」のだと思っていたのですが。 [713] では > なぜ、オブジェクト自身の is-a 関係が継承関係の設計に使えない > 場合があるのか、そのことを説明しているのが LSP です (ただし、 > 正方形や円のケースでは、LSP 以外にも、メモリ効率という別の理 > 由もあります)。継承関係の設計において、オブジェクト自身の > is-a 関係は使えない場合がある弱い判断基準なわけですが、LSP > は常に使える絶対的な判断基準なわけです。実はLSP(オブジェクト > の振舞いに関する is-a) の方が、オブジェクト自身のis-aよりも > むしろ本質的な原則なわけです。 と書かれています。 > オブジェクト自身の is-a 関係が継承関係の設計に使えない場合がある のは事実です。 しかし、そういう「場合がある」のであって、「常に使えない」とは書かれていません。 事実、[715] では > たとえば、「常識的に考えた is-a 関係に対して、継承を当てはめれば良 > い」というのは、正方形と長方形の例のようにうまくいかない例外もあり > ますが、かなり使える原則です。 と書かれています。「is-a の関係は使えないわけではない」のですね。 にも関わらず、[713] では「is-a は役に立たない。LSP こそ基準にすべきだ」と書かれているように見受けられます。 そう読んでしまうのは、俺の読解力不足ですか? [715] を境に、そちらの主張が切り替わっているような気がするのですが。
[この投稿を含むスレッドを表示] [この投稿を削除]
[723] Re:オブジェクト指向「初」入門
投稿者:CES
2007/02/20 02:13:25

要点抽出。 >議論が空転している気がするんです。整理しましょう。 >まず(常識的かどうかは置いておくとして)「オブジェクトの is-a」で大まかな関係を作るというのは、どちらも同じことを言ってますね。 >kit さんは、その上で「LSP に照らして破綻したら、継承関係にはしない」と言う。 >俺は「LSP に照らすまでも無く、継承関係にしてはいけない場合がある」と言う。 >結局、どの段階で、最初の「is-a」が間違えていたかを判断するのかが違うだけで、大差ないでしょう。 >問題は「LSP に照らさないと、間違いかどうか判断できないケースはあるのか」だと思うんですよ。 >そのへんどうです? 1:オブジェクトが is-a であると仮定した。 2:LSP に照らし合わせたらうまくいった。 3:継承関係を結んだ。 これに異論を差し挟む余地は無いでしょう。 問題は、そうでないケースですね。 kit さんの場合 1:オブジェクトが is-a であると仮定した。 2:LSP に照らし合わせたらうまく行かなかった。 3:オブジェクトは is-a なんだけど継承関係にはしない。 俺の場合 1:オブジェクトが is-a であると仮定した。 2:LSP に照らし合わせたらうまく行かなかった。   (照らし合わせるまでも無く判断できる場合もある) 3:実はオブジェクトは is-a じゃなかったんだ。だから継承関係にはしない。 結局、違うのは、過程3の前半だけなんですよね。 だから、[712] ではこう書いているんです。 > is-a と LSP をどうしても両立させられない例を一つでも出していただけませんか。 俺の方法ではうまく行かないケース、つまり 「どこからどう見ても疑念を挟む余地無く is-a なんだけど、LSP に照らし合わせたらうまく行かないから、LSP を優先するケース」 があるのか、ということなんです。俺が度々言う「is-a と LSP が矛盾するケース」ってのはこういうことなんです。 「常識的な is-a と LSP が矛盾するケース」ではないですよ。「どこからどう見ても」ってのは、「あらゆる非常識な関係も考慮に入れて」ってことです。 こういう場合があると言えますか? 俺は「あらゆる角度から見る」ことが不可能であるため、そのようなケースは存在しないと思うのですが。
[この投稿を含むスレッドを表示] [この投稿を削除]
[722] Re:オブジェクト指向「初」入門
投稿者:CES
2007/02/20 02:13:25

>「is-a の意味は常識的なものとは限らない。場合によって、適切なもの >を選べ」というのは、実のところ、まったく意味のない言明です。なぜな >ら、CES さんは、is-a という関係が具体的にどうあるべきかを一切述べ >ていないからです。 どう言えばいいですかねぇ。 「クラスはオブジェクトの集合である」と考えた時、「ある集合Aと、その部分集合Bがあったら、B is-a Aである」でいいですか? もっとも、「どのような基準に従ってオブジェクトを集合に分類するか」には、結局、唯一解がないのは同じことなんですが。 >我々は、設計段階で、どういう継承関係にすればうまくいくかを知りたい >ため、設計原則を求めているわけです。 そんな話は今初めて聞きましたがねぇ… >たとえば、「常識的に考えた is-a 関係に対して、継承を当てはめれば良 >い」というのは、正方形と長方形の例のようにうまくいかない例外もあり >ますが、かなり使える原則です。 それでいいと思いますよ。 我々の社会常識が「大多数にとって都合がいい見方」であるように「多くの場合に都合がいいケース」はあってもおかしくありません。 ただし、それがたまたま成り立たないからといって、それだけを槍玉に挙げないでいただきたい。 ちなみに、件の文献の、長方形と正方形の関係の誤りは、LSP を持ち出すまでも無く「間違いだ」と判断できるものです(まぁ、LSP を考えてみて判断しても構わないのですが。別にそれでも is-a と LSP の矛盾は指摘できませんから)。 オブジェクトの is-a よりも LSP を優先すべきだという根拠にはなりません。 >また、「LSPに従うオブジェクト同士に対して、継承を当てはめれば良い」 >というのは、常に利用可能な原則です。 >ところが、CES さんは、「継承してうまく動くような関係が is-a である。 >したがって、継承してうまく動くような関係に対して、継承を当てはめれ >ば良い」と言ってるに過ぎないわけです。これは見て分かるようにトート >ロジーに過ぎず、設計の指針としては、全く役に立たないわけです。 違います。 「どういう関係が is-a であるか」については言及していません。 「is-a である関係が、LSP を満たすように作れ」と言っているのです。 件の文献も言っているではありませんか。 > あるところで、何か、置き換えが必要なところがあるとする。 > 型Sのオブジェクトo1 と、型Tのオブジェクトo2があって、 > プログラムが既に型Tのオブジェクトを使うように構築されているとする。 > o1がo2で置き換えられても、SがTのサブタイプであるならば、 > Pは同じ振る舞いをするべきである。 「サブタイプならば同じ振る舞いをすべきである」と書かれています。 「同じ振る舞いをするならサブタイプである」とは書かれていません。 結局、この文献は「どんなものを継承関係にすべきか」という指針には、一言も言及していないのです(「どんなものを継承関係にしてはいけないか」は、LSP を用いて言及しています。しかし、それは LSP を用いなくても指摘可能であることは度々述べています)。 >> 全く同じ属性と振る舞いを持つクラスは、同じクラスだと考えるべきです。 >> これは、「LSP が成り立つならば is-a も成り立つ」と言い換えることもできます。 > >一つ目の文章は正しいと思います。 >しかし、一つ目の文章から二つ目の文章を導くことはできません。 突っ込まれるかなーと思っていました。 ちょっと拡大しましょう。 全く同じ属性と振る舞いを持つクラスは、同じクラスだと考えるべきです。 そして、あるクラスと互換性のある属性と振る舞いを持つクラスは、そのクラスと何らかの関係があるクラスと見るべきです。 逆転させて言えば「関係の無いクラスに、互換性のある属性と振る舞いを持たせるべきではありません=継承関係にすべきではありません=LSP が成立してはいけません」となるのではないでしょうか。 >なお、Martin 氏の文章を読み返してみて、私がこれまで説明で使って >用語法が、Martin 氏の用語法と異なっているのに気づきました。 >私がこれまで >1. オブジェクトの振舞いに関する is-a >2. オブジェクト自身に関する is-a >という二つの言葉で区別してきたことを、Martin 氏は >1. 振舞いの is-a == オブジェクト(CamelCase にした名詞)の is-a >2. 物(子文字で始まる名詞)の is-a >と呼んでいますね。 >まあ、独立に読んでいれば意味は通じると思いますが、併せて読むと >混乱するのであまり良くありませんね。どうも申し訳ない。 小文字の is-a ってどこで使ってますか? ひょっとして原文? 提示された日本語版には見当たらないのですが… >設計手順としては、まず常識的な is-a を使って継承関係を考えてみた >上で、それを LSP で検証すればいいんですよ。検証に通らない場合には、 >たとえ常識的なis-a 関係であっても、継承関係にはしません。検証に通 >れば、もちろん継承関係にします。 >簡単でしょう? >本来無関係のオブジェクト同士うんぬんなどと悩む必要はありません。 議論が空転している気がするんです。整理しましょう。 まず(常識的かどうかは置いておくとして)「オブジェクトの is-a」で大まかな関係を作るというのは、どちらも同じことを言ってますね。 kit さんは、その上で「LSP に照らして破綻したら、継承関係にはしない」と言う。 俺は「LSP に照らすまでも無く、継承関係にしてはいけない場合がある」と言う。 結局、どの段階で、最初の「is-a」が間違えていたかを判断するのかが違うだけで、大差ないでしょう。 問題は「LSP に照らさないと、間違いかどうか判断できないケースはあるのか」だと思うんですよ。 そのへんどうです? >なお、もし本来無関係だと思っていたオブジェクト同士にLSPが成り立つ >のであれば、実はそのオブジェクト同士は、たぶん無関係じゃないんですよ。 本当に無関係でないのなら構いませんが、「たぶん」というのはいただけません。 実のところ、「本当に無関係か」を判断することはできません。どうにかして関係を見出すことはできます。 しかし、その関係は、設計者の意図した関係で無い可能性が大きいでしょう。 そのような関係に、LSP を成り立たせることは、メリットがあるとは思えません。 >しかし、通常のソフトウェア開発で、そういう発見を必要とすることは >あまりありませんから、無関係だと思うオブジェクト同士について、 >いちいちLSPを検証してみる必要はありません。 LSP は「たまたま成り立っちゃう」ものではなくて「意図して成り立たせる」ものであると考えます。 であるならば、先のようなデメリットを考えた時に「意図して崩す」ことも、当然ありえる話です。 それをせず、「たまたま成り立っちゃう」のを放置しておくのは、バグの温床になりませんか。
[この投稿を含むスレッドを表示] [この投稿を削除]
[721] Re:プログラミングの入門用言語
投稿者:(ぱ)
2007/02/20 02:13:25

>processingのmouseXの代わりに、get_mouse_x()という関数を用意しました。 get_mouse_x()も、ウインドウ内の座標を返すのですから、ウインドウごとにしないと まずいですね。このへん考えるべきことはいろいろありそうですが、まあ方向性として。 ついでに補足しますけど、私は、HSPに関しては「もう21世紀なのにこの言語はないだろう」 というまつもとゆきひろさんの意見に賛成します。 http://www.rubyist.net/~matz/20040827.html#p01 こちらにある、「「初心者(だけ)のための言語」ってのは駄目だと思っている」 という意見にも賛成します。 http://www.rubyist.net/~matz/20040925.html#p02 ただ、 | 初心者と言えども言語の全ての機能を一度にマスターする必要はない。 | よって言語が初心者向きでない機能を持つことは、あまり問題にならない。 これにはいまいち賛同しかねるんですよねえ。サンプルで見かけるプログラムで 「初心者向きでない機能」が使われていると、おっかなく思う初心者は大勢いそうです。 crowbarはどうでしょうか。クロージャは、[717]を見るとわかるように、言語の作者の 私でさえ使いこなせていない。とほほほほ。 しかし、それはそれとして、オブジェクトの概念自体は必要だと思うし、初心者に わからないものでもないと思います。 w = open_window(800, 500); と書いてウインドウが開くのなら、そしてopen_window()を実行するたびに 何個でもウインドウが開けるのなら、そのウインドウに丸を描くのに w.fill_circle(x, y, 10); と書かなければならないのは、いくら相手が初心者でも、自明じゃないのかなあ。 別にfill_circle(w, x, y, 10); でもいいけど。 んで、シューティングゲームを作るのに敵をたくさん出したければ、自分でクラスっぽい ものを作らざるを得ないし、そのmove()メソッドをオーバーライドすることで、 ポリモルフィズムも自然に利用できるんじゃないかと思うんですけど、どうでしょうか。
[この投稿を含むスレッドを表示] [この投稿を削除]
[720] Re:プログラミングの入門用言語
投稿者:(ぱ)
2007/02/20 02:13:25

> if (get_mouse_x() < x) { > x++; あ、条件式逆だった…
[この投稿を含むスレッドを表示] [この投稿を削除]
[719] Re:プログラミングの入門用言語
投稿者:(ぱ)
2007/02/20 02:13:25

>てなことを書かれておられましたが、Processing(http://processing.org/)はどう >でしょうか? 情報ありがとうございます。ちょっと見てみました。 ExamplesのStructureを一通り見ただけですが、 ・やっぱりイベントドリブンなのか。(mouseXという謎の変数が出てきてますが) ・ウインドウをふたつ開くことはできるのか? あたりが感想(と疑問)です。イベントドリブンは、処理が分断されるので、 ゲームとかを作りたい人にはわかりにくいのではないか、と私は思っています。 >これは、言語はJavaそのものですが、IDEによって、クラス定義などの >初心者にとって面倒そうな部分をうまく隠蔽してあって、単なる手続き型言語のように >使えます。これなら初心者にとっても比較的とっつきやすいんじゃないかと思います。 うーん。とっつきやすいかとは思いますが、結構用途が限定された言語にも見えます。 draw()は言語仕様に組み込まれているんでしょうか? たとえば現在私が作っているcrowbarをベースに、ライブラリ関数を追加して、 以下のようなプログラムは作れるようになるのではないでしょうか。 processingのmouseXの代わりに、get_mouse_x()という関数を用意しました。 # マウスを追いかけるボールのプログラム。 w = open_window(800, 500); # 引数はウインドウのサイズ x = 0; y = 0; prev_x = x; prev_y = y; for (;;) { # 直前のボールの消去 w.set_color(BLACK); w.fill_circle(prev_x, prev_y, 10); # 中心のx, y, 半径 if (get_mouse_x() < x) { x++; } elsif (get_mouse_x() > x) { x--; } elsif (get_mouse_y() < y) { y++; } elsif (get_mouse_y() > y) { y--; } w.set_color(WHITE); w.fill_circle(x, y, 10); prev_x = x; prev_y = y; wait(100); # 100msec待ちつつイベントを拾う。最後のイベントで上書き。 } 私が件の雑記で書きたかったのは、「ベーシックマガジン向けプログラミング言語」が あったらいいなあ、ということなんですけど、これぐらい書けたら、汎用性を保ちつつ、 それなりに達成してないでしょうかね? もちろん、fill_circle()だけでなく、 イメージを指定された場所に表示する関数とかも必要ですけれど。 wait()あたりの一等地の名前を使うことについては、名前空間で対処するとして。 でも、processingは、Javaアプレットとして実行できるのはいいと思います。 ゲーム作ったらやっぱり友達に自慢したいと思うので。
[この投稿を含むスレッドを表示] [この投稿を削除]
[718] Re:正規表現関連の関数の質問
投稿者:(ぱ)
2007/02/20 02:13:25

>ご教授ありがとうございます。 >GCに少し興味を持ったのですが、お勧めのサイトなどありますか? 私のお勧めサイトというと、ここの参考URLですかねえ。 http://kmaebashi.com/programmer/devlang/array.html あと、紙ものの資料では、大昔の情報処理学会誌に「ごみ集めの基礎と最近の動向」 というのがあって、とてもよかったのですが、現在では入手不能だと思います。 私はというと会社で該当の情報処理学会誌が捨てられる直前に気が付いて、 コピーしておいたのですが、その後数回の引越しで現在行方不明です…だめだめ。 >以下の本を購入しようと思ったのですが、(ぱ)さんは読んだことありますか? > >http://www.amazon.co.jp/exec/obidos/ASIN/0471941484/qid=1136566955/sr=1-1/ref=sr_1_10_1/250-0589622-2949018 すみません、読んでないです。
[この投稿を含むスレッドを表示] [この投稿を削除]
[717] Re:イテレータ(とCPS)
投稿者:(ぱ)
2007/02/20 02:13:25

土曜はとあるイベントにて大阪で飲んだくれておりまして、ずいぶん返事が遅くなりまして すみません。 それプラス、私自身、クロージャに慣れておらず継続もわかっておらず、今回のNykRさんの サンプルはずいぶん荷が重いものでした。とはいえ放り出していては勉強にならんので、 私なりに解釈してみました。間違い等ありましたらご指摘ください。 さて、単に木をイテレートするだけなら、 tree.each(closure(item) { # このitemについてなんかする }); という形のeachメソッドをツリーに装備するのは簡単で、ツリーの中で再帰して、 要素ごとに、渡されたクロージャを呼び出せばよいのですが、こういう形式(内部イテレータ) だと、あるツリーについて、「ここまで走査した」という状態を保存しておけないのが 問題になるわけですよね。その点、NykRさんの提示されたイテレータでは、こういう 書き方も許される。 # ふたつのイテレータでツリーを並列に走査する。 for (ite1 = iterator_GoF(foreachTree_CPS(tr)), ite2 = iterator_GoF(foreachTree_CPS(tr)); !ite1.isDone() && !ite2.isDone(); ite1.next(), ite2.next()) { print(" " + ite1.currentItem()); print(" " + ite2.currentItem()); } これができるのが外部イテレータの強みです。 Cなどで、再帰を使ってツリーを辿る場合、「ここまで走査した」という情報がスタック上に ありますから、スタックが1本しかない以上、ふたつのイテレータを並行して使うことは できないわけです(片方が片方の繰り返しに完全に含まれるなら可能)。 tr = {13,{5,{3,{},{}},{13,{12,{},{}},{}}},{16,{16,{15,{},{}},{}},{17,{},{}}}}; この例では、nodeの[0]にそのノードの値が、[1]に左の子が、[2]に右の子が 入っていますから、再帰で間順で走査するなら以下のようになります。 function internalIterate(node) { if (node.size() == 0) { } else { internalIterate(node[1]); # ...(a) print(" " + node[0]); # とりあえず表示しておく internalIterate(node[2]); } } (a)の箇所で左の子について再帰呼び出しを行い、それが戻ってきてから続きの処理を やっています。「戻ってきてから続きの処理をやる」ことができるのが再帰の嬉しい ところですが、それを期待していては、外部イテレータは作れない。 そこで、「戻ってきてから続きの処理をする」のではなく、「戻ってきてから やってほしい続きの処理をクロージャとして渡す」とすれば、関数から戻ってこなくても よくなる。その変換をしたのがこれ。 function internalIterate(node, cont) { if (node.size() == 0) { cont(); } else { internalIterate(node[1], closure () { # 続きをクロージャで渡す。 print(" " + node[0]); internalIterate(node[2], cont); }); } } # 第2引数には「処理の続きを渡す」のだから、最後に「おしまい」と表示される。 internalIterate(tr, closure() {print("おしまい");}); さて、この状態では、要素ごとに行う処理がprint()に固定されていますから 汎用性がありません。では引数でなにか関数を渡せば、とこうしても、 internalIterate(node[1], closure () { # 続きをクロージャで渡す。 proc(node[0]); # 処理を引数procで渡す internalIterate(node[2], cont); }); これでは内部イテレータと同じですから意味がありません。 そこで、このproc()にも、続きの処理をクロージャで渡してやることにします。 function foreachTree_CPS(proc) { return closure internalIterate(node, cont) { if (node.size() == 0) { cont(); } else { internalIterate(node[1], closure () { proc(node[0], closure() { internalIterate(node[2], cont); }); }); } }; } 外部イテレータの場合、このprocの第2引数をnext()の際に呼び出せばよいわけですね。 なぜならそれが「処理の続き」だから。 イテレータはこうなります。 function iterator_GoF(foreach_CPS, collection) { this = new_object(); this.first = closure () { this.isDone = closure () { return false; }; foreach_CPS(closure (item, cont) { this.currentItem = closure () { return item; }; this.next = closure () { cont(); }; })(collection, closure(){ # ..(b) this.isDone = closure () { return true; }; }); }; this.first(); return this; } イテレータのfirst()が呼び出されたときに、foreach_CPS()を呼び出して、 internalIetrate()を取得し、それに対しcollectionとクロージャを渡しています(b)。 これがつまり元のソースの internalIterate(tr, closure() {print("おしまい");}); に相当するわけですが、「おしまい」と表示する代わりに、isDoneについて、 trueを返すよう関数を差し替えています。 んで、internalIterate()に渡しているproc()では、 this.currentItem = closure () { return item; }; this.next = closure () { cont(); }; currentItemを設定後、nextに対し、contすなわち「処理の続き」をセットしています。 これで、次に利用者がnext()を呼び出したとき、internalIteratorの続きが実行される、と。 NykRさんのソースとは微妙に変わっていますが、こんな解釈でよいでしょうか? # いやあ、実に勉強になりました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[716] プログラミングの入門用言語
投稿者:みずしま
2007/02/20 02:13:25

こんにちは。 大分前の雑記「プログラミングの入門用言語(2003/5/1)」の最後の方で、 > C, Javaライクな文法で、こういう方向性の言語って、現在あるんでしょうか。 てなことを書かれておられましたが、Processing(http://processing.org/)はどう でしょうか?これは、言語はJavaそのものですが、IDEによって、クラス定義などの 初心者にとって面倒そうな部分をうまく隠蔽してあって、単なる手続き型言語のように 使えます。これなら初心者にとっても比較的とっつきやすいんじゃないかと思います。
[この投稿を含むスレッドを表示] [この投稿を削除]
[715] Re:オブジェクト指向「初」入門
投稿者:kit1
2007/02/20 02:13:25

> 唯一の正解は無いでしょう。場合によって、適切なものを選べば、それ > が正解です。 これが CES さんのやり方の問題なんです。 「is-a の意味は常識的なものとは限らない。場合によって、適切なもの を選べ」というのは、実のところ、まったく意味のない言明です。なぜな ら、CES さんは、is-a という関係が具体的にどうあるべきかを一切述べ ていないからです。 我々は、設計段階で、どういう継承関係にすればうまくいくかを知りたい ため、設計原則を求めているわけです。 たとえば、「常識的に考えた is-a 関係に対して、継承を当てはめれば良 い」というのは、正方形と長方形の例のようにうまくいかない例外もあり ますが、かなり使える原則です。 また、「LSPに従うオブジェクト同士に対して、継承を当てはめれば良い」 というのは、常に利用可能な原則です。 ところが、CES さんは、「継承してうまく動くような関係が is-a である。 したがって、継承してうまく動くような関係に対して、継承を当てはめれ ば良い」と言ってるに過ぎないわけです。これは見て分かるようにトート ロジーに過ぎず、設計の指針としては、全く役に立たないわけです。 結局、CES さんの主張は、LSP どころか、(常にうまくとは限らない)常識的 な is-a 関係による継承関係の設計よりも、さらに劣るものにしか見えません。 また、CES さんは下記のように書いていますが、これはそもそも意味不明です。 > 全く同じ属性と振る舞いを持つクラスは、同じクラスだと考えるべきです。 > これは、「LSP が成り立つならば is-a も成り立つ」と言い換えることもできます。 この二つの文章のうち、一つ目の文章は、クラスとクラスの等価関係に 関する文章です。 二つ目の文章は、クラスとクラスの包含関係に関する文章です。 等価関係に関する文章と、包含関係に関する文章が、同一の意味である という発想は、まったくもって非論理的だと私は思います。 なぜ、この二つの文章が等価だと発想されたのか、残念ながら、私には 理解できません。 一つ目の文章は正しいと思います。 しかし、一つ目の文章から二つ目の文章を導くことはできません。 なお、Martin 氏の文章を読み返してみて、私がこれまで説明で使って 用語法が、Martin 氏の用語法と異なっているのに気づきました。 私がこれまで 1. オブジェクトの振舞いに関する is-a 2. オブジェクト自身に関する is-a という二つの言葉で区別してきたことを、Martin 氏は 1. 振舞いの is-a == オブジェクト(CamelCase にした名詞)の is-a 2. 物(子文字で始まる名詞)の is-a と呼んでいますね。 まあ、独立に読んでいれば意味は通じると思いますが、併せて読むと 混乱するのであまり良くありませんね。どうも申し訳ない。 > オブジェクト指向の第一目的は「わかりやすくすること」であると(今 > は)思っています > 本来、無関係のオブジェクト同士を継承関係にするのがわかりやすいで > すか? 私が欲しいのは良い設計指針であって、オブジェクト指向の第一目的は 何かという問いの答は実はどうでもいいんですが(なぜなら、人によって 答がそれぞれ違うので、そんなことの統一見解を決めても実益がないから です)、それは置いておいて、かなり誤解されていると思います。 設計手順としては、まず常識的な is-a を使って継承関係を考えてみた 上で、それを LSP で検証すればいいんですよ。検証に通らない場合には、 たとえ常識的なis-a 関係であっても、継承関係にはしません。検証に通 れば、もちろん継承関係にします。 簡単でしょう? 本来無関係のオブジェクト同士うんぬんなどと悩む必要はありません。 なお、もし本来無関係だと思っていたオブジェクト同士にLSPが成り立つ のであれば、実はそのオブジェクト同士は、たぶん無関係じゃないんですよ。 しかし、通常のソフトウェア開発で、そういう発見を必要とすることは あまりありませんから、無関係だと思うオブジェクト同士について、 いちいちLSPを検証してみる必要はありません。
[この投稿を含むスレッドを表示] [この投稿を削除]
[714] Re:オブジェクト指向「初」入門
投稿者:CES
2007/02/20 02:13:25

>> 正方形は長方形のサブクラスであるとしても成り立つ場合は既に >> 書きました。is-a と LSP をどうしても両立させられない例を一 >> つでも出していただけませんか。 > >CES さんご自身が、正方形を長方形のサブクラスに『しない』方が >いい場合があると、[709]で認めているじゃないですか。常識的に >は、正方形 is-a 長方形ですから、当然、正方形は長方形のサブク >ラスとして継承関係を結ぶべきですし、Robert C. Martin 氏のエッ >セイでも、その方法をまず勧めています。しかし、そうしない方が >いい場合もあるわけですから、オブジェクト自身の is-a は必ずし >も判断基準に使えません。 俺はそういうことを言っているのではありません。 LSP なんか関係なく、「正方形 is a 長方形にならない場合もある」ということです。 その場合は、正方形が長方形でないのは何ら問題ではないのですから、「is a と LSP が矛盾する」とは言えません。 「常識的には」と書かれていますが、それが間違いの元です。 世の中に客観的な視点など存在しないというのは以前に書きました。 正方形 is a 長方形というのは、客観的に見えますが、「数学的に都合がいい見方」に過ぎません。常識と言うのも、大多数に都合がいい見方に過ぎません。真理ではないのです。 件の文献の勘違いは「長方形」の定義が曖昧なことです。 「正方形 is a 長方形」は数学に都合がいい見方、「縦と横の長さが独立していなければならない」は、このプログラムに都合がいい見方であって、数学に都合がいい見方ではない。 どちらの見方が間違いというのではありません。どちらも場合によっては正解なのですが、その「場合」が統一されていないのが間違いなのです。 このプログラムが「長方形」に何を期待しているのかが明確になっていないのがいけないのです。 大本の問題は、何のためのプログラムなのかを明確にしないまま、コードだけ示して煙に巻こうとしたことですね。 仮に、「常識的に考えて、正方形 is a 長方形なのだから、当然サブクラスにすべきだ」というのが正しいとして、では「りんご」は何のサブクラスにすべきですか? 常識的に考えて「果物」のサブクラス? それとも「バラ科の植物」? スーパーマーケットのシステム開発だったら「商品」のサブクラスにすべきではないですか? 唯一の正解は無いでしょう。場合によって、適切なものを選べば、それが正解です。 「正方形 is not a 長方形」にすべき場合は確かにあるでしょう。 それは、LSP に都合が悪いからそうなったのではなく、作りたいソフトの目的に合致しないからそうなったのです。 「is-a は LSP と両立できなかったので泣く泣く諦めた」のではなく「そもそも両立する必要が無かった」のです。 現在は is-a が推奨されています。百歩譲って has-a もまぁ認めるとしましょう。 問題は、「LSP さえ成り立つのなら、まったく無関係のクラス同士を継承関係にしていいのか」ということです。 (どういう設計になるのか知りませんが)LSP が成り立つのなら、車を鳥のサブクラスにするのもアリなのですか? オブジェクト指向の第一目的は「わかりやすくすること」であると(今は)思っています(以前、この掲示板に長期滞在したときは「バグを減らすこと」だと思っていました。考えは変わる可能性があります)。 本来、無関係のオブジェクト同士を継承関係にするのがわかりやすいですか? >> よろしければ、おすすめの本を紹介していただけないでしょうか。 > >今回紹介したエッセイ自身を含んだ、Robert C. Martin 氏の >「アジャイルソフトウェア開発の奥義」はいかがでしょう? >http://hamasyou.com/archives/System/aeeoeeueaconoeoeass.php >http://hamasyou.com/archives/System/aeeoeeueaoeeoeaass.php >に長めの紹介があります。 持ってますけど読んでませんでした。 OCP や LSP の評判を聞いて買ったのですが、買ったきりで。 そのうち読むことにしましょう。 こちらにも一点、考え直したことがあったので、最後にそれについて言及します。 オブジェクト指向において、オブジェクトを特徴付けるものは、属性と振る舞いです(プロパティとメソッドとか、メンバ変数とメンバ関数とか、言語によって呼び方はいろいろあるでしょうが)。 つまり、全く同じ属性と振る舞いを持つクラスは、同じクラスだと考えるべきです。 これは、「LSP が成り立つならば is-a も成り立つ」と言い換えることもできます。 しかし、逆に言えば「違うクラスに、全く同じ属性と振る舞いを持たせるべきではない」「関係の無いクラスに、LSP を成り立たせるべきではない」とも言えます。 そう考えれば、「is-a が成り立つのならば LSP が成り立つのは当然」「is-a が成り立たないのならば、LSP も成り立たせるべきではない」のではないでしょうか。
[この投稿を含むスレッドを表示] [この投稿を削除]
[713] Re:オブジェクト指向「初」入門
投稿者:kit
2007/02/20 02:13:25

> 俺がプログラミングを初めてまだ7年、オブジェクト指向が分かっ > てきたのはここ1、2年ほどのことですのでね。 意外と長いんですね。 私はプログラミング歴は24年ぐらい、オブジェクト指向に関しては プログラミング言語C++第1版の和訳や、Smalltalk-80のオレンジブッ クの和訳が出た頃からですから、20年弱くらいですかね。 その前に、先輩から米国byte誌のSmalltalk-80特集号を見せてもらっ たこともありましたが。 > 正方形は長方形のサブクラスであるとしても成り立つ場合は既に > 書きました。is-a と LSP をどうしても両立させられない例を一 > つでも出していただけませんか。 CES さんご自身が、正方形を長方形のサブクラスに『しない』方が いい場合があると、[709]で認めているじゃないですか。常識的に は、正方形 is-a 長方形ですから、当然、正方形は長方形のサブク ラスとして継承関係を結ぶべきですし、Robert C. Martin 氏のエッ セイでも、その方法をまず勧めています。しかし、そうしない方が いい場合もあるわけですから、オブジェクト自身の is-a は必ずし も判断基準に使えません。Robert C. Martin 氏が、エッセイの 「本当の問題」「何が悪いのか?」「Design By Contract」のとこ ろで説明しているのは、そういうことです。オブジェクト自身の is-a で考えるのは誤りであり、オブジェクトの振舞いに関する is-a で考えないといけないのです。前に出た円と楕円の話も同じ です。 このあたりは、和訳を読むよりも、原文 http://www.objectmentor.com/resources/articles/lsp.pdf の "What Went Wrong" のところを読んだ方が、むしろ理解しやす いかもしれません、「a Square object is definitely not a Rectangle object.」と書いてありますから。和訳の「決定的な違 いがあるのです。」という表現では、残念ながら、ここの is-a と is-not-a のニュアンスが消えてしまっています。私は原文の方を 先に読んだので、ここのところが非常に強く印象に残りました。 なぜ、オブジェクト自身の is-a 関係が継承関係の設計に使えない 場合があるのか、そのことを説明しているのが LSP です (ただし、 正方形や円のケースでは、LSP 以外にも、メモリ効率という別の理 由もあります)。継承関係の設計において、オブジェクト自身の is-a 関係は使えない場合がある弱い判断基準なわけですが、LSP は常に使える絶対的な判断基準なわけです。実はLSP(オブジェクト の振舞いに関する is-a) の方が、オブジェクト自身のis-aよりも むしろ本質的な原則なわけです。 現在では、has-a の関係は、継承よりも委譲を使うのが良い解だと されていますが、昔は has-a でも継承を使うことが良くありまし た。今でもたまにそういうプログラムを見ることがあると思います。 これも、アプリケーションを限定すれば、has-a で LSP を満たす 場合があることから来ているわけです。has-a で継承して問題のな いアプリケーションは、オブジェクト自身の is-a 関係で継承して 問題のないアプリケーションよりも、はるかに少ないので廃れてき ているわけですが。 has-a が廃れてきているのに is-a がそうではないのは、オブジェ クト自身についてis-a の関係が成り立つ場合のほとんど(ただし全 てではない)で、同時に、オブジェクトの振舞いに関する is-a 関 係(すなわちLSP)も満たすからです。 > よろしければ、おすすめの本を紹介していただけないでしょうか。 今回紹介したエッセイ自身を含んだ、Robert C. Martin 氏の 「アジャイルソフトウェア開発の奥義」はいかがでしょう? http://hamasyou.com/archives/System/aeeoeeueaconoeoeass.php http://hamasyou.com/archives/System/aeeoeeueaoeeoeaass.php に長めの紹介があります。 ただ、和訳だと上述したように、ニュアンスが失われる部分はある でしょうね。また、data中心でモデリングした結果の扱いについて は、この本の主張に異論がある場合もあるでしょう。この本では常 にOOAを優先すべしという方向ですが、data中心でモデリングした 結果の方を優先した方がいい場合もある筈です。 私は、Robert C. Martin 氏自身の名前は、亡くなられた石井勝さ んのページで知りました。 http://www.objectclub.jp/community/memorial/homepage3.nifty.com/masarl/article/oo-principles.html 石井さんがこのページを書かれたのは1999年ですね。 今ではLSPは有名な原則ですが、これが広まったのは Liskov 氏自 身の功績というよりは、Robert C. Martin 氏の功績の方が大きい と思います。私がこの法則を知ったのも今回のエッセイを読んだ からですし、google で The Liskov Substitution Principle を 検索して最初に出てくるのも、このエッセイですし。
[この投稿を含むスレッドを表示] [この投稿を削除]
[712] Re:オブジェクト指向「初」入門
投稿者:CES
2007/02/20 02:13:25

>もちろん、「オブジェクトが is-a であるか」と「オブジェクトの『振舞い』 >が is-a であるか」の二つが矛盾しない場合は問題ありません。しかし、矛盾 >した場合に優先すべきなのは、LSP の方です。 >しかしどうやら CES さんは、矛盾した場合、LSP よりも前者を優先すべきだ >とお考えのようですね。 どちらかと言えばそうかもしれません。 LSP を守ることも重要ですが、まずはオブジェクトの is-a を優先し、その上で LSP が守られるように都合をつけるべきだと思います(結果的には、両方守るべきです)。 >Robert C. Martin がこの文書を発表してから、もう10年近く、Liskov から >数えれば、もう15年以上経っており、私は既に常識的な知識だと思っていまし >たが、驚かれたということは、どうやらそうではなかったようですね。 俺がプログラミングを初めてまだ7年、オブジェクト指向が分かってきたのはここ1、2年ほどのことですのでね。 >そもそも LSP や、この文書が有名になったのは、「オブジェクトが is-a である >か」という判定条件が成り立たない場合があるということを、はっきりと示 >しているからだと思うのですが。 >is-a だけで済むのであれば、わざわざ原則として掲げる必要も、文書で解説 >する必要もありません。 >失礼ながら、御自身の考えを他人の掲示版で開陳されるよりも先に、もう少し >オブジェクト指向関係の良書で勉強された方が良いのではないでしょうか。 よろしければ、おすすめの本を紹介していただけないでしょうか。 >少なくともこれまでのところ、私は CES さんの意見に説得される可能性は >ありません。CES さんの考えを証明する具体的な例を一切目にしていません >ので。前の投稿でも書きましたが、私は机上の空論は嫌いですし、具体的な >例のない議論に説得されることは決してありません。 >(ぱ)さんも同様ではないかと思います。 その言葉はそっくりお返しします。 正方形は長方形のサブクラスであるとしても成り立つ場合は既に書きました。 is-a と LSP をどうしても両立させられない例を一つでも出していただけませんか。
[この投稿を含むスレッドを表示] [この投稿を削除]
[711] Re:オブジェクト指向「初」入門
投稿者:kit
2007/02/20 02:13:25

> いや恐れ入った。 > 「オブジェクトが is-a であるか」は守られなくてもいいのか。 その通りです。 もちろん、「オブジェクトが is-a であるか」と「オブジェクトの『振舞い』 が is-a であるか」の二つが矛盾しない場合は問題ありません。しかし、矛盾 した場合に優先すべきなのは、LSP の方です。 しかしどうやら CES さんは、矛盾した場合、LSP よりも前者を優先すべきだ とお考えのようですね。 Robert C. Martin がこの文書を発表してから、もう10年近く、Liskov から 数えれば、もう15年以上経っており、私は既に常識的な知識だと思っていまし たが、驚かれたということは、どうやらそうではなかったようですね。そも そも LSP や、この文書が有名になったのは、「オブジェクトが is-a である か」という判定条件が成り立たない場合があるということを、はっきりと示 しているからだと思うのですが。 is-a だけで済むのであれば、わざわざ原則として掲げる必要も、文書で解説 する必要もありません。 失礼ながら、御自身の考えを他人の掲示版で開陳されるよりも先に、もう少し オブジェクト指向関係の良書で勉強された方が良いのではないでしょうか。 あるいは、もし、「オブジェクトが is-a であるか」は LSP よりも優先する という考えをどうしても主張されたいのであれば、掲示版はそもそも不向きな メディアだと思います。 なぜ LSP よりも優先するのかを、適切な例を含めた上で、ご自分の Web ペー ジで解説された方が良いと思いますよ。 もし、Barbara Liskov や Robert C. Martin も優れた考えであるのなら、 独立した文書として公開する価値が十分あると思います。 少なくともこれまでのところ、私は CES さんの意見に説得される可能性は ありません。CES さんの考えを証明する具体的な例を一切目にしていません ので。前の投稿でも書きましたが、私は机上の空論は嫌いですし、具体的な 例のない議論に説得されることは決してありません。 (ぱ)さんも同様ではないかと思います。 > 「正方形は長方形のサブクラスであるか?」という質問に、唯一の正解はあり > ません。答えは、数学に厳密である必要がある場合には YES 、そうでない場 > 合には NO になります。 あるアプリケーションが、Robert C. Martin が例に示しているような 条件と、数学的に厳密であるという必要があるという条件のどちらも 同時に満たしている必要がある場合はどうすれば良いのでしょうか? もちろん、答えは NO です。 従って、上に書いた CES さんの答え「数学に厳密である必要がある 場合には YES」は、条件に抜けがある誤った答であるということに なります。 私には、CES さんが LSP の本質を理解していないように見えますね。 理解しているなら、上のような文章が出てくる筈はありません。
[この投稿を含むスレッドを表示] [この投稿を削除]
[710] Re:オブジェクト指向「初」入門
投稿者:CES
2007/02/20 02:13:25

#ちょっと落ち着いて整理しましょう… >だったら最初からそう書けばいいのに。 >つか、それを読み取れというのは無茶と言うものです。 これは、(お互いに)「自分ではそう言ったつもりだったけど、相手には伝わらなかった」ということで傷み分けにしましょうや。 >私が最初から言っているのは、 > >「クラスを辞書で引いて分類と書いてあるからといって、プログラムの設計の際に、 >クラスを分類として捉えることが正しいことになるわけではない」 > >ということです。 なるほど。 俺は「辞書的用語」と「術語」の問題(あくまで用語の問題で、実際の設計はまた別問題)だと思っていました。 前橋さんは「どう呼ぶか」よりも「実際にどう設計するか」を問題視されていた。そこが齟齬の原因。 ちなみに、それに関する俺の答えは [706] > もちろん、実装の都合上、必ずしもそうとは言えないクラスが出てくることはあり得るでしょう。しかし、それらは例外として考えるべきであり、基礎としては無駄ではありません です。一言で言えば「(例外はあるかもしれないが)原則的に、辞書的意味と同じと考えていい」ということ。 後半は感情的になって煽ってしまったことはお詫びいたします。 #最後の最後で何とかまとまってよかった。
[この投稿を含むスレッドを表示] [この投稿を削除]
[709] Re:オブジェクト指向「初」入門
投稿者:CES
2007/02/20 02:13:25

> リンク先の文章で示されている「正方形を長方形のサブクラスにするのが誤り」という話が的外れであることは、ずいぶん前に書いてますよ。 と言うだけでは何なのでちょっと補足。 「正方形は長方形のサブクラスである」というのは、数学的に見れば、確かにそうです。 しかし、長方形の数学的な性質とは、「4つの角が全て直角である四角形」というだけであって「縦と横の長さが独立していなければならない」という要件はありません。 リンク先の文章では、その数学的には必要とされていない要件を要求しているのですから、もはや「数学的には正方形は長方形のサブクラスだ」という前提は成り立たないのです。 では、正方形クラスを長方形クラスのサブクラスとして設計するのは誤りなのでしょうか? そうとは限りません。 数学的に正しいプログラムを書く必要があって、長方形の縦と横の長さが独立していなければならないという要件が無いのなら、この設計は全く妥当なものです。 「正方形は長方形のサブクラスであるか?」という質問に、唯一の正解はありません。 答えは、数学に厳密である必要がある場合には YES 、そうでない場合には NO になります。 提示された文章では、それがちぐはぐだからおかしなことになっているのです。 [653] あたりで言っているのはそういうことです。
[この投稿を含むスレッドを表示] [この投稿を削除]
[708] Re:オブジェクト指向「初」入門
投稿者:CES
2007/02/20 02:13:25

>> 「サブクラスの方が機能が上」という考え方だと、is-a の関係を考えた時 >> に「機能が豊富なものは機能がショボいものの一種」ということになって変 >> だよね。 > >変じゃないですよ? >Robert C. Martin が、Liskovの置換原則に関する有名な文書 >http://www2.ocn.ne.jp/~yamagu/object/LSP-J.pdf >で述べた通り、継承の際に使う is-a の関係は、「オブジェクトが is-a で >あるか」ではなく、「オブジェクトの『振舞い』が is-a であるか」で判断 >すべきです。 >「機能が豊富なものは機能がショボいものの一種」というのは、この原則を >平易な言葉で言い替えたものに過ぎません。 >オブジェクト指向設計の大原則です。 いや恐れ入った。 「オブジェクトが is-a であるか」は守られなくてもいいのか。 LSP を守るべきであるのは当然だけど、リンク先の文章で示されている「正方形を長方形のサブクラスにするのが誤り」という話が的外れであることは、ずいぶん前に書いてますよ。
[この投稿を含むスレッドを表示] [この投稿を削除]
[707] Re:オブジェクト指向「初」入門
投稿者:kit
2007/02/20 02:13:25

抽象論は苦手なので、このスレッドには書かないようにしようと思ってたの ですが、堂々めぐりしているように見えるので。 > 「サブクラスの方が機能が上」という考え方だと、is-a の関係を考えた時 > に「機能が豊富なものは機能がショボいものの一種」ということになって変 > だよね。 変じゃないですよ? Robert C. Martin が、Liskovの置換原則に関する有名な文書 http://www2.ocn.ne.jp/~yamagu/object/LSP-J.pdf で述べた通り、継承の際に使う is-a の関係は、「オブジェクトが is-a で あるか」ではなく、「オブジェクトの『振舞い』が is-a であるか」で判断 すべきです。 「機能が豊富なものは機能がショボいものの一種」というのは、この原則を 平易な言葉で言い替えたものに過ぎません。 オブジェクト指向設計の大原則です。 > 集合論(というか論理学のベン図)で考えれば、スーパークラスはサブクラ > スよりも一段階抽象的なので、直接比較できないことはわかるよね。 これは、「オブジェクトが is-a であるか」を継承関係の設計の判断基準に 使うべきだと述べているように見えます。これは、第一近似として使いやすい 方法ではありますが、Robert C. Martin の文書で示されている通り、厳密に 考えると誤りであり、Liskovの置換原則の方を優先すべきです。
[この投稿を含むスレッドを表示] [この投稿を削除]