アカウント名:
パスワード:
これってC++で言うところのTemplateと同じものと考えてOK? それとも違う?
つまり、コンパイラが吐き出す内部コードの違いだけで、使い方としては同じ、 と考えてオーケー?
Javaでは、この意味でのコード共有は、generic typeがお出ましするまでも無く当初から可能でしたしJDKのAPIの一部に入ってました(java.util.Vector,HashTable、コレクションAPIのこと)。
JavaでC++のtemplateのようなものなしになぜこれが可能だったのかというと、Javaの多くのクラスがObjectを根として持つ大きな階層構造をなしているため、Objectを扱えるStackを1つ定義してあれば、Objectのサブクラスの要素すべてを扱えるからです。(C++はクラス階層に統一的な「根」となるクラスが無いし、あとポインタで扱えない・扱いたくない「値オブジェクト」の問題があったからこうはできなかった。このことにはC++にはGCがない、という根が深い問題とも絡んでいます)
しかしJavaのこの方法でも問題があって、いったんObjectを経由するがために、型チェックが動的にしか行えないわけです。配列でたとえると、Stringの配列を使うときには、String[]を使えばいいのにObject[]を使わなければならない、ということです。Object[]だから要素にMyClassの要素を入れることもできちゃうし、それがわかるのは取り出し時のキャスト時です。これは不便な話ですが、generic typeが無い今までは実際にこんなへんなことを強要されていた。これを、コレクションAPI使用時に、配列と同じように、代入時に、しかもコンパイル時にチェックできるようにしようというのがgeneric typeです。 コレクションクラスはもとはSmalltalk由来で、 Smalltalkとかだったら、こんなもんは実行時でOKな話ですが、Javaという静的に型づけする言語にコレクションを持ち込んでしまうと、不自然になるのでそれなりに合わせたとゆうわけです。
templateじゃなくてgeneric typeを使った際の利点はなんでしょうか?
下の方に投稿したこの記事 [srad.jp]に関連ポインタを書いときましたので参考にしてください。
もともとC++のテンプレートはgeneric typeに相当するものを速度を犠牲にすることなく実装しようとして考え出されたものでしょう?generic typeとかtype polymorphismとかの話は関数型言語の世界では古くからあって、C++もそれを取り込みたかったわけ。でも速度は犠牲にしたくなかったから、テンプレートでマクロ展開っていう方向性になって、使い勝手は悪くなった。一方、JavaはSMLなどの関数型言語も十分考慮されて設計されたけれど、取りこぼしもあって、それを今やろうとしているだけだと思う。
だから言
もともとC++のテンプレートはgeneric typeに相当するものを速度を犠牲にすることなく実装しようとして考え出されたものでしょう?
C++にコレクション(コンテナクラス)機能を追加する際に、Smalltalk流にObjectを経由した抽象操作でやる、という選択肢は確かにありました。
これは実際にTools.h++で使われている方式(Smalltalk_likeコレクション) [s34.co.jp]です(オプションですけどね)。 このような方式がC++の標準ライブラリに採用され得なかった理由は、効率のこともあるけど、第一義にはそうするとC++じゃなくなるからです。 上のTools.h++のコンテナにはRWCollectableを継承したオブジェクトしか入れられませんし、かつそれはヒープから確保したものである必要があります(厳密にはそうじゃなくても入れられるけどremoveできなくなる^_^)。つまりスタック上のオブジェクトや静的・大域オブジェクト、あるいは何かの演算の結果得られる一時オブジェクトを実質的に使えないということです。
こんなことでC++と呼べるんでしょうか! GCがあれば、格納できるオブジェクトの記憶クラス制約の問題は解決するでしょうが、それもひとつのもっとC++ではない道です。
ポインタでオブジェクトをハンドルするのではなく、コピーコンストラクタを定義した値オブジェクトを自在に駆使することがC++の真髄です(と「Effective C++」に書いてあるし好き嫌いは別としてそのとおりだと思う)。
つまりC++には値オブジェクトをコンテナに値で格納したい、という強い願いがあるわけです。これにC++が固執しているセントラルドグマ「ユーザ定義クラスをintもdouble などの基本型と同様に扱える」ということと考え合わせると、コンパイル時に展開するしかなくなる。なぜなら値オブジェクトを格納するコンテナへの要素の格納は、intの場合変数の代入(bitwise copy)であるし、キャスト演算が生じるかもしれないし、コピーコンストラクタの呼び出しが起きるかもしれない。 それを実行時に切り分けるわけには効率上いかないのです。(ただ逆にこうしたことで多相性は犠牲になるしスプライシングの問題も生じます。純粋オブジェクト指向信望者にとっては許しがたい悪業ざんまい..。)
まあ追求すると速度の問題じゃん、ということなんだけど、 そこにまで到達する前の段階でC++のアイデンティティの問題に基づく、不可避の必然がある、と。これを抜かしちゃ話にならない。
SML/NJやHaskellを使った上での感想として言えば
JavaはSMLなどの関数型言語も十分考慮されて設計されたけれど、取りこぼしもあって、それを今やろうとしているだけだと思う。
「実行時エラー検査がコンパイル時に移っただけ」という表現が元コメントにあるけれど、それにこそ強い型付け存在意義があるわけで、「だけ」というのはかなり語弊があると思う。
「痛くない注射針を作れる金型技術を持ってるのは世界で岡野工業株式会社だけ」
チェックがコンパイル時に前倒しにできるようになった、というただそれだけの話。
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
「毎々お世話になっております。仕様書を頂きたく。」「拝承」 -- ある会社の日常
generic type (スコア:0)
これってC++で言うところのTemplateと同じものと考えてOK?
それとも違う?教えて、エライ人。
Re:generic type (スコア:1, 参考になる)
C++のテンプレートってのは「型紙」で、パラメータを与えることでコンパイル時にコードを展開(インスタンス化)する。別の型をパラメータに与えて使う場合はその型用のコードがインスタンス化される。基本的には文字列操作(マクロ展開)のようなイメージ。
Javaのgeneric typeは、パラメータ型ごとにインスタンス化されるわけではない。生成されるコードは1つだけ。 生成されるバイトコードで実行時に型チェックをするコードが含められたりするわけではないので、generic typeを使って書かれたソースコードからコンパイルされたバイトコードは従来のJVMでも実行することができる。 コンパイル時の型チェックができるようになるというだけ。この種の型チェックは、もしgeneric typeがなかったら、実行時にコレクションから要素を取り出すときのキャスト演算でしていたことなので、そのチェックがコンパイル時に前倒しにできるようになった、というただそれだけの話。
はっきりいって、C++のテンプレートとくらべると、Javaのgeneric typeは「ど単純」で複雑さの度合い、理解しなければならないことの量、そして機能差からいって別物と理解するべきでしょう。
Re:generic type (スコア:1)
>コンパイル時の型チェックができるようになるというだけ。
.classファイルには情報は反映されない、ということなのですよね?
だとすると、あるクラスのソースがある状況と、ソースが無くて.classしかない状況とでは、
そのクラスを使う別のクラスのコンパイルが通るかどうかが違ってきてしまう、
ということが起こり得るんでしょかね?
Re:generic type (スコア:1)
いえ、.classファイルには、専用の情報が追加されるようですよ。
ただ、実行時には参照しない(新コンパイラ用の)情報なので、旧環境での実行に差し障りは無いとの説明だったと記憶しています。
(今、手元にソースが無いので、ちょっと自信なし)
--- Melloques Les Covdrasey ---
Re:generic type (スコア:0)
と考えてオーケー?
templateじゃなくてgeneric typeを使った際の利点はなんでしょうか?
#スマン、オイラバカなんで。もう少しわかりやすく説明して頂けると・・・。
Re:generic type (スコア:3, 参考になる)
このようなあつかう型の違いをパラメータとして切り出せるようにしたのがtemplate。コード共有の話です。
Javaでは、この意味でのコード共有は、generic typeがお出ましするまでも無く当初から可能でしたしJDKのAPIの一部に入ってました(java.util.Vector,HashTable、コレクションAPIのこと)。
JavaでC++のtemplateのようなものなしになぜこれが可能だったのかというと、Javaの多くのクラスがObjectを根として持つ大きな階層構造をなしているため、Objectを扱えるStackを1つ定義してあれば、Objectのサブクラスの要素すべてを扱えるからです。(C++はクラス階層に統一的な「根」となるクラスが無いし、あとポインタで扱えない・扱いたくない「値オブジェクト」の問題があったからこうはできなかった。このことにはC++にはGCがない、という根が深い問題とも絡んでいます)
しかしJavaのこの方法でも問題があって、いったんObjectを経由するがために、型チェックが動的にしか行えないわけです。配列でたとえると、Stringの配列を使うときには、String[]を使えばいいのにObject[]を使わなければならない、ということです。Object[]だから要素にMyClassの要素を入れることもできちゃうし、それがわかるのは取り出し時のキャスト時です。これは不便な話ですが、generic typeが無い今までは実際にこんなへんなことを強要されていた。これを、コレクションAPI使用時に、配列と同じように、代入時に、しかもコンパイル時にチェックできるようにしようというのがgeneric typeです。
直接比較できないですね。比較するんだったら、templateと「JavaのコレクションAPI+generic type」という構図になるかな? でも、言語が違うからやっぱり直接比較にならない。ただ、templateはC++に合うように、generic typeはJavaに合うようにそれぞれ良く考えられてはいる、とは言えると思われます。コレクションクラスはもとはSmalltalk由来で、 Smalltalkとかだったら、こんなもんは実行時でOKな話ですが、Javaという静的に型づけする言語にコレクションを持ち込んでしまうと、不自然になるのでそれなりに合わせたとゆうわけです。
Re:generic type (スコア:0)
Re:generic type (スコア:1, 参考になる)
List list = new ArrayList();
String text = (String) list.get(i);
がgeneric typeの導入によって
List<String> list = new ArrayList<String>();
String text = list.get(i);
になる。この場合のメリットは
あと<>(本当は半角)の中も合わせて型チェックされることになるのでキャストは厳しくなる。
List list1 = new ArrayList();
List<String> list2 = (List<String>) list1;
はだめ、
List<Object> list1 = new ArrayList<Object>();
List<String> list2 = (List<String>) list1;
はOK。
Re:generic type (スコア:0)
> List<String> list2 = (List<String>) list1;
> はOK。
ダウト(Object と String を入れ替えても)
Re:generic type (スコア:1)
下の方に投稿したこの記事 [srad.jp]に関連ポインタを書いときましたので参考にしてください。
Re:generic type (スコア:0)
たとえば
template <type t> class foo : public t {
public:
int bar() {
return t_method1() + t_method2();
}
};
のように親クラスとして使ったり、
template <type t> class foo {
};
template class foo<short> {
};
template class foo<long> {
};
のように型によって厳密化させて別定義することもできます。
だ
Re:generic type (スコア:0)
Re:generic type (スコア:0)
確かに、不自然な型キャストがグッと減って便利ですね。
#いや、また陣営が違うとおんなじ(またはほとんど同じ概念)ことを何故か
違う言葉で言い表す例のアレか・・・と思ったもので。スマソ。
Re:generic type (スコア:0)
もともとC++のテンプレートはgeneric typeに相当するものを速度を犠牲にすることなく実装しようとして考え出されたものでしょう?generic typeとかtype polymorphismとかの話は関数型言語の世界では古くからあって、C++もそれを取り込みたかったわけ。でも速度は犠牲にしたくなかったから、テンプレートでマクロ展開っていう方向性になって、使い勝手は悪くなった。一方、JavaはSMLなどの関数型言語も十分考慮されて設計されたけれど、取りこぼしもあって、それを今やろうとしているだけだと思う。
だから言
Re:generic type (スコア:1)
C++にコレクション(コンテナクラス)機能を追加する際に、Smalltalk流にObjectを経由した抽象操作でやる、という選択肢は確かにありました。
これは実際にTools.h++で使われている方式(Smalltalk_likeコレクション) [s34.co.jp]です(オプションですけどね)。
このような方式がC++の標準ライブラリに採用され得なかった理由は、効率のこともあるけど、第一義にはそうするとC++じゃなくなるからです。 上のTools.h++のコンテナにはRWCollectableを継承したオブジェクトしか入れられませんし、かつそれはヒープから確保したものである必要があります(厳密にはそうじゃなくても入れられるけどremoveできなくなる^_^)。つまりスタック上のオブジェクトや静的・大域オブジェクト、あるいは何かの演算の結果得られる一時オブジェクトを実質的に使えないということです。
こんなことでC++と呼べるんでしょうか!
GCがあれば、格納できるオブジェクトの記憶クラス制約の問題は解決するでしょうが、それもひとつのもっとC++ではない道です。
ポインタでオブジェクトをハンドルするのではなく、コピーコンストラクタを定義した値オブジェクトを自在に駆使することがC++の真髄です(と「Effective C++」に書いてあるし好き嫌いは別としてそのとおりだと思う)。
つまりC++には値オブジェクトをコンテナに値で格納したい、という強い願いがあるわけです。これにC++が固執しているセントラルドグマ「ユーザ定義クラスをintもdouble などの基本型と同様に扱える」ということと考え合わせると、コンパイル時に展開するしかなくなる。なぜなら値オブジェクトを格納するコンテナへの要素の格納は、intの場合変数の代入(bitwise copy)であるし、キャスト演算が生じるかもしれないし、コピーコンストラクタの呼び出しが起きるかもしれない。 それを実行時に切り分けるわけには効率上いかないのです。(ただ逆にこうしたことで多相性は犠牲になるしスプライシングの問題も生じます。純粋オブジェクト指向信望者にとっては許しがたい悪業ざんまい..。)
まあ追求すると速度の問題じゃん、ということなんだけど、 そこにまで到達する前の段階でC++のアイデンティティの問題に基づく、不可避の必然がある、と。これを抜かしちゃ話にならない。
Re:generic type (スコア:1)
>ポインタでオブジェクトをハンドルするのではなく、コピーコンストラクタを定義した値オブジェクトを自在に駆使することがC++の真髄です
(中略)
>純粋オブジェクト指向信望者にとっては許しがたい悪業ざんまい..。)
あはは。ほんとOO信奉者には許し難いです(^^;
OO信者は、同値性と同一性が(プログラマの(笑))任意の時点で自在に使い分けられないと…
つまり同一性をとことん殺さず維持してないと…腹下しちゃいますからねえ。
値Objectなんてな概念には塩まきます。#それが自分の利益を損ねようとも(笑)
ただ、
>C++が固執しているセントラルドグマ「ユーザ定義クラスをintもdouble などの基本型と同様に扱える」
ここでいう「同様」に、やっぱり一抹の疑問を感じるです。
Rubyの短い整数みたいなヤリカタでいいじゃんというか、
intのように「ビット単位で」いじり倒せるってのが本当ならば、なんでVMTポインタをいじらせんのじゃ?とか(藁)、
なんか釈然としない点が一杯。
#問題が問題を呼ぶんで、言語仕様が結局「あの巨大さにならざるを得ない」、ってのは痛い。
そう考えると、少々ヘボくても、モデルがすっきりしてる参照オンリーな言語のほうが、
腹の健康のためには数倍よろしいです。
Re:generic type (スコア:0)
Tigerはいままで「総称性」が「制約付き総称性」になった という話です。
generic typeという名は不適切でSunが悪いんです。 「リフレクション」もそうだし。
Re:generic type (スコア:0)
Re:generic type (スコア:0)
Re:generic type (スコア:1)
「だけ」という限定は、限定しているだけで、価値判断をふくんでません。ここで例題です。
この文章から、岡野工業株式会社を軽く見ていたり、価値がないとか、作れても作れなくても大差ないとか、そんなことが読み取れますでしょうか。
あと、SmallTalkじゃなくて、Smalltalkね。ありがちなミスだけどね。
Re:generic type (スコア:1)
私が(ってACだったのだが) という言い方をしたのは、もと記事の投稿者も、あと他の人も 「C++のテンプレートがJavaに入るの?うげー覚えるの大変、言語が汚くなるー困るー拡大はんたいーはんたいー」というような雰囲気だったから、そうじゃないのだぞと。型制約に基づくコンパイルチェックという(Javaでは)普通のことが普通にできるようになった、ただそれだけのことなんだよ、むしろ今までがおかしかったんだ、とまあそういうことを言いたかったのです。それがうまく伝わらなかったのはぼくにも責任の一端があるってことではありますが。
「型制約があろうがなかろうが、大差ない。そんなのは重要な差ではない」なんていう主張をするつもりは毛頭ありません。私も型制約のある言語の方が好きです(特に業務で使う場合には・特に他人に書かせる場合には、と血の涙を流しながらnot AC)。