- PR -

神は無駄をしたもうか?

投稿者投稿内容
t-wata
大ベテラン
会議室デビュー日: 2002/07/12
投稿数: 209
お住まい・勤務地: 東京
投稿日時: 2002-12-26 01:06
よく考えたら、上の例だと、Aをふつうのクラスにして、extends した場合との違いが分からないですね。

-----A.java---------
public interface A extends B,C{}
interface B extends D{}
interface C{}
interface D extends E,F{}
interface E {}
interface F {void amethod();}
のように無駄に複雑にしておくとよいですかね。
この状態では、
A a = new Test();
B b = new Test();
D d = new Test();
F f = new Test();
とした場合、いずれもamehtodを実行できますが、void amethod();
をべつのInterfaceに移動すると、実行できるインスタンスとできない
インスタンスがでてきます。この様に多重継承の可能なInterfaceでは、
単一継承しかないクラスにくらべ、かなり複雑になると思います。

Interfaceのメソッドを実行するためには、Interfaceおよび、そのスーパー
インターフェイス達のどれかが、メソッドを定義している、かつ、そのメソッド
をクラスまたはそのスーパークラスが実装している必要があり、なので、
invokevirtualとinvokeinterfaceを分けたと思うのです。
(invokevirtualはinvokeinterfaceにくらべずっとシンプルに実装されていると思います)
実際にはconstant poolまで分けてますね。
yu
ベテラン
会議室デビュー日: 2002/09/29
投稿数: 58
お住まい・勤務地: 東京
投稿日時: 2002-12-26 01:29
以下の書き込み、t-wata さんが前の書き込みを書き終える前に書き始めたため、
内容が重複しています。でも、返事としておかしくないので、そのまま保存します。

-----------------------------------------------------------

t-wata さん、レスありがとうございます。

別な表現方法をすると、
Test からの関数呼び出しは、
invokeinterface A.amethod()V
をしているということですよね。

これは、A.amethod()V が実在しているかチェックしているときに、リンク例外が
発生しています。

でも、これって、A が interface でなく、クラスでも同じだと思います。

-----A.java---------
public class A{
void amethod() {}
}
-----Test.java------
public class Test extends A{
public void amethod() {}
public static void main(String[] args){
A a = new Test();
a.amethod();
}
}

とやると、
invokevirtual A.amethod()V
になりますが、同じように、
Exception in thread "main" java.lang.NoSuchMethodError: A.amethod()V
が発生します。

3つ目のパターンとして、

-----A1.java---------
public interface A1 {
void amethod();
}
-----A2.java---------
public interface A2 {}
-----A.java---------
public interface A extends A1, A2 {}
-----Test.java------
public class Test implements A{
public void amethod() {}
public static void main(String[] args){
A a = new Test();
a.amethod();
}
}

として、A1 の amethod() を消すというのも考えられるのですが、
結局、

-----A1.java---------
public interface A1 {
void amethod();
}
-----A2.java---------
public interface A2 {}
-----A.java---------
public abstract class A implements A1, A2 {}
-----Test.java------
public class Test extends A{
public void amethod() {}
public static void main(String[] args){
A a = new Test();
a.amethod();
}
}

のパターンがありえるので、やることは一緒だと思います。
4つ目は、
invokevirtual A.amethod()V
にちゃんとなることを確認しました。

以上、一緒だと、僕は思うのですが...


[ メッセージ編集済み 編集者: yu 編集日時 2002-12-26 01:54 ]
t-wata
大ベテラン
会議室デビュー日: 2002/07/12
投稿数: 209
お住まい・勤務地: 東京
投稿日時: 2002-12-26 12:43
abstractクラスのabstractメソッドもinvokevirtualになるのを見落としてました。
なので私の発言は意味が無いので、忘れて下さい。

ちなみに、yuさんと同じようなことを言ってる人もいますね。
http://www.dina.dk/~pmb/jvm-suggestions.html
参考まで。
NothingButXMLInfoSet
大ベテラン
会議室デビュー日: 2002/07/16
投稿数: 116
投稿日時: 2002-12-26 14:15
#以下、あくまでも参考情報を示しているだけです。攻撃的な意図はまったくないことをご理解ください。

yuさんの疑問の解決になるのかどうかわかりませんが、.NET FrameworkのCLRではメソッド呼び出し命令はほぼ2つ(正確には3つ)しかありません。アーリーバウンドのcallとレイトバウンドのcallvirtです(もう1つはcalli)。C#コンパイラの実装ではvirtualメソッドをcallで呼ぶケースもあるので、クラスの定義と命令の対応付けは純粋にコードの意味に依存するといっていいと思います。もっとも私自身はコンパイラを書いたことはありませんので、それがどんな意味を持つのかよくわかっていないのですけど。

JVMとCLRのVMとして比較した資料がいくつかあったので参考までに。もちろん.NET寄りにバイアスかかってますので、割り引いてください。

A Technical Overview of the Commmon Language Infrastructure
Stacking them up: a Comparison of Virtual Machines
未記入
ぬし
会議室デビュー日: 2002/03/28
投稿数: 255
投稿日時: 2002-12-26 15:30
#私が根本的に間違ってないこと限りは次の通りでよいはず.
>僕の理解では、method signature を入手する方法も、
>入手した後の処理も、invokevirtual でも、invokeinterface でも
>差がないと思うのですが、前後のどちらに差が出るのでしょうか?

どっちかというと入手した後の処理,でしょう.

invokevirtualでは,constantpool resolutionの後は実装レベルでは
ポインタへの定数加算程度の処理になります.invokeinterfaceは
そう簡単ではなく,すくなくとも単純な実装では条件分岐を外す
ことはできません.
#参考文献:
#http://www.amazon.co.jp/exec/obidos/ASIN/4254121393/qid%3D1040883814/250-1143225-1041069

>ちなみに、yuさんと同じようなことを言ってる人もいますね。
>http://www.dina.dk/~pmb/jvm-suggestions.html
>参考まで。
#良くも悪くも本当に同レベルだと思う.命令セットを含むVMの設計は様々な
#トレードオフのオンパレード.その全てのバランスを取るのが重要.上の例
#ではその一部しか見ていない.第一,あの程度ではいずれも致命的な欠陥では
#なく,これらの「改良」を加えても,全体のパフォーマンスや開発効率には
#さほど影響しないだろうし.
##Windowsのレジストリやショートファイルネーム等の持つ欠陥に比べたら
##可愛いもんです.
yu
ベテラン
会議室デビュー日: 2002/09/29
投稿数: 58
お住まい・勤務地: 東京
投稿日時: 2002-12-26 16:21
皆様、どうもありがとうございます。
こんなにレスが続くとは思いませんでした。
参考資料いろいろありがとうございます。

改めて書かせていただきますと、僕自身は Sun がクラスファイルの構造を変えるべきだ
と言う気は毛頭ありません。

引用:

invokeinterfaceはそう簡単ではなく,
すくなくとも単純な実装では条件分岐を外すことはできません.


invokevirtual と invokeinterface をまとめて実装してしまったことが、
本当に正しいのか、不安なので、ぜひ教えていただけないでしょうか。

何の「条件分岐」が必要なのでしょうか?
僕は invokevirtual 同様、synchronized 関数かチェックするための
条件分岐の前までは条件分岐が存在しないです。

ぜひ教えてください。お願いします。

引用:

JVMとCLRのVMとして比較した資料 ...


.NET は Java を研究しあげて作っていますから、
まぁ、Java よりひどいということはないでしょう。

マイクロソフトが手を出したということは、オブジェクト指向も
そろそろ成長はおしまいではないでしょうか。

次は、より分散環境(ユビキタスなど)に適した新しい言語が
伸びるんでしょうかね。
未記入
ぬし
会議室デビュー日: 2002/03/28
投稿数: 255
投稿日時: 2002-12-27 11:49
>invokevirtual と invokeinterface をまとめて実装してしまったことが、
>本当に正しいのか、不安なので、ぜひ教えていただけないでしょうか。
うーん.これで分からないということは,多分説明するのはかなり
手間がかかると思います.次のページとかを参考にしてはいかがでしょうか.
http://www.netgene.co.jp/java/docs/javaPressVol17.html#5.3

>何の「条件分岐」が必要なのでしょうか?
メソッドディスパッチに必要な「インスタンスのクラス(動的なクラス/型)」
の判定です.

静的な型だけでは実行時の動的な型が判定できず,そのままではメソッド
呼出し毎に毎回instanceofに相当する処理が必要になります.が,そんな
真似をしているとパフォーマンスが出ませんからね.通常はもっと静的に
(コンパイル時ではないので「半静的に」という感じ)実行するメソッドを
判定します.

もちろん,これは実装依存の話なので,必ずこうする必要がある物では
ありません.もっと効率の良い方法があれば,そちらを採用すべきでしょう.

>>JVMとCLRのVMとして比較した資料 ...
>.NET は Java を研究しあげて作っていますから、
>まぁ、Java よりひどいということはないでしょう。
それはどうでしょうか.

Windowsだってマッキントッシュを分析して出していると思いますが,
インターフェースの出来についてはやはりマッキントッシュの方が
優れているようです.
#詳細は面倒なんで,詳しく知りたい方は「ヒューメインインター
#フェース」等を参照して下さい.

NT(のちのWindowsNT)にしてもUNIXに対抗して開発したものの,中途半端に
Windows互換に路線変更したために安定性やセキュリティに問題の多いもの
になっています.

>>.NET FrameworkのCLRではメソッド呼び出し命令はほぼ2つ(正確には3つ)
>>しかありません。アーリーバウンドのcallとレイトバウンドのcallvirtです
>>(もう1つはcalli)。
たとえば,VC++.NETがどの程度C++であるかは把握してませんが,なまじC++と
言っているくらいだから,ひょっとして多重継承をサポートしていたりは
しませんか?
#そうでなければ,「C++」という看板に偽り有り.まあいつものことだけど.

これらの命令がJavaVMのバイトコードのどれに相当するのか良く分かりませんが,
callがinvokestatic,callvirtがinvokeinterfaceかinvokevirtualに相当する
ものだと思います.(callvirtが多重継承もサポートするならinvokeinterfaceで,
単一継承専用ならinvokevirtual相当と思う.)
#calliは一体なんでしょう?

もし多重継承を基本にしているとすれば,パフォーマンス的に.NET版VMは
JavaVMより不利になります.逆に単一継承専用だと多重継承は全くサポート
できないので「様々な言語のサポート」を最大の売りにしている.NETとしては
問題が多いでしょう.
#ちなみに,JavaVMもかならずしもJava言語専用ではない.多言語プログラミング
#なんてのをやる人がほとんどいないだけで.ネイティブメソッド(.NET用語では
#多分「アンマネージドコード」)については,いずれにせよVM上で実行する
#メリットがほとんど無い.

まあ,これはほんの一例ですがVMの設計は全体のバランスが大切です.
「何でもできる」を売りにしてVMを設計しても,必ずしもJavaVMより
優れた設計になるとは限らない,とは言えると思います.

CPUの命令セットなんかもそうですね.なんでもかんでも詰め込むCISCは肥大化
して性能を上げるのが難しい.その後は命令セットは実装のことも考慮して
決めるのが主流になってます.X86が未だCISC命令をサポートしつづけているのは
Windowsのレガシーコードを動かすためであって,パフォーマンスやコスト的には
大きな負担になっているはずです.

>マイクロソフトが手を出したということは、オブジェクト指向も
>そろそろ成長はおしまいではないでしょうか。
C++も「一応」OO言語ということなんで,MSがOOに手を出してから意外に
経ってますよ.ただ,Windowsプログラマーの多くはVBプログラマーで,
少数派のVC++ユーザーについても,その大半がOOPをやってないだろうという
だけで....
tasuku
常連さん
会議室デビュー日: 2001/08/11
投稿数: 28
投稿日時: 2002-12-27 12:49
引用:


マイクロソフトが手を出したということは、オブジェクト指向も
そろそろ成長はおしまいではないでしょうか。




COM自体がオブジェクト指向の産物なのですから、Microsoftの
OO度は、実際には非常に高いです。

MFCにしても、当時の開発者事情を考慮してOO度を下げた可能性が高いです。
(商業的に見ればいつの時代も、少数の精鋭を相手にするより
 大多数の愚か者を相手にした方が儲かるんです。
 使いこなすユーザーの数が増えてナンボのものですから...。
 Microsoftは、それを実践しているだけであって
 そこを勘違いすると痛い目に合いますよ。)

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