- PR -

特集「私がJavaからC#に乗り換えた10の理由」について

投稿者投稿内容
英-Ran
ベテラン
会議室デビュー日: 2002/06/12
投稿数: 55
投稿日時: 2003-07-19 20:41
引用:

yaさんの書き込み (2003-07-19 18:43) より:
>>英-Ranさん
で、今の議論ですが、議論を進めてきて「メソッドオブジェクト」の問題にうつっているようですので、それついて自分の考えを述べたいと思います。



申し訳ないですが、その前に、二つ目の「「C# delegate」、「メソッドオブジェクト」、「無名InnerClass」のそれぞれにおいて「委譲」の主体は何か 」についてyaさんなりの答えを示していただけませんか。

そこが明確にできないと、メソッドオブジェクトに関する議論もわけのわからないことになると個人的には思ってますので。

引用:

C#では実現されていない(というよりもC# delegateでにたような事はできるので十分と私は思いますが)。これについては、いくつか難しいな、と思う点があるので挙げてみたいと思います(「概念」を否定しているのではありません、「組み込むことが難しい」といっているのです)。



やはりyaさんは私が言ったことを正しく認識できてませんね。一番目の答えから導ける結論には「委譲を実現するための機能を比較するのだから、どれを使っても委譲が実現できる」ということでもあるのですよ。また、すでにC#にdelegateがあるから別にいらないというのは、「C# delegate以外を実装する道もあったのではないか」という当初私が主張した議論からはずれていませんか(もしかして、yaさんは違うことを議論してました?)。

引用:

上の方式ならばこの形を持ったメソッドがアセンブリリンク階層ではじめて定義された場所、になりますので、mscorlibあたりになるんでしょうか。
つまり、MyAssembly.dllとMyAssembly2.dllが同じこの形式のMethodでやり取りしようとした場合mscorlibを参照してmscorlibで使用されたクラスのメソッドと同時に暗黙的につくられたMethodの型にしたがってやりとりをする、と。私はこんな方式はいやです(この場合だとすべてのアセンブリのrootのmscorlibに入っている(だろう)から問題ないかもしれませんが、同じ階層に複数あったらどうします?)。
配列との根本的な違いはこの辺ではないでしょうか。



たしかに面白いですね。

とはいえ、CLI作っているのはMicrosoft自身なんだから言語に組み込むこと自体は何の問題もないではないかと思うけれど(それに問題となるのは型検査だけなんだから、Method型はひとつで型検査は別途行えばいいという話もある。C# delegateのような例外を認められるならそれくらいは認めていいんじゃないかと)。

Javaでも、別のクラスローダーからロードされたクラスは別のクラスとして認識されるということがあるので、こういう問題は実装上はよく問題になることがありますね。

# 個人的には興味のある話題なのでちょっと考えてみます

引用:

結局暗黙的なメソッドオブジェクトの型定義だとこのように、結構大変な事になってしまうんです。だから結局「明示的に型定義するほうが望ましい」ってことになります。



実装が難しいかどうかは別として型定義は明示的ですよね(だって、メソッドはきちんと宣言されるわけだし)。

引用:

また、参照のしやすさを考えると名前をもっていてくれるほうがありがたいです。



これに関しては、二番目の回答を聞いてからにしましょう。他の機能との正しい比較をせずして結論を決めるのは早計というものです。

引用:

と、ここまで書いてきて思ったのですが。.NETのStrongly Type SafeはすべてのTypeを「世界にたった一つのType」と定義している点ではまずまずだと思います。これと、メソッドオブジェクトを統合するのは根本的に無理なんじゃないでしょうか。



メソッドオブジェクトを導入すると何処らへんが「世界にたった一つのType」ではなくなるんでしょうか。しかも、C#がStrongly Type Safeではないことは「C# delegate」によって示されているんですが理解してます?

[ メッセージ編集済み 編集者: 英-Ran 編集日時 2003-07-20 00:09 ]
taka
会議室デビュー日: 2002/08/02
投稿数: 16
投稿日時: 2003-07-19 23:16
なんかJAVAの事よくしってる人がいばってる印象ですねー(ちょっとでもまちがうと見下す・・・)もうちょっと大人になれば・・・
nak2k
ベテラン
会議室デビュー日: 2003/07/17
投稿数: 86
投稿日時: 2003-07-20 00:06
K-NAKです。
微力ながらお二方の技術的議論上の食違いの解決に乗り出して見ます。
(あくまで技術上の部分だけ^^;)

引用:
objectさんの書き込み (2003-07-19 07:39) より:
メソッドは、(d)の形式を経る事によって初めて、C#に於いてより完全な「メソッドオブジェクト」になっていると考えるべきです。



ここの文で「メソッドオブジェクト」という言葉を使ったのは、まずかったと思います。
多くの人がここを読んでデリゲートについて勘違いしたと思います。(おっしゃりたいことは非常に良く分かるのですが^^;)

「メソッドオブジェクト」という言葉を聞いて普通思い浮かべるのは、やはり英-Ran様の言うとおり「メソッドもオブジェクトである」になると思います。(C#で言うところの、System.Reflection.MethodInfoクラス)

ここで、object様の”より完全”について考えて見ますと、何が”より完全”かはやはり”委譲”ということになると思います。”委譲”をより完全にあらわしたもの、つまり「委譲オブジェクト(デリゲートオブジェクト)」。C#のデリゲートがデリゲートと名づけられた所以だと思います。

引用:
英-Ranさんの書き込み (2003-07-19 14:27) より:
Methodオブジェクトの考え方は「メソッドもオブジェクトである」ということです。JavaScriptのFunctionオブジェクトを使ったことのあるかたならある程度想像がつくかと思いますが、


もしかして……とは思ってましたが、やはり「メソッドオブジェクト」という言葉はそのようなもののことを示しておりましたか……。残念ながら「メソッドオブジェクト」だけでは委譲の全ケースを表現することは不可能ですよ。

「メソッドオブジェクト」=「リフレクションのメソッドクラス」でよろしいでしょうか? そうでしたら、英-Ran様の示したコードの中で「Method(void, Object)」の部分を「リフレクションのメソッドクラス」に置き換えてみてください。
C#とJavaでリフレクションに違いがないなら、非常に困った事態に直面することと思います。

引用:
takaさんの書き込み (2003-07-19 23:16) より:
なんかJAVAの事よくしってる人がいばってる印象ですねー(ちょっとでもまちがうと見下す・・・)もうちょっと大人になれば・・・


それを言わないのが大人というものです(そんなこと言う私も、そんなことを言わないのが大人というm……(以下、無限再帰ループスタックオーバーフロー落ち(笑))
英-Ran
ベテラン
会議室デビュー日: 2002/06/12
投稿数: 55
投稿日時: 2003-07-20 00:17
英-Ran@狂信的Java信者です。

引用:

k-nakさんの書き込み (2003-07-20 00:06) より:
ここで、object様の”より完全”について考えて見ますと、何が”より完全”かはやはり”委譲”ということになると思います。”委譲”をより完全にあらわしたもの、つまり「委譲オブジェクト(デリゲートオブジェクト)」。C#のデリゲートがデリゲートと名づけられた所以だと思います。



それがそうじゃないという話が私の話の本筋だったりします……が、納得してもらいえない懸念がだんだん濃厚になりつつあります

引用:

「メソッドオブジェクト」=「リフレクションのメソッドクラス」でよろしいでしょうか? そうでしたら、英-Ran様の示したコードの中で「Method(void, Object)」の部分を「リフレクションのメソッドクラス」に置き換えてみてください。
C#とJavaでリフレクションに違いがないなら、非常に困った事態に直面することと思います。



いえ、イメージとしてはRubyのMethodオブジェクトに型がついたものです。他の言語を見れば委譲の方法としてクロージャやMethodオブジェクトという考え方の方がC#のdelegateよりも一般的な機構だと思います。言語の表街道しか知らないと違和感があるかもしれませんが……

引用:
takaさんの書き込み (2003-07-19 23:16) より:
なんかJAVAの事よくしってる人がいばってる印象ですねー(ちょっとでもまちがうと見下す・・・)もうちょっと大人になれば・・・



まあ、Java信者なんでしょうがないと割り切っていただければ幸い。
nak2k
ベテラン
会議室デビュー日: 2003/07/17
投稿数: 86
投稿日時: 2003-07-20 01:32
引用:

英-Ranさんの書き込み (2003-07-20 00:17) より:
英-Ran@狂信的Java信者です。

引用:

k-nakさんの書き込み (2003-07-20 00:06) より:
ここで、object様の”より完全”について考えて見ますと、何が”より完全”かはやはり”委譲”ということになると思います。”委譲”をより完全にあらわしたもの、つまり「委譲オブジェクト(デリゲートオブジェクト)」。C#のデリゲートがデリゲートと名づけられた所以だと思います。



それがそうじゃないという話が私の話の本筋だったりします……が、納得してもらいえない懸念がだんだん濃厚になりつつあります


まずは、素早いレスありがとうございます。
ただ、技術的な話以外の部分でちょっと思うところある内容でしたので少しだけ……。

私は、英-Ran様が狂信的Java信者であろうとなかろうと、また他の方が英-Ran様のことをそのどちらに感じようとも、ここでの英-Ran様との議論は非常に有意義なものになる、と感じております。

ですので、たしかに私は「Javaの使用経験が浅く、C#を面白い言語だなと感じている(完璧な言語と感じている、ではないですよ?)人間」ではありますが、「言っても納得してもらえないから…」などと諦めたりせずに、今後とも議論に付き合っていただけると嬉しいです。

(第一、すぐにみんながみんな納得したら、議論のしがいがないじゃないですか(笑))

引用:
いえ、イメージとしてはRubyのMethodオブジェクトに型がついたものです。他の言語を見れば委譲の方法としてクロージャやMethodオブジェクトという考え方の方がC#のdelegateよりも一般的な機構だと思います。言語の表街道しか知らないと違和感があるかもしれませんが……



リフレクションのメソッドオブジェクトとは違うわけですね。そうなると私の発言の「置き換えてみてください」はまったく無意味ですね。

うーん…、私、Rubyはやったことないんですよね…。クロージャでしたら、以前とあるC++のテンプレートクラスライブラリで、クロージャテンプレートクラスなるものをみかけたことがあるのですが、それが英-Ran様のおっしゃるクロージャと同じ思想のもとに書かれたものかどうかは正直あやしいですし…(第一、そのクロージャクラス、C#のdelegateに近いものだったんですよ)

とりあえずRubyのMethodオブジェクトについて調べれるだけ調べてみますね。
他にも何か理解の助けになるようなことがありましたら教えていただけると嬉しいです。
ya
大ベテラン
会議室デビュー日: 2002/05/03
投稿数: 212
投稿日時: 2003-07-20 01:54
>>英-Ranさん
先ほどの書き込みですが…あくまで現在議論されていた「メソッドオブジェクト」に関しての話ですので、委譲とはあまり関係ないです(つまりC#ではメソッドオブジェクトが実現できないのではないか、という主張です)。

まずはきかれた事ですね。
「委譲」に関しては結局のところ処理を他者に渡すこと。
C# delegateについてはやはり、リダイレクトするだけのただのオブジェクトだと思います(個人的にはそれによって.NETの型システムにおいても何とかなっていると思います)。だから主体は「特定のクラスメソッドへのアクセス権」だと思います。
「メソッドオブジェクト」についてはメソッド自体をオブジェクトにしてしまう(みなしてしまう)こと。この場合主体はメソッドの属性(戻り値とパラメータ)を取り出したものです。
無名InnerClassについてはこれは渡すものはオブジェクト(InnerClass)ですが、それを共通化しているものはInterfaceです。つまり、主体はメソッド集合そのもの。
全体的に問題なのは「メソッドをどのように共通化するか」だと思いますが(使うときInterface型なのかdelegate(C#)型なのかMethod型なのかの問題)。


引用:

一番目の答えから導ける結論には「委譲を実現するための機能を比較するのだから、どれを使っても委譲が実現できる」ということでもあるのですよ。また、すでにC#にdelegateがあるから別にいらないというのは、「C# delegate以外を実装する道もあったのではないか」という当初私が主張した議論からはずれていませんか(もしかして、yaさんは違うことを議論してました?)。




もとの問題は私が

コード:

x.SampleEvent += new EventHandler(o.Event_Handler);



よりも

コード:

x.SampleEvent += o.Event_Handler;



の方がよいというのを否定しただけなんですけどね。この書き方は明らかにメソッドオブジェクトだととらえられましたので、どちらかといえば私の議論は委譲を実現する、比較する事よりもメソッドオブジェクトの否定、からはいっています(私も議論的にそれている部分がありましたし…)。ひょっとしたら議論自体ずれていたのかもしれません(ただ個人的には委譲については漠然とした理解でしたので他者の意見を聞いて話を合わせたのは非常に有益でしたが)。私がキーワード「delegate」を「C# delegate」、キーワード「委譲」を概念としての委譲として使っていたのもすれ違いの原因かもしれません。

というわけで、「メソッドオブジェクトの難しさ」についてですが…。

引用:

とはいえ、CLRを作っているのはMicrosoft自身なんだから言語に組み込むこと自体は何の問題もないではないかと思うけれど(それに問題となるのは型検査だけなんだから、Method型はひとつで型検査は別途行えばいいという話もある。C# delegateのような例外認められるならそれくらいは認めていいんじゃないかと)。




.NETの場合「型検査」だけではありません(広い意味では型検査ですが)。所属アセンブリを元にそのコードグループから発生するコードアクセスセキュリティもからんできます(だからすべてのコードについてアセンブリが必要ですし型の一意性に関してもこれに依存しているのでアセンブリは絶対に必要です)。とりあえず「アセンブリ(StrongName)が必要なんだ」ということです。

引用:

メソッドオブジェクトを導入すると何処らへんが「世界にたった一つのType」ではなくなるんでしょうか。しかも、C#がStrongly Type Safeではないことは「C# delegate」によって示されているんですが理解してます?




「世界にたった一つのType」ではなくなる、というわけではなくて…。この点において一番の問題は、「Method型の所属アセンブリが決定できない(または非常にわかりにくくなる)」、そして「それではコードグループも決定できない(または非常にわかりにくくなる)」ということです。
解決策としては、ある動的なアセンブリを用意してそこにすべてのMethod型を必要になったら確保する、ということも考えましたが、結局コードグループ判断のときに問題が発生して、へたな設計をしてしまうとセキュリティホールになってしまいますし。


ちなみに、Method型を一つにしてパラメータや戻り値の違いはすべてインスタンスとして吸収させる、という手も思いつきましたが、これだとコンパイル時型判断が難しいかな、と思いました。
nak2k
ベテラン
会議室デビュー日: 2003/07/17
投稿数: 86
投稿日時: 2003-07-20 04:14
ここらで少しコーヒーブレイク
JavaScriptでC#のDelegateに近いことをやってみました。
(Windows環境であれば、下記のコードをテキストファイルで保存して、拡張子を.jsにすれば動作を確認できます)

コード:
function Delegate(aObj, aMethod) {
  this.Target = aObj;
  this.Method = aMethod;
  this.DynamicInvoke = function() {
    var t = this.Target;
    var old = t.__tmp;
    t.__tmp = this.Method;
    t.__tmp();
    t.__tmp = old;
  }
}

function ClassA() {
  this.aMessage = "JavaScript Delegate Sample";
  this.Show = function() {
    // ブラウザで試す時はalertに変更
    WScript.Echo(this.aMessage);
  }
}

function ClassB() {
  this.aDelegate = null;
  this.Show = function() {
    this.aDelegate.DynamicInvoke();
  }
}

var instanceA = new ClassA();
var instanceB = new ClassB();

instanceB.aDelegate = new Delegate(instanceA, instanceA.Show);
instanceB.Show();



Delegateのメンバ Target, Method, DynamicInvoke はDotNETのDelegateクラスにあわせてみました。

上記のコードではinstanceBは、デリゲートインスタンスについては知ってますが、instanceAの存在やinstanceAのメソッドの存在は知りません。でも、Showの処理を、instanceAのShowメソッドに任せることができています。(ClassAの、と言ってないことにご注意を)

デリゲートインスタンスを介さず、instanceA.ShowだけをinstanceBに渡すのはまずいです。「WScript.Echo(this.aMessage);」の部分で、thisがinstanceAであることを確定できなくなるからです。

ここで注意したいのはデリゲートインスタンス生成の文「new Delegate(instanceA, instanceA.Show);」ですね。デリデートインスタンス生成の時には、毎回ターゲットとなるインスタンスの名前(ここではinstanceA)を2回書かなければなりません。
なのでC#のデリゲートでは、このことについてコンパイラが特別な計らいをしてくれていて、instanceA.Show と一回書くだけで2つのパラメータ(インスタンスへの参照とメソッドへの参照)をデリゲートのコンストラクタに渡してくれているようです。
(ILコード確認したわけではありませんが
英-Ran
ベテラン
会議室デビュー日: 2002/06/12
投稿数: 55
投稿日時: 2003-07-20 12:40
引用:

yaさんの書き込み (2003-07-20 01:54) より:
>>英-Ranさん
先ほどの書き込みですが…あくまで現在議論されていた「メソッドオブジェクト」に関しての話ですので、委譲とはあまり関係ないです(つまりC#ではメソッドオブジェクトが実現できないのではないか、という主張です)。



了解です。ただ、「実装できない」から「メソッドオブジェクト」は導入すべきでないと言われるのはちょっとさびしい……。

# .Net Framework版Rubyは作るのかな?

引用:

C# delegateについてはやはり、リダイレクトするだけのただのオブジェクトだと思います(個人的にはそれによって.NETの型システムにおいても何とかなっていると思います)。



yaさんと私のすれ違いはここから始まっているのです。「委譲」の主体は処理の受け渡しをするものです。ですから、

無名Inner Class:ただの内部クラスのオブジェクト
メソッドオブジェクト:Method クラスのオブジェクト

です。では、C#のdelegateはなんでしょう。答えは、きちんとMicrosoftのドキュメントには書いていますが、

C# delegate:メソッド参照

です。C# delegateというものが実際には「bound method reference」とよばれる技術であることからもこれは明白です。yaさんはC# delegateの良さをいろいろと語ってくれましたが、書いていて「オブジェクトなら当たり前のこと」ばかり書いていたことに気付きませんでした?

# C# delegateという名称が誤解を招くという話が以下のスレッドで書かれています。
# http://java-house.jp/ml/archive/j-h-b/019913.html#body

なぜ、C# delegeteにはdelegateオブジェクトのようなラッピングを必要とするのか。
それはC# delegateの本質がメソッド参照(悪く言えば関数ポインタ)だからです。C#はメソッドをfirst class objectとして持たないオブジェクト指向言語ですから、メソッド参照という概念は本来存在し得ないものです。また、指し示す先が何者かわからない参照では型の検査もしようがありませんし、変数に格納することもできません。

だからこそ、メソッド参照をラッピングし謎の型検査もし無理やりfirst class objectというレベルにまで持ち込まなければC#の中には概念として扱うことができないのです。

では、他のメソッドオブジェクトや無名InnerClassはどうかというと、これらはそもそもオブジェクトです。オブジェクトということはオブジェクトが持つべき特性は当たり前のように備えています。

yaさんは以前「イベントを定義するのはカプセル化されたあるクラスなので、ほかのクラスとは独立性が高くあるべきです」とおっしゃっておられましたが、メソッドオブジェクトはfirst class objectです。だったら通常のオブジェクトでそうするように遠くに運びたいときは自分でラッピングするクラスを作ってやればいいだけの話です(ついでに他の情報だってつけてもいいし、新しいメソッドだって定義できる)。

無名InnerClassに至っては名前がないだけの単なる内部クラスですから、特に疑問を感じることもないでしょう(無名InnerClassが安全でないと主張するなら、すべてのクラスが安全でないといっているのと同義ですから)。また、無名InnerClassは、継承先のクラス名がないだけで型の名前はきちんと存在するわけですし。

これが、私なりの見解です。反論があればもちろんお受けします。

[ メッセージ編集済み 編集者: 英-Ran 編集日時 2003-07-20 12:41 ]

スキルアップ/キャリアアップ(JOB@IT)