+ Javaの弱い参照について
created 2013-09-03 modified 2013-09-03
ふとしたきっかけで、自分のサイトを"Java"で検索したら、私がJavaを論難している日記がたくさんでてきました。自分で読んでちょっと面白かったので、まとめてみました。
(1)Javaの弱い参照
その中から一つ。Javaの弱い参照に関して、2008-04-18 の日記を引用。弱い参照について。
もうさ、そこまでしてGC技術にこだわる理由ってあるのか?
この記事のキモって、参照されてるモノ(記事ではSocket)のライフタイムが終了したことをフックしたいってことでしょ?
でもSocketのデストラクタソースを改造する気力もなし。Socketを使ってるライブラリなりフレームワークの成果をいただいておきながら、面倒に巻き込まれるのはイヤと。
なら、そのSocketを含んでる何らかのライブラリやフレームワークの提供者に、フックを提供してよ、って政治的に動くのがまず前提じゃないかね。で、それもイヤと。
(まぁライブラリ提供者だって、フック提供してよと言われても、イヤだし無理だろう)
ていうかそもそも、GC言語なのに、事実上はC的なポインタが必要になる場面があるってことを、この記事の著者自身が冒頭で言ってるじゃんぬ。それがつまりおいらの感想では、GCパラダイスは破綻してるってことだと思うのだがうーぬ。
さっさとGC技術をあきらめて、非GC言語で「リソース開放漏れを防ぐ設計ノウハウの浸透」に注力してくれないかな。
そのほうが、オレが個人的に幸せになれるという直感があるんだが、根拠不明。
追記:「リソース開放漏れを防ぐ設計ノウハウ」の具体例
(2)オートポインタの類を上手に使う。別に汎用のauto_ptr< >とかじゃなくてもぜんぜんOk。デストラクタでメンバを開放する専用のクラス一個つくればいいだけ。
(1)ならそれはちゃんとドキュメント化すべき。ドキュメントが長大になるなら概要設計がよくない。
(2)マネージャが責任をもつようにつくる。マネージャを含むフレームワークが分かりにくいなら概要設計がよくない。
あれだよね。「Javaには、ポインタが無い」は間違いで、「Javaでは構造体やクラスはポインタでしか使えない」なんだよね。
C#なんか、ポインタやらGCというソフトウェア技術をきちんと理解してないと、きちんとオブジェクトの終了処理を書けないし。何のためのGC?と。
リンク | 備考 |
---|---|
弱参照でメモリー・リークを塞ぐ |
もうさ、そこまでしてGC技術にこだわる理由ってあるのか?
この記事のキモって、参照されてるモノ(記事ではSocket)のライフタイムが終了したことをフックしたいってことでしょ?
でもSocketのデストラクタソースを改造する気力もなし。Socketを使ってるライブラリなりフレームワークの成果をいただいておきながら、面倒に巻き込まれるのはイヤと。
なら、そのSocketを含んでる何らかのライブラリやフレームワークの提供者に、フックを提供してよ、って政治的に動くのがまず前提じゃないかね。で、それもイヤと。
(まぁライブラリ提供者だって、フック提供してよと言われても、イヤだし無理だろう)
ていうかそもそも、GC言語なのに、事実上はC的なポインタが必要になる場面があるってことを、この記事の著者自身が冒頭で言ってるじゃんぬ。それがつまりおいらの感想では、GCパラダイスは破綻してるってことだと思うのだがうーぬ。
さっさとGC技術をあきらめて、非GC言語で「リソース開放漏れを防ぐ設計ノウハウの浸透」に注力してくれないかな。
そのほうが、オレが個人的に幸せになれるという直感があるんだが、根拠不明。
追記:「リソース開放漏れを防ぐ設計ノウハウ」の具体例
動的メモリを使わない
(1)自動変数なら、例外で抜けても言語が責任を持って解放してくれる。極力自動変数を使う(クラスオブジェクトも)。(2)オートポインタの類を上手に使う。別に汎用のauto_ptr< >とかじゃなくてもぜんぜんOk。デストラクタでメンバを開放する専用のクラス一個つくればいいだけ。
大事なものはちゃんと管理しる
オブジェクトの生成、削除がメソッド内に閉じないようなものは、そのソフトウェアの重要な設計項目であるはず。(1)ならそれはちゃんとドキュメント化すべき。ドキュメントが長大になるなら概要設計がよくない。
(2)マネージャが責任をもつようにつくる。マネージャを含むフレームワークが分かりにくいなら概要設計がよくない。
あれだよね。「Javaには、ポインタが無い」は間違いで、「Javaでは構造体やクラスはポインタでしか使えない」なんだよね。
C#なんか、ポインタやらGCというソフトウェア技術をきちんと理解してないと、きちんとオブジェクトの終了処理を書けないし。何のためのGC?と。
(2)Javaスクールの危機
こんなのもありました。Javaスクールの危機 について。2009-02-18 の日記を引用。
リンク | 備考 |
---|---|
Javaスクールの危険 | Joel Spolsky / 青木靖 訳 2005年12月29日木曜 だそうです |
いや、正確に引用すると「Javaは大体において優れたプログラマと凡庸なプログラマを見分けるのに使えるほど難しい言語ではない」です。
私は口が悪いので「Javaしか知らないやつはカス」となるわけだが、これはどうも理解を得にくいようだ。
ややメタな話になるが、私は、「Javaのみプログラマ」を切る判断はすでに確定していて、Javaの罪について話が通るかどうかを、先を見通せるリーダーであるかの判断基準にしている。
ところで、Javaの罪について理解できないひとでも「一昔前のVisualBasicと同じ」というと、何割かは気付いてくれる。そして、VBと同じだと言われなければ気付かない自分についても気付いてくれる、ように見える。
追記 2009/2/19
今はJavaが嫌いですが、過去にはこんなもの(+ アプレット)も作ってました。(3)共通レイヤの賢さ、JavaとDirectX
それからこんなのも。共通レイヤを設けることについて、DirectX は賢かった、Javaは賢くなかった、という話。2009-07-29 の日記を引用。
VisualStudio2008、イケてます。
Windows Presentation Foundation の仕組みを使うと、
C#で
・ボタンやらスライドバーやらを含む画面をパパッと作り
・3Dのモデルとしてキューブを定義し
・スライドバーで回転
なんていうアプリ製作が、いわゆるVBのノリで(GUIのデザイナで画面をつくることができて、ドットキーを押すと補完が働いて、F5押せばすぐ試せて)できました。
こりゃ、2~3年でビジネスアプリも3D化の波に飲まれるよ。昔は「情報可視化」の勉強って、ゲーム屋さんか研究者しかやってなかったけど、業務アプリ屋にも必要になりますぜ、絶対。
必要になるっていうか、こんだけ敷居が下がったらそういうアプリがあふれるよ。
DirectXの開発陣には先見の明があったと思う。その前にも「共通化」とかの考え方はあったと思うけど、要はセンスやタイミングやビジネス設計が悪くて生き残れなかったのでしょう。それを生き残ってこういう形で昇華させたDirectXは、格好いい。
クライアントUI分野はマイクロソフトのひとり勝ちになるだろうなぁ。
これと比較すると、やっぱりJavaはイケてなかったと思う。
7/30 追記:
Javaは、OSのAPIに共通化レイヤを設けようとした。
DirectXは、DOS/V PCの拡張カード(ハード)のAPIに共通化レイヤを設けようとした。
Javaは、さまざまなOSが共通でできるライン(最大公約数=個々のOSができることより低い)を決めた。
DirectXは、さまざまなハードベンダに求めるライン(最小公倍数=個々のカードができることより高い)を決め、ハードでできなければソフトが肩代わりする(でもそれだと遅くて魅力ないよ)、とやった。
Javaが乗るOSのベンダは、Java仕様を満たそうと競争はしなかった(CやC++が速く動くようにすることが、Java対応にもなる。JVMはそれまでのノイマン型コンピュータの域を出ない)。
DirectX対応のハードベンダは、DirectXの仕様(新機能)を満たそうと激しく競争した。結果、淘汰も起こったが、劇的にコストあたりのパフォーマンスがあがった。
私の切り口を一言で言うと「ムーアの法則、それに頼るやつはアホ、それを先導できるひとは賢い」かな。
まず頂点を並べてから、その頂点を使って面を並べるわけですが、デフォルトでは反時計回りの側がオモテになるようで、それで統一しておけばウラ・オモテ指定は不要です。
わかりやすいです。イケてます。
マイクロソフト社って昔はこんなにイケてなかったのに、すごいなぁ。
ただ、面定義は4角形はダメで3角形のみ。まぁこれはこれで良し。
どっちかというと、「4角形もOKです」的な、原理原則に従わず猥雑な仕様だったほうが昔のMSっぽかった気がして、逆の意味での驚きがあります。
Windows Presentation Foundation の仕組みを使うと、
C#で
・ボタンやらスライドバーやらを含む画面をパパッと作り
・3Dのモデルとしてキューブを定義し
・スライドバーで回転
なんていうアプリ製作が、いわゆるVBのノリで(GUIのデザイナで画面をつくることができて、ドットキーを押すと補完が働いて、F5押せばすぐ試せて)できました。
こりゃ、2~3年でビジネスアプリも3D化の波に飲まれるよ。昔は「情報可視化」の勉強って、ゲーム屋さんか研究者しかやってなかったけど、業務アプリ屋にも必要になりますぜ、絶対。
必要になるっていうか、こんだけ敷居が下がったらそういうアプリがあふれるよ。
DirectXの開発陣には先見の明があったと思う。その前にも「共通化」とかの考え方はあったと思うけど、要はセンスやタイミングやビジネス設計が悪くて生き残れなかったのでしょう。それを生き残ってこういう形で昇華させたDirectXは、格好いい。
クライアントUI分野はマイクロソフトのひとり勝ちになるだろうなぁ。
これと比較すると、やっぱりJavaはイケてなかったと思う。
7/30 追記:
Javaは、OSのAPIに共通化レイヤを設けようとした。
DirectXは、DOS/V PCの拡張カード(ハード)のAPIに共通化レイヤを設けようとした。
Javaは、さまざまなOSが共通でできるライン(最大公約数=個々のOSができることより低い)を決めた。
DirectXは、さまざまなハードベンダに求めるライン(最小公倍数=個々のカードができることより高い)を決め、ハードでできなければソフトが肩代わりする(でもそれだと遅くて魅力ないよ)、とやった。
Javaが乗るOSのベンダは、Java仕様を満たそうと競争はしなかった(CやC++が速く動くようにすることが、Java対応にもなる。JVMはそれまでのノイマン型コンピュータの域を出ない)。
DirectX対応のハードベンダは、DirectXの仕様(新機能)を満たそうと激しく競争した。結果、淘汰も起こったが、劇的にコストあたりのパフォーマンスがあがった。
私の切り口を一言で言うと「ムーアの法則、それに頼るやつはアホ、それを先導できるひとは賢い」かな。
追記2
3Dモデルの指定についてまず頂点を並べてから、その頂点を使って面を並べるわけですが、デフォルトでは反時計回りの側がオモテになるようで、それで統一しておけばウラ・オモテ指定は不要です。
わかりやすいです。イケてます。
マイクロソフト社って昔はこんなにイケてなかったのに、すごいなぁ。
ただ、面定義は4角形はダメで3角形のみ。まぁこれはこれで良し。
どっちかというと、「4角形もOKです」的な、原理原則に従わず猥雑な仕様だったほうが昔のMSっぽかった気がして、逆の意味での驚きがあります。
(4)コールバック系
コールバック、デリゲート、リスナーなど、「呼び返す」機能についての記述。2011-02-16 の日記より引用。
Androidにからんで、最近Javaをいじっているが、...
私はやっぱりJava嫌いだ。っていうか苦手だ。私には、Javaの原理主義的なオブジェクト指向は、古いオブジェクト指向時代の「手段と目的の履き違え」を引きずっているように見えてしまう。
時間のかかる処理の完了時の処理をするために、コールバック機構、デリゲート機構を作りたかったんですよ、今日は。
Javaでコールバックしたい場合は、(1)コールバックを分けたい単位でクラスを全部分けてやらないといけないみたい。つまりオブザーバパターン。
さもなくば、(2)リフレクションを使うか。
あるいは、(3)コールバックの呼びクチは1箇所に集約して、switch等で自分で分けるとか。
Javaではコールバックと言わず、デリゲートとも言わず、リスナー(クラス)っていうんだってさ。
Android関係のサンプルコードをみてると、やたら○○リスナーと言ってラムダ関数っていうか無名クラスが出てくるので、妙だな、単体テストしにくいだろ、とおもっていたのだが、デリゲートが使えないと知って少しだけ納得。
(1)のオブザーバパターンっていうのは、GoFのパターンの中でも「使える」パターンの一つで、M-V-VMパターンでも有効に使われてるように【プログラムの依存関係を逆転する(=プログラム変更の際の主従関係を逆転する)】ためのいい考えだとおもっています。
有効な例:これまでの3層レイヤ方式で、ロジックはデータを呼び、またロジックはプレゼンも呼ぶ、だと、一番偉いはずのロジックが、プログラム変更に際してはプレゼンとデータの両方にアタマ下げて従わなければいけない。M-V-VMでは、プレゼンとロジックの呼ぶ・呼ばれる関係を、オブザーバパターンで逆転することで、主従関係を(立場が強いほうから) データ→ロジック→プレゼン の一直線にしたと。
それはナイスな考えなのですよ。とくに、これからはスマートフォン対応などで、ロジックに対してプレゼンがマルチ(複数)になっていくから。
でもコールバックっていうのは、もっと細かい単位で使うもんだろ?と。
しかも、コールバックされた処理の中では結局何をやりたいかと言うと、ユーティリティの利用者側(=コールバックされた側)がガメていた(privateにしたかった)データをいじる訳だ。結果を格納するテキストボックスを更新する、とかね。
で、メソッド分割で作れるデリゲートと比較して、クラスが分かれる方式だと、せっかくのカプセル化を解かないといけなくなる。そうなると、もうどこにメリットがあるのか訳が分からん。
(2)のリフレクションって高価な手法だと思ってるんだが、間違ってますかね?
(3)のswitch文って結局アタマから総当たりでブランチしていくだけなので、非効率なのよね。メソッドポインタが使えればポインタ配列でO(1)でできる話なんだが。
結局、Javaでつくるとクラスが細かくなりすぎて、しかもぼんやりカプセルが開いたクラスが多くなって、「ソフトウェアをシンプルに保って管理しやすくする」「細かいことに目をつぶってザックリ理解しやすくする」というオブジェクト指向の目的からどんどん遠ざかっていく。
なんかいい方法ないのかな。
脱線:
普通、switch文を初めて見たら効率よく検索してるとおもうよね。私も昔そう思った。でも実際はif、else if、とアタマからブランチするように翻訳される。
新しいプログラミング言語の作者はなぜ、switch文を、テーブル検索するように翻訳しないのだろう?
C/C++はそう翻訳せざるを得ないんだけどさ。理由は、breakしないことをゆるしていて、判定する順番、ソースに書いてある順序が意味をもってるから。でも新しい言語はbreakなしを許さず複数のcaseに入ることを許さなければいいのに。
C/C++では関数ポインタ配列を簡単に書けるから、O(n)となることを回避する方法はあるんだが、javaは...
やっぱりJavaはフールプルーフを重視した言語なのだろうか。
まぁね、こういうこと考える事自体が楽しいからいいんだけどさ。
2011/3/9
「嫌いなものじゃなくて好きなもので自分を語れよ」
と、「国際問題をハスに流す萌えキャラ」に言われた気がするので、今後気をつけます。
私はやっぱりJava嫌いだ。っていうか苦手だ。私には、Javaの原理主義的なオブジェクト指向は、古いオブジェクト指向時代の「手段と目的の履き違え」を引きずっているように見えてしまう。
時間のかかる処理の完了時の処理をするために、コールバック機構、デリゲート機構を作りたかったんですよ、今日は。
Javaでコールバックしたい場合は、(1)コールバックを分けたい単位でクラスを全部分けてやらないといけないみたい。つまりオブザーバパターン。
さもなくば、(2)リフレクションを使うか。
あるいは、(3)コールバックの呼びクチは1箇所に集約して、switch等で自分で分けるとか。
Javaではコールバックと言わず、デリゲートとも言わず、リスナー(クラス)っていうんだってさ。
Android関係のサンプルコードをみてると、やたら○○リスナーと言ってラムダ関数っていうか無名クラスが出てくるので、妙だな、単体テストしにくいだろ、とおもっていたのだが、デリゲートが使えないと知って少しだけ納得。
(1)のオブザーバパターンっていうのは、GoFのパターンの中でも「使える」パターンの一つで、M-V-VMパターンでも有効に使われてるように【プログラムの依存関係を逆転する(=プログラム変更の際の主従関係を逆転する)】ためのいい考えだとおもっています。
有効な例:これまでの3層レイヤ方式で、ロジックはデータを呼び、またロジックはプレゼンも呼ぶ、だと、一番偉いはずのロジックが、プログラム変更に際してはプレゼンとデータの両方にアタマ下げて従わなければいけない。M-V-VMでは、プレゼンとロジックの呼ぶ・呼ばれる関係を、オブザーバパターンで逆転することで、主従関係を(立場が強いほうから) データ→ロジック→プレゼン の一直線にしたと。
それはナイスな考えなのですよ。とくに、これからはスマートフォン対応などで、ロジックに対してプレゼンがマルチ(複数)になっていくから。
でもコールバックっていうのは、もっと細かい単位で使うもんだろ?と。
しかも、コールバックされた処理の中では結局何をやりたいかと言うと、ユーティリティの利用者側(=コールバックされた側)がガメていた(privateにしたかった)データをいじる訳だ。結果を格納するテキストボックスを更新する、とかね。
で、メソッド分割で作れるデリゲートと比較して、クラスが分かれる方式だと、せっかくのカプセル化を解かないといけなくなる。そうなると、もうどこにメリットがあるのか訳が分からん。
(2)のリフレクションって高価な手法だと思ってるんだが、間違ってますかね?
(3)のswitch文って結局アタマから総当たりでブランチしていくだけなので、非効率なのよね。メソッドポインタが使えればポインタ配列でO(1)でできる話なんだが。
結局、Javaでつくるとクラスが細かくなりすぎて、しかもぼんやりカプセルが開いたクラスが多くなって、「ソフトウェアをシンプルに保って管理しやすくする」「細かいことに目をつぶってザックリ理解しやすくする」というオブジェクト指向の目的からどんどん遠ざかっていく。
なんかいい方法ないのかな。
脱線:
普通、switch文を初めて見たら効率よく検索してるとおもうよね。私も昔そう思った。でも実際はif、else if、とアタマからブランチするように翻訳される。
新しいプログラミング言語の作者はなぜ、switch文を、テーブル検索するように翻訳しないのだろう?
C/C++はそう翻訳せざるを得ないんだけどさ。理由は、breakしないことをゆるしていて、判定する順番、ソースに書いてある順序が意味をもってるから。でも新しい言語はbreakなしを許さず複数のcaseに入ることを許さなければいいのに。
C/C++では関数ポインタ配列を簡単に書けるから、O(n)となることを回避する方法はあるんだが、javaは...
やっぱりJavaはフールプルーフを重視した言語なのだろうか。
まぁね、こういうこと考える事自体が楽しいからいいんだけどさ。
2011/3/9
「嫌いなものじゃなくて好きなもので自分を語れよ」
と、「国際問題をハスに流す萌えキャラ」に言われた気がするので、今後気をつけます。
(5)お、おぅ
...過去の自分からツッコミ受けてしまった。そうだね。好きな物を語るよ!
それでふと思ったんですけど、嫌い嫌いって言ってる俺は、もしかしてJavaのことが大好きなんじゃね? ...うーん、いや、やっぱりない...な。