K.Maebashi's BBS

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

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

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

[408] クラスメソッドとクラス変数
投稿者:タイガー
2007/02/20 02:13:25

こんにちは。 「プログラミング言語を作る」をいつも楽しみにしています。 個人的には、オブジェクトとクロージャ辺りからだんだん面白くなってきたと思います。 まだ機能的に色々追加していくのだと思いますが、クラスメソッドとクラス変数は、今の仕様で実現は可能ですか?色々考えたのですが、思いつきません。 また、実現不可能な場合、追加の仕様としてはどういうのを考えていますか? グローバル変数で代用するのはちょっと…と思います。
[この投稿を含むスレッドを表示] [この投稿を削除]
[409] Re:クラスメソッドとクラス変数
投稿者:(ぱ)
2007/02/20 02:13:25

>「プログラミング言語を作る」をいつも楽しみにしています。 ありがとうございます。 >クラスメソッドとクラス変数は、今の仕様で実現は可能ですか? 「今の(crowbarの)仕様」ということだと、そもそもクラスがないのに、 クラスメソッド、クラス変数とは何ぞや? という話になるかと思いますが、 現在、create_point()のような関数を作ることでクラスじみたことを 実現しているように、何とか似たことを実現したい、ということであれば、 「クラスもまたオブジェクトである」 「インスタンスは、クラスのconstructorメソッドで生成する」 ということにして、 function create_point_class() { class = new_object(); # このへん this.constructor = closure() { this = new_object(); this.x = x; this.y = y; this.print = closure() { print("(" + this.x + ", " + this.y + ")\n"); }; … return this; }; return class; } とか書けばできそうに思うのですが、どうでしょうか(すみません試してないです)。 「#このへん」で作ったローカル変数や、ローカル変数に代入したクロージャは、 コンストラクタの中で定義されているメソッドからだけ参照できるはずです。 >また、実現不可能な場合、追加の仕様としてはどういうのを考えていますか? >グローバル変数で代用するのはちょっと…と思います。 私としては、クラス変数やクラスメソッドというものに、わざわざ言語仕様で 対応するだけの価値を感じていません。 crowbarにはそもそもクラスがないですが、クラスベースのOO言語を作るとしても、 クラス変数やクラスメソッドはつけず、グローバル変数のようなものにして、 名前空間を選択的に開示できるような形にすると思います。
[この投稿を含むスレッドを表示] [この投稿を削除]
[411] Re:クラスメソッドとクラス変数
投稿者:タイガー
2007/02/20 02:13:25

こんにちは。 >「今の(crowbarの)仕様」ということだと、そもそもクラスがないのに、 >クラスメソッド、クラス変数とは何ぞや? という話になるかと思いますが、 確かにその通りですね。クラス「らしきもの」ですね。 >function create_point_class() { > class = new_object(); > # このへん > > this.constructor = closure() { > this = new_object(); > this.x = x; > this.y = y; > > this.print = closure() { > print("(" + this.x + ", " + this.y + ")\n"); > }; > … > return this; > }; > return class; >} > >とか書けばできそうに思うのですが、どうでしょうか(すみません試してないです)。 >「#このへん」で作ったローカル変数や、ローカル変数に代入したクロージャは、 >コンストラクタの中で定義されているメソッドからだけ参照できるはずです。 ソースの5行目は、 this.constructor = closure() { でなく、 class.constructor = closure() { だと思います。 上のコードで名前空間らしきものが表現できているように思いますが、 私の考えていたのは、オブジェクトを作らないでグローバルと名前空間が違う、 でも静的な寿命を持つ変数が使えるかを考えていました。 上のコードでは、new_object()でオブジェクトを作成しないと 「#このへん」の変数を参照できないと思いますので、 結局インスタンス変数に見えるような気がします。 >私としては、クラス変数やクラスメソッドというものに、わざわざ言語仕様で >対応するだけの価値を感じていません。 >crowbarにはそもそもクラスがないですが、クラスベースのOO言語を作るとしても、 >クラス変数やクラスメソッドはつけず、グローバル変数のようなものにして、 >名前空間を選択的に開示できるような形にすると思います。 たぶんその辺は言語の特徴になってくると思いますので、クラス変数らしきものを どう表現するのか(あるいはしないのか)は難しいかもしれません。 ただ、Javaとかに慣れているとクラス変数はストレートで分かりやすい気がします。
[この投稿を含むスレッドを表示] [この投稿を削除]
[412] Re:クラスメソッドとクラス変数
投稿者:(ぱ)
2007/02/20 02:13:25

>ソースの5行目は、 >this.constructor = closure() { >でなく、 >class.constructor = closure() { >だと思います。 です。すみません間違えました。 あと、「closure(x, y) {」のように引数が必要ですね。 >上のコードでは、new_object()でオブジェクトを作成しないと >「#このへん」の変数を参照できないと思いますので、 >結局インスタンス変数に見えるような気がします。 うーん、私が狙ったのは、複数のpointオブジェクトから共通に参照できる ひとつのクラスフィールド、です。 まあ、create_point_class()を複数回呼んでしまえば複数作れてしまいますが、 それは利用者側の問題にしてよいのではないかと。 あくまで「静的な」(ひとつしかない)データが、グローバル変数以外の方法で必要だ、 ということであれば、Cのstatic指定したローカル変数のようなものを付けると いうのはひとつの手かもしれませんが。
[この投稿を含むスレッドを表示] [この投稿を削除]
[415] Re:クラスメソッドとクラス変数
投稿者:タイガー
2007/02/20 02:13:25

>うーん、私が狙ったのは、複数のpointオブジェクトから共通に参照できる >ひとつのクラスフィールド、です。 >まあ、create_point_class()を複数回呼んでしまえば複数作れてしまいますが、 >それは利用者側の問題にしてよいのではないかと。 それだとprivateなインスタンス変数な気がします...。間違ってたらすいません。 但し、パフォーマンスはともかく、利用者側から見れば、 やりたいことは実現できますので現時点では十分かもしれません。 >あくまで「静的な」(ひとつしかない)データが、グローバル変数以外の方法で必要だ、 >ということであれば、Cのstatic指定したローカル変数のようなものを付けると >いうのはひとつの手かもしれませんが。 staticのローカル変数でも実現可能ですね。どう設計するかですね。 あと、制御構造の抽象化としてiteratorのようなものを表現する場合、 Ruby(のeachメソッド)みたいにクロージャをメソッドに渡す形でサンプルを書いてみたのですが、 もっとうまいやり方がありますか? あと、C#のforeachやJava5の拡張forのようなものを実装する予定はありますか? function Array(arr_data) { this = new_object(); this.arr_data = arr_data; this.iterate = closure(c) { for (i = 0; i < this.arr_data.size(); i = i + 1) { c(this.arr_data[i]); } }; return this; } a = {1, 2, 3, 4, 5, 6, 7, 8}; c1 = closure(i) { print("" + i + " "); }; a1 = Array(a); a1.iterate(c1);
[この投稿を含むスレッドを表示] [この投稿を削除]
[416] Re:クラスメソッドとクラス変数
投稿者:(ぱ)
2007/02/20 02:13:25

>>うーん、私が狙ったのは、複数のpointオブジェクトから共通に参照できる >>ひとつのクラスフィールド、です。 ... >それだとprivateなインスタンス変数な気がします...。間違ってたらすいません。 ひとつのクラスのconstructorで10個のpointが作られた時、 「クラスフィールド」はひとつしかないので、ただのインスタンス変数とは違うでしょう。 >あと、制御構造の抽象化としてiteratorのようなものを表現する場合、 >Ruby(のeachメソッド)みたいにクロージャをメソッドに渡す形でサンプルを >書いてみたのですが、 >もっとうまいやり方がありますか? これでよいのではないでしょうか。私もやるとすればこういう形だと思っていました。 >あと、C#のforeachやJava5の拡張forのようなものを実装する予定はありますか? 予定は未定ですが、文法としてそういうものを実装するつもりはありません。 言語仕様がライブラリに依存するのはあまり美しくないと思っていますので。
[この投稿を含むスレッドを表示] [この投稿を削除]
[417] Re:クラスメソッドとクラス変数
投稿者:kit
2007/02/20 02:13:25

> >あと、制御構造の抽象化としてiteratorのようなものを表現する場合、 > >Ruby(のeachメソッド)みたいにクロージャをメソッドに渡す形でサンプルを > >書いてみたのですが、 > >もっとうまいやり方がありますか? > これでよいのではないでしょうか。 えーと、iterator は、iterator 自体がオブジェクトであるような 作りにした方が便利だと思います。iterator を利用する側が 必ず closure を作るのは面倒くさいですし、なにより、 複数のコレクションを、複数の iterator を使って同時に並行して アクセスするようなプログラム、たとえばコレクションどうしの 大小比較: function compare(i, j) { for (; !i.isDone() && !j.isDone(); i.next(), j.next()) { if (i.currentItem() < j.currentItem()) return -1; if (i.currentItem() > j.currentItem()) return 1; } if (i.isDone() && j.isdone()) return 0; if (i.isDone()) return -1; else return 1; } print(compare(ArrayIterator(a), ArrayIterator(b)) + "\n"); みたいなことをしようとすると、eachメソッド方式では困っちゃいます。 なので、たぶん次のような設計の方がいいと思います。 function ArrayIterator(anArray) { this = new_object(); this.theArray = anArray; this.index = 0; this.first = closure() { this.index = 0; } this.next = closure() { this.index++; } this.isDone = closure() { return this.index >= this.theArray.size(); } this.currentItem() = closure() { return this.theArray[this.index]; } return this; } と、ここまで書いて、実際に動作するプログラムかどうか試そうとしたら、 文法エラーになっちゃいました。UNIX版をコンパイルしてみたんですが、 次のような1行だけのプログラムで a = {1,2}; 1:文法エラー({付近) となります。 また、次のような2行だけのプログラムでも a = new_object(); a.hoge = 1; 2:不正な文字(.) となります。 crowbarの実装の中身は全然見てないんですが、UNIX版だけの問題なんでしょうか?
[この投稿を含むスレッドを表示] [この投稿を削除]
[418] Re:クラスメソッドとクラス変数
投稿者:kit
2007/02/20 02:13:25

> と、ここまで書いて、実際に動作するプログラムかどうか試そうとしたら、 > 文法エラーになっちゃいました。 実装をちらっと見たら、すぐ原因が分かりました。 最新版である crowbar 0.3 ではなくて、crowbar 0.1.01 を使っていた のが原因でした。(大汗;;;) 大変失礼しました。 http://kmaebashi.com/programmer/devlang/index.html のページに、最新版への配布ページへのリンクがあると、 多少はこういう間違いが減るかもしれません… で、コンパイルしてみると、 1. 単項の「!」演算子がない。(これは欲しいです) 2. C言語の「,」演算子がないので、for 文の3番目の項の 「i.next(), j.next()」でエラー 3. closure() への代入文で「;」を忘れていた といった問題がありました。 直してみたものが以下の通りなんですが、 実行すると 33:面面面面民藥算劼boolean型には使えません。 となります。これはなぜでしょうね。 function ArrayIterator(anArray) { this = new_object(); this.theArray = anArray; this.index = 0; this.first = closure() { this.index = 0; }; this.next = closure() { this.index = this.index++; }; this.isDone = closure() { return this.index >= this.theArray.size(); }; this.currentItem = closure() { return this.theArray[this.index]; }; return this; } function compare(i, j) { while (i.isDone() == false && j.isDone() == false) { if (i.currentItem() < j.currentItem()) { return -1; } if (i.currentItem() > j.currentItem()) { return 1; } i.next(); j.next(); } if (i.isDone() && j.isdone()) { return 0; } if (i.isDone()) { return -1; } else { return 1; } } a = {1, 2, 3, 4, 5, 6, 7, 8}; for (i = ArrayIterator(a); i.isDone() == false; i.next()) { print("" + i.currentItem(), " "); } print("\n");
[この投稿を含むスレッドを表示] [この投稿を削除]
[419] Re:クラスメソッドとクラス変数
投稿者:kit
2007/02/20 02:13:25

いろいろ訂正… > で、コンパイルしてみると、 「コンパイルしてみる」じゃなくて「実行してみる」ですね。(^^;) コンパイラ言語ばかり使っている癖でつい… > this.next = closure() { this.index = this.index++; }; ここは編集間違いで this.next = closure() { this.index++; }; でした。 あと、this.theArray と this.index をユーザに公開するのは 良くないので、ArrayIterator() の実装は function ArrayIterator(anArray) { this = new_object(); index = 0; this.first = closure() { index = 0; }; this.next = closure() { index++; }; this.isDone = closure() { return index >= anArray.size(); }; this.currentItem = closure() { return anArray[index]; }; return this; } とした方がいいですね。 > 実行すると > 33:面面面面民藥算劼boolean型には使えません。 > となります。これはなぜでしょうね。 これは調べてません。
[この投稿を含むスレッドを表示] [この投稿を削除]
[420] Re:クラスメソッドとクラス変数
投稿者:(ぱ)
2007/02/20 02:13:25

取り急ぎ。 >で、コンパイルしてみると、 >1. 単項の「!」演算子がない。(これは欲しいです) >2. C言語の「,」演算子がないので、for 文の3番目の項の > 「i.next(), j.next()」でエラー ... >実行すると > 33:面面面面民藥算劼boolean型には使えません。 >となります。これはなぜでしょうね。 これは、エラーメッセージ生成部分がバグっているようで、本来は 「33:==はboolean型には使えません。」 と出るべきものです(メッセージの可変部が先頭にあるとだめらしい)。 で、==がなぜbooleanに使えないかというと、単に実装してないためです(^^; eval.cのeval_binary_booleanにelse ifを書き足すだけのはずですが、 すみません忘れてました。 http://kmaebashi.com/programmer/devlang/crowbar_src_0_3/S/10.html#280 booleanの比較なんてそうそうするもんじゃない、という考え方もありますが、 その上単項の!もないのではどないせいっちゅうんだ、という話ですね。 いろいろ仕様のポカ、テスト漏れがありましてすみません。次バージョンで直します。 報告ありがとうございました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[421] Re:クラスメソッドとクラス変数
投稿者:タイガー
2007/02/20 02:13:25

>えーと、iterator は、iterator 自体がオブジェクトであるような >作りにした方が便利だと思います。iterator を利用する側が >必ず closure を作るのは面倒くさいですし、なにより、 利用者側がclosureを作るのが面倒というのは、Ruby風の a1.iterate() { |i| print("" + i + " "); } という書き方ができないからであって、iterate()というメソッドの 中にループ処理を隠している分、Iteratorを使うよりも 記述はシンプルだと思います。 ただ逆に、慣れてないとループしているというのが分かりづらくなっています。 >複数のコレクションを、複数の iterator を使って同時に並行して >アクセスするようなプログラム、たとえばコレクションどうしの >大小比較: >function compare(i, j) { ... >} >print(compare(ArrayIterator(a), ArrayIterator(b)) + "\n"); >みたいなことをしようとすると、eachメソッド方式では困っちゃいます。 Iteratorのご紹介ありがとうございます。ただIteratorは良い方法だと思いますが、 Array自身にeachメソッドを付ける方法とどちらが良いかはよく分かりません。 Arrayみたいな「データ構造」を表すクラス(もどき)にリスト(の要素)をイテレートするという 「処理」を表すメソッドを持たせるのは、真面目に考えればよくないのかもしれませんが、 頻繁にでてくる処理なので、Arrayに持たせるのはバランス的に自然なのかもしれません。 ただ、compare()みたいなのをどう表現するのかは、調べてみます。 (ぱ)さんへ >ひとつのクラスのconstructorで10個のpointが作られた時、 >「クラスフィールド」はひとつしかないので、ただのインスタンス変数とは違うでしょう。 よく考えたらその通りでした。すいません。 closureの特性をうまく利用した方法だと思います。
[この投稿を含むスレッドを表示] [この投稿を削除]
[423] Re:クラスメソッドとクラス変数
投稿者:kit
2007/02/20 02:13:25

> 利用者側がclosureを作るのが面倒というのは、 : > iterate()というメソッドの中にループ処理を隠している分、 > Iteratorを使うよりも記述はシンプルだと思います。 確かに、「面倒」というのは、あまり適切じゃない形容詞でしたね。 each メソッドのような方法は、できる能力が限られている分、むし ろArrayIterator 的なやり方よりも短い表現で済むのが (crowbar を 含めて) 普通だと思います。 > Iteratorのご紹介ありがとうございます。ただIteratorは良い方法 > だと思いますが、Array自身にeachメソッドを付ける方法とどちら > が良いかはよく分かりません。 誤解を与えて申し訳ないです。Ruby でいう each メソッドのような 方法が悪いと言ってるわけではありません。each メソッド式のやり 方で十分な場合は、記述が短いという点で優れているわけですから、 そちらを使った方がいいことの方が多いでしょう。 しかし、記述力というか、制御構造の自由度という点では ArrayIterator 的なやり方の方が優れていますから、もしもどちらか 片方だけしか提供しないから選べと言われたら、ArrayIterator 的方 法がいいんじゃないでしょうか。 実際のところは、たいていの言語のコレクションライブラリが、each メソッド式と、ArrayIterator 的方法の両方の機能を提供しているよ うな気がします。 ただ、Iterator という言い方をした時に、each メソッドのような 方法が最初に出てくることには若干違和感があります。 GoF のデザインパターンをはじめ、Iterator という名称を用いた時 には、ArrayIterator() が生成するような、繰り返し用のオブジェク トを指すことの方が多いんじゃないでしょうか。
[この投稿を含むスレッドを表示] [この投稿を削除]
[424] Re:クラスメソッドとクラス変数
投稿者:kit
2007/02/20 02:13:25

> GoF のデザインパターンをはじめ、Iterator という名称を用いた > 時には、ArrayIterator() が生成するような、繰り返し用のオブジェ > クトを指すことの方が多いんじゃないでしょうか。 念のため確認してみたんですが、GoF の場合、クラス図では ArrayIterator() 式のやり方しか記載してないんですが、 文章の方では、ruby の each メソッド式のやり方も紹介してました。 この場合、ArrayIterator() 式を外部 Iterator、each メソッド式を 内部 Iterator と呼んで区別するようです。 読んだのははるか昔なので、さっぱり忘れてました。 失礼しました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[425] Re:クラスメソッドとクラス変数
投稿者:タイガー
2007/02/20 02:13:25

Rubyで、kitさんのcompare()メソッドを実装するにはどうすれば実現可能か考えてみました。 まず、Array(配列を表す)クラスの他にLinked(リンクリストを表す)クラスが あると過程して、この2つのクラス両方がcompare()に区別なく渡せるような実装を考えます。 方法1. ArrayとLinkedの両方に共通なメソッドで、各要素を先頭から順に 取り出せる関数(インターフェース)を定義する。 つまり、next()、isDone()、currentItem()を両方のクラスに実装する。 compare()に、ArrayやLinkedのインスタンスを渡し、 このメソッドを使って実装する。 方法2. Iteratorクラスを作る。ArrayクラスとLinkedクラスの区別は、 Iteratorクラスの中に隠す。 compare()に、Iteratorのインスタンスを渡す。 方法3. Linkedにも(Arrayクラスの様な)to_aメソッドを実装し、 to_aで、全要素を配列にして1つずつ比較。 私はあまりRubyに精通していないので、以上の単純な方法を考えました。 まず、方法3ですが、実現はできてもcompare()の実装の「ロジック」が ストレートな表現ではないため、良い方法とは思えません。同様に 特殊なことで実現できたとしても同じ意味で良くないです。 方法1は、「データ構造」クラスの中に(2つのクラスに共通な、つまり抽象的な) データのアクセサをつけることで実現します。 方法2は、kitさんと同様にIteratorクラスで表現する方法です。 方法1と方法2の比較ですが、どちらが良いのかは難しいですが、 Arrayクラスをあまりよごしたくないので、直感的にはIteratorクラスを 作成する方が良いように思えます。 >しかし、記述力というか、制御構造の自由度という点では >ArrayIterator 的なやり方の方が優れていますから、もしもどちらか その通りかもしれません。 >実際のところは、たいていの言語のコレクションライブラリが、each >メソッド式と、ArrayIterator 的方法の両方の機能を提供しているよ >うな気がします。 RubyはIteratorクラスがありません。observer(Observableモジュールを使う) とかはあるみたいなので、Iteratorも標準で入れて欲しいです。 >この場合、ArrayIterator() 式を外部 Iterator、each メソッド式を >内部 Iterator と呼んで区別するようです。 結局、データ構造のクラスの中に入れるか、別のクラスにするかという 感じでしょうか。 私もIteratorと言うと外部の方が思い浮かびます。Javaのイメージで。 crowbarは、Rubyのイメージだったので内部の方の実装をイメージしてました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[426] Re:クラスメソッドとクラス変数
投稿者:(ぱ)
2007/02/20 02:13:25

私は常々Javaとかで外部イテレータを使うたび、「めんどくせー」と思ってました。 なので、Ruby式のイテレータいいじゃん、と思っていましたが、 確かにkitさんのおっしゃるようなケースで困りますね。 (Javaのように)コレクションがIteratorを返すようになっていれば、 ライブラリ関数のforeachとクロージャで、C#のforeachみたいなものは作れるから、 その方面でいくのがよさそうですね。 >方法1. ArrayとLinkedの両方に共通なメソッドで、各要素を先頭から順に > 取り出せる関数(インターフェース)を定義する。 これはまずいのでは。たとえば「コレクション中に同じ要素がないかどうか」を 二重ループでチェックするような場合、コレクションそのものが位置を保持していると ひとつしか持てないので困ります。 コレクションにeachメソッドを付けるやり方では、位置を押さえているのは eachメソッドのローカル変数なので問題にならないですけど。
[この投稿を含むスレッドを表示] [この投稿を削除]
[428] Re:クラスメソッドとクラス変数
投稿者:タイガー
2007/02/20 02:13:25

>これはまずいのでは。たとえば「コレクション中に同じ要素がないかどうか」を >二重ループでチェックするような場合、コレクションそのものが位置を保持していると >ひとつしか持てないので困ります。 確かにその通りですね。良くない設計ですね。 結局、外部Iteratorしかなさそうですね...。 ところでこれって、(ぱ)さんの言われているマルチプルインスタンスの問題ですか? >方法2. Iteratorクラスを作る。ArrayクラスとLinkedクラスの区別は、 > Iteratorクラスの中に隠す。 > compare()に、Iteratorのインスタンスを渡す。 あと方法2ですが、よく考えてみたらArrayとLinkedの区別をIteratorクラスに隠す のは良くないですね。if~elseが出てくるので。 ArrayIteratorとLinkedIteratorの両方を用意して、利用者側(クライアント側)が それを使うしかないですね。クラスの生成部分を抽象化したければJavaみたいに Factoryで隠せば良いですので。 今回色々勉強になりました。ありがとうございました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[429] Re:クラスメソッドとクラス変数
投稿者:(ぱ)
2007/02/20 02:13:25

>あと方法2ですが、よく考えてみたらArrayとLinkedの区別をIteratorクラスに隠す >のは良くないですね。if~elseが出てくるので。 ええと、Javaのようにイテレータの生成メソッドをコレクションに付けた上で、 それぞれオーバーロードというか、別のクロージャを割り当てれば、if文は 出てこないのでは? ところで、現行の実装では、配列にはメンバを追加できないので、配列から イテレータを取得できるようにするにはeval.cをいじって「メソッドもどき」を 追加しなきゃいけないわけですが、まあこれはこれでいいんじゃないかと 私としては思っています。「すべてがオブジェクト」とか主張したいわけでは ないですので。
[この投稿を含むスレッドを表示] [この投稿を削除]
[430] Re:クラスメソッドとクラス変数
投稿者:(ぱ)
2007/02/20 02:13:25

>ところでこれって、(ぱ)さんの言われているマルチプルインスタンスの問題ですか? この部分にレスつけ忘れてました。 本質的には同じことですよね。多重度の問題。UMLで「0..*」とか書くやつです。 先のタイガーさんの「方法1.」だと、コレクションが唯一のイテレータを 保持していると言えますから、多重度は1です。 コレクションそのものが複数作れますから、イテレータも複数作れるには 違いないけれど、ひとつのコレクションに対してはひとつだから先に書いたような 問題が発生します。 インスタンス自体がひとつしかないケースは、なんというか「地面」があって、 そこからそのオブジェクトに線が引いてあって、地面のところに「多重度1」の 指定があるようなイメージを持っています。私の場合。 で、その線の根元というのは要するにstaticな変数なのであって、 私はあまりたくさんのオブジェクトが地面にくくりつけられているモデルは 好きじゃないので、staticに冷淡だったりするわけです。
[この投稿を含むスレッドを表示] [この投稿を削除]
[431] Re:クラスメソッドとクラス変数
投稿者:タイガー
2007/02/20 02:13:25

>本質的には同じことですよね。多重度の問題。UMLで「0..*」とか書くやつです。 >先のタイガーさんの「方法1.」だと、コレクションが唯一のイテレータを >保持していると言えますから、多重度は1です。 > >コレクションそのものが複数作れますから、イテレータも複数作れるには >違いないけれど、ひとつのコレクションに対してはひとつだから先に書いたような >問題が発生します。 > >インスタンス自体がひとつしかないケースは、なんというか「地面」があって、 >そこからそのオブジェクトに線が引いてあって、地面のところに「多重度1」の >指定があるようなイメージを持っています。私の場合。 > >で、その線の根元というのは要するにstaticな変数なのであって、 >私はあまりたくさんのオブジェクトが地面にくくりつけられているモデルは >好きじゃないので、staticに冷淡だったりするわけです。 概念とかを説明するときに、そういったイメージとかの説明があると 理解しやすくて分かりやすいですね。 今回マルチプルインスタンスとか多重度が重要というのが分かりました。 1つのデータ(オブジェクト)の個数を考えるのは簡単ですが、 2つ以上のデータ、つまりある1つのデータの個数に対して、 それに関連するデータの個数が複数必要なのか、1つで良いのかとか、 それが多重度ということですね。 >ええと、Javaのようにイテレータの生成メソッドをコレクションに付けた上で、 >それぞれオーバーロードというか、別のクロージャを割り当てれば、if文は >出てこないのでは? おっしゃる通りだと思います。確かにJavaではそうなっていますし、 Javaのやり方は、うまいやり方だと思います。 Iterator(処理)は、ArrayList(データ)を知らないといけない訳ですし。 ただ、単一責任の原則というのがあって、1つのオブジェクト(クラス)は、 それぞれ1つの役割のみを持つようにするということで、 Iteratorの生成をArrayList自身に持たせるというのは、どうなのでしょうか? ただ逆に、生成部分を他に分けたからといってメリットがあるわけではないですし、 むしろ、ArrayList自身に持たせてしまった方がすっきりする気がします。 ただ、Javaの設計がベストなのかは分かりません。 あと、「プログラミング言語を作る」が書籍化されることを期待しています。 ありがとうございました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[432] Re:クラスメソッドとクラス変数
投稿者:(ぱ)
2007/02/20 02:13:25

>http://kmaebashi.com/programmer/devlang/index.html >のページに、最新版への配布ページへのリンクがあると、 >多少はこういう間違いが減るかもしれません… 一応つけました。 ただ、crowbarはまだいろいろな意味で未完成品なので、 いかにもな「ダウンロードページ」はまだ作りたくないところです。 ver.0.3.01の修正でkitさんのプログラムが動くようになりましたので、 動いたものを貼っておきます。 function ArrayIterator(anArray) { this = new_object(); index = 0; this.first = closure() { index = 0; }; this.next = closure() { index++; }; this.isDone = closure() { return index >= anArray.size(); }; this.currentItem = closure() { return anArray[index]; }; return this; } function compare(i, j) { for (; !i.isDone() && !j.isDone(); i.next(), j.next()) { if (i.currentItem() < j.currentItem()) { return -1; } if (i.currentItem() > j.currentItem()) { return 1; } } if (i.isDone() && j.isDone()) { return 0; } if (i.isDone()) { return -1; } else { return 1; } } a = {1, 2, 3, 4, 5, 6, 7, 8}; b = {1, 2, 3, 4, 5, 6, 7, 9}; print("compare.." + compare(ArrayIterator(a), ArrayIterator(b)) + "\n"); for (i = ArrayIterator(a); !i.isDone(); i.next()) { print("" + i.currentItem() + " "); } print("\n");
[この投稿を含むスレッドを表示] [この投稿を削除]
[434] Re:クラスメソッドとクラス変数
投稿者:kit
2007/02/20 02:13:25

> 一応つけました。 : > 動いたものを貼っておきます。 素早い… どうもありがとうございます。 あと、素朴な疑問なんですが、現在 && や || が短絡演算になってない のは単なる手抜きの結果とのことなんですが、これはやはり将来的には 短絡演算になると期待していていいんでしょうか? さらに妄想ですが、ラベル指定の break/return 文に関して、字面的に ネストした内側のクロージャから、外側の関数のラベルを指定して脱出 できると、ライブラリレベルで Lisp 風の catch & throw が書けて楽 しいと思います。(returnするだけのクロージャを作っておいて、必要 な時に呼び出すと大域脱出できる。実際 Common Lisp はそういう言語 規格になってます。っていうか内輪の話になりますが、昔NJSのNaClに 対して、そういうcatch & throw の実装をマクロで書いて遊んでいたの でした。)
[この投稿を含むスレッドを表示] [この投稿を削除]
[435] Re:クラスメソッドとクラス変数
投稿者:kit
2007/02/20 02:13:25

っと簡単に書きましたが、大域脱出ができるようになると、 Lisp の unwind-protect、Java の finally 節相当の機能が どうしても欲しくなり、さらにその向こうにもっと深い淵が 待ってるような気もしますね。(NaClにはunwind-protect も ありました。)
[この投稿を含むスレッドを表示] [この投稿を削除]
[437] Re:クラスメソッドとクラス変数
投稿者:(ぱ)
2007/02/20 02:13:25

>あと、素朴な疑問なんですが、現在 && や || が短絡演算になってない >のは単なる手抜きの結果とのことなんですが、これはやはり将来的には >短絡演算になると期待していていいんでしょうか? あ、それはすぐできるのでやります。すっかり忘れてました。 >さらに妄想ですが、ラベル指定の break/return 文に関して、字面的に >ネストした内側のクロージャから、外側の関数のラベルを指定して脱出 >できると、ライブラリレベルで Lisp 風の catch & throw が書けて楽 >しいと思います。 なるほど… 勉強になります。 (Java風に考えれば)こんな感じですかね。 try(closure(throw) { }, closure() { }); throwには脱出用のclosureが入っているつもりなんですが、これはやっぱり 引数で渡すことになるんでしょうか? ただまあ例外処理については、今のところふつうの(?) try catch finallyを 付けようかと思ってますけど。
[この投稿を含むスレッドを表示] [この投稿を削除]
[438] Re:クラスメソッドとクラス変数
投稿者:kit
2007/02/20 02:13:25

> (Java風に考えれば)こんな感じですかね。 >try(closure(throw) { > }, > closure() { > }); この例はちょっと意味が良く分かりませんでした。 Common Lisp 等にある return/return-from の機能は、もっと 原始的な感じで、むしろ C の setjmp/longjmp に近いレベルに なります。たとえば、break にラベル指定ができるとすると、 (Lisp 風じゃなくて crowbar 風に書くと) こういう感じになる と思います。 exit_to_toplevel = null; function subroutine() { ... 中略 ... if (致命的エラーが起きたら) { exit_to_toplevel(); } ... 中略 ... } function do_it(command) { ... 中略 ... subroutine(); ... 中略 ... } for (;;) { toplevel: { exit_to_toplevel = closure() { break toplevel; }; command = キー入力; do_it(command); } } あるいは、関数名を指定した return (return_from) があれば、 こんな感じです。 function subroutine(do_exit) { ... 中略 ... if (致命的エラーが起きたら) { do_exit(false); } ... 中略 ... return 1234; } function do_it(command) { do_exit = closure(result) { return_from do_it result; }; ... 中略 ... value = subroutine(do_exit); ... 中略 ... return true; } for (;;) { command = キー入力; if (!do_it(command)) { print("error happend\n"); } } もっとも、Lisp でこういうプリミティブなスタイルのプログラミング が良く行われているというわけではないですが… 上のように書くにし ても、ユーザーが明示的に closure を変数にセーブするのではなく、 closure は catch & throw マクロに付随する連想リストの中に隠されて、 ユーザの目には見えなくなります。 また、いまどきは、もっと Java 等に似たスタイルが使われているようです。 http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html
[この投稿を含むスレッドを表示] [この投稿を削除]
[440] Re:クラスメソッドとクラス変数
投稿者:(ぱ)
2007/02/20 02:13:25

>>try(closure(throw) { >> }, >> closure() { >> }); > >この例はちょっと意味が良く分かりませんでした。 説明不足ですみません。これ全体がJavaでいうところのtry catchになっており、 ライブラリ関数tryの第1引数にtry節、第2引数にcatch節のclosureを渡します。 また、catch節側にも引数が要りますね。 function try(c1, c2) { exception = null; toplevel: { throw = closure(ex) { exception = ex; break toplevel; }; c1(throw); } if (exception != null) { c2(exception); } } こういうtry関数をライブラリで用意することで、アプリケーション側では try(closure(throw) { # try節 }, closure(exception) { # catch節 }); こう書けるのかなあ、と。 >Common Lisp 等にある return/return-from の機能は、もっと >原始的な感じで、むしろ C の setjmp/longjmp に近いレベルに >なります。たとえば、break にラベル指定ができるとすると、 >(Lisp 風じゃなくて crowbar 風に書くと) こういう感じになる >と思います。 … >for (;;) { > toplevel: { > exit_to_toplevel = closure() { break toplevel; }; > command = キー入力; > do_it(command); > } >} breakの機能自体は、同じものを想定していると思っています。 >上のように書くにしても、ユーザーが明示的に closure を変数に >セーブするのではなく、closure は catch & throw マクロに >付随する連想リストの中に隠されて、ユーザの目には見えなくなります。 crowbarで上記try関数を書くとして、もしローカル変数がダイナミックスコープに なっていれば、throwのクロージャを引数で渡さなくてよさそうなんですが、 ダイナミックスコープは混乱しそうなので付ける気はないわけでして、 Lispはレキシカルスコープでもクロージャの受け渡しができるわけでしょうか。 Lispのマクロは、「コードを示すリストをプログラムからいじること」という レベルでしか理解していないです。throwに相当するシンボルをさくっと 置き換えればよいのかな。
[この投稿を含むスレッドを表示] [この投稿を削除]
[443] Re:クラスメソッドとクラス変数
投稿者:kit
2007/02/20 02:13:25

> こういうtry関数をライブラリで用意することで、アプリケーション側では > こう書けるのかなあ、と。 ははあ、なるほど。 Java や C++ の例外の場合、例外の受け手は直接指定せず、受け手が 存在しない場合はトップレベルまで伝搬するわけですが、こういう風に 書くと、それとはだいぶ意味的に違うものになりそうです。 Java や C++ の例外処理機構と意味的に同じものは、ラベル指定の break 機能と、Lisp で言う unwind-protect (Java の finally) があり、処理系 側がトップレベルで break に使うラベルを何か定義してくれれば、 一応ライブラリレベルで、実装はできるとは思います。 ただ、その場合、例外の種類を表すものはグローバル変数 (あるいは スレッドローカル変数) で保持することになり、また、例外の伝搬を 実装するために、クロージャのリストも管理することになるんじゃ ないかな… 例外の catch は、finally 節内で、例外の種類を保持する グローバル変数を参照するだけで、できそうです。 でも Lisp みたいなマクロがないと、文法的に結構面倒くさそうなので、 言語レベルで定義しちゃった方が、むしろ好ましいかもしれませんね。 > Lispはレキシカルスコープでもクロージャの受け渡しができるわけでしょうか。 > Lispのマクロは、「コードを示すリストをプログラムからいじること」という > レベルでしか理解していないです。throwに相当するシンボルをさくっと > 置き換えればよいのかな。 catch & throw は、throw する先を表すキーとしてシンボルを 使うわけですが、このキーとクロージャの対応を管理する連想 リストは、関数呼びだしのネストに従って、スタック式に管理 します。この連想リストは、言語が提供するものではなく、 ライブラリが内部的に管理する単なるデータ構造に過ぎないので、 レキシカルスコープとは関係ないわけです。
[この投稿を含むスレッドを表示] [この投稿を削除]
[445] Re:クラスメソッドとクラス変数
投稿者:(ぱ)
2007/02/20 02:13:25

>Java や C++ の例外の場合、例外の受け手は直接指定せず、受け手が >存在しない場合はトップレベルまで伝搬するわけですが、こういう風に >書くと、それとはだいぶ意味的に違うものになりそうです。 う。確かに私の書いたのだと、トップレベルまで伝搬しませんし、 例外の種類に関わらずcatch節に流れ込みますね。 例外の種類に関わらずcatchに流れ込むことについては、 「自分が知らない例外だったらcatch節で投げ直してよ」という方法で いけそうな気がしますが(ていうかクラス階層という概念がないcrowbarでは、 別途例外階層を定義する手段を提供しない限りそうなってしまいそうですが)、 catch節で例外を投げなおしたときには、上位がさらにtryで囲まれていれば そっちのtryのcatch節に流れ込むように思います(というかそう作らなければ 面白くない)。ただ、catch節で例外を投げなおすためには、上位のtry用の クロージャを持っていなければいけないので、何かと面倒そうではあります。 >また、例外の伝搬を >実装するために、クロージャのリストも管理することになるんじゃ >ないかな… こういうことですかね。 >でも Lisp みたいなマクロがないと、文法的に結構面倒くさそうなので、 >言語レベルで定義しちゃった方が、むしろ好ましいかもしれませんね。 ということで言語レベルで定義しようとせこせこ弄り回しているわけですが、 上に書いたように、crowbarにはクラス階層の概念がないので、どうやって catchしたものか考えているところです。 Common Lispの例外処理は、ちょっとぐぐって以下のページを見つけたのですが、 http://www.geocities.jp/m_hiroi/xyzzy_lisp/abclisp16.html やっぱり階層構造を(おそらくライブラリレベルで)実現していますね。 上に書いたような「なんでもcatchに流れ込むから、あとはアプリケーションで 投げ直してくれ」という戦略をとるにせよ、なんらかの方法で識別がつかないと そもそもアプリケーションでも区別がつきませんから、どうしようかと 考えているところです。 (1)例外の種類の区別を、言語レベルで提供するか、ライブラリレベルで提供するか、  規約レベルの話にするか。 (2)例外の種類別catchを、言語レベルで提供するか、アプリケーションで  判断してもらうか。 Javaのように、catchを例外の種類ごとに書く方法だと、OR条件(この例外と この例外の時にはこうする)のようなものが書きにくくて、なんとかならんもんかと 常々思っているのですが…
[この投稿を含むスレッドを表示] [この投稿を削除]
[449] Re:クラスメソッドとクラス変数
投稿者:kit
2007/02/20 02:13:25

> (1)例外の種類の区別を、言語レベルで提供するか、ライブラリ >  レベルで提供するか、規約レベルの話にするか。 ゼロ除算や、浮動小数点関係のエラーのような例外は、言語処理系 の側で投げて欲しいので、完全にライブラリレベルだけってわけに はいきませんよね。 利用者側で例外の種類を拡張できないようにするのも不便そうだし、 結局、折衷策にせざるをえないような気がします。 > (2)例外の種類別catchを、言語レベルで提供するか、アプリケー >  ションで判断してもらうか。 > > Javaのように、catchを例外の種類ごとに書く方法だと、OR条件 > (この例外とこの例外の時にはこうする)のようなものが書きにく > くて、なんとかならんもんかと常々思っているのですが… 条件の判断を言語の文法として導入せず、アプリケーション側で 判断してもらう場合、上に伝搬させたい例外の throw を忘れやす そうな気もします。Java に慣れている人だと、finally 節の中 では普通 throw を行わないので、特に危ないかも。 欲しい機能のが OR 条件だけなら、catch の後に例外を羅列でき るような文法にするんですかねえ…
[この投稿を含むスレッドを表示] [この投稿を削除]
[450] Re:クラスメソッドとクラス変数
投稿者:(ぱ)
2007/02/20 02:13:25

>条件の判断を言語の文法として導入せず、アプリケーション側で >判断してもらう場合、上に伝搬させたい例外の throw を忘れやす >そうな気もします。Java に慣れている人だと、finally 節の中 >では普通 throw を行わないので、特に危ないかも。 確かにそうですね。私自身「Java謎+落とし穴~」にそんなことを書いてました。 >欲しい機能のが OR 条件だけなら、catch の後に例外を羅列でき >るような文法にするんですかねえ… ひとまずORがあれば、そのcatch節の中で処理の振り分けはできそうなので (できるように作ればですが)、よさそうな手に思えます。 try {  … } catch (HogeException, PiyoException: ex) {  … } とかですかねえ…
[この投稿を含むスレッドを表示] [この投稿を削除]