看板 PLT 關於我們 聯絡資訊
※ 引述《PsMonkey (痞子軍團團長)》之銘言: : 面對 C 家族的狂熱分子 : Java 典型被批判的就是「沒有指標」 : 或著應該說「沒有辦法直接用指標」 ^^ 者 : 甚至有人用「全梭了」的肯定語氣跟我說 : 「沒有指標很難寫程式」 老實說,我以前也會這樣說 :p 算是一個懵懂時期的重大錯誤之一吧 [遠目] 不過其實這件事可能還在不早之前…這就不多提了 主要的問題點在於,那時我完全不懂 Java, 不懂 Java 說「沒有指標」這件事到底是指什麼。 以下假設讀者懂 Java reference 也懂 C/C++ pointer, 不懂的話請多看書或提出討論 XD 這篇文章中的一個標題(不用看,跟本文無關,但可參考): http://www.cs.caltech.edu/~mvanier/hacking/rants/ scalable_computer_programming_languages.html 縮 http://rubyurl.com/uQC 「Direct access to memory and pointer arithmetic: very bad」 真正的燙手山芋其實是這句話裡的東西,而非 pointer 本身。 而 Java 到底有沒有 pointer? 就我的觀點,有,只是不能以之運算罷了。 在 C/C++ 中,東西是可以建立在 stack 上的,而當你把他 pass around 時, 則是 pass by value, 是把整個東西 bitwise copy 丟過去。 而我呢,在還沒接觸 Java 前,以為所有的東西都必須這樣 bitwise copy... 這種程式語言能用才怪,這樣寫 sub-routine / sub-program / function 豈不是大吃資源?怎麼可能能用? 再者,Java 的 reference, 跟 C++ 的 reference 根本毫無關係… C++ 的 reference 是 alias, 即決定了就不能改變了,也不能是 NULL 的 reference, 即每個 reference 一定要 refer 某樣東西,而且永遠是那東西。 ok, 在這種狀況下告訴我 Java 沒有 pointer, 只有 reference, 怎麼能接受呢? Orz 但事實上,Java 的 reference 在 well-written 的 C++ 裡, 其意思跟 C++ 的 pointer(包括 smart pointer)是差不多的。 Java 的 reference 不能運算,即不能寫 Object o; o += 1; 不能比較 Object o1, o2; boolean b = o1 < o2; 不能取得變數本身(取址以便做 alias) Object o; Variable v = &o; 除此之外跟 pointer 應該是沒什麼差別了(暫時想不到) 而沒有這些會不會有什麼問題?我敢說,絕對不。 alias 當然很方便,但其實也造成很多問題。(這邊不講了,會扯很遠) 指標運算更是 error-prone, 某種程度上也會跟硬體相依。 上面那篇文章說:「very bad」 基本上我是同意的。只是我是覺得反正就不要用,工具放著又不會來咬人, 也許哪天還是要用到啊,倒也不必視為毒蛇猛獸就是了。 另外 Java 也沒有 stack 上的 object, 一定要用 new 來建立 所以有沒有 pass by address/reference, 也不是那麼重要了… 這種情況下,到底該不該說沒有 pointer? 我保留,但尊重 Sun 的術語, 所以談到 Java 時仍然使用 reference 一詞。再講到 C/C++ 的話, 我會稱 Java 的 reference 是閹割過的 pointer, 否則容易跟 C++ 的 reference 搞混。 我想會講「沒有指標很難寫程式」這句話,有三種可能: 1. 跟我一樣誤會了 Java 術語 2. 他要做硬體操作 3. 他要做非常重要的最佳化 結論是,不要再相信沒有根據的說法了 >< 受夠一些廣告用詞了…… : 夾在兩造雙方之間,其實就平民小卒來說,還挺困擾的 廣告太多,誤解太深,解決之道,親自一探 : 同樣的事情也發生在 gc、效率等等問題上 Modern C++ Design 作者 Andrei Alexandrescu, (http://en.wikipedia.org/wiki/Andrei_Alexandrescu 這人現在好有名啊…) 在 comp.lang.c++.moderated 上說,GC 可能是 programming 界被誤解最深的東西 簡單地說,他認為 GC 的好處太多了,而事實上,有些時候 GC 反而能增進效率。 因為有的時候,release 時機是很難處理的,這時候 GC 處理效率會比人高。 另外還有一個很好的範例,顯示 GC 如何處理一個棘手的 return 問題: …抱歉,我忘了是什麼情況 囧rz 希望有人可以指出 Orz 總之大意就是,你必須在 function return 完之後釋放資源。 可是這在一般流行的程式語言中,是不可能用簡單方法辦到的, 因為 return 之後 function 就跳離了,又不能這樣寫: return result; release(temp); // 當然此例可以拉到 return 上面,但我記得有種狀況是不行的 難道要這樣嗎? try{} finally{ release(temp); } return result; 不過這樣似乎變成一定要 release 了,不能用成緊接在 return 之後 比較蠢的方法可能可以這樣做: register_call_after_1_second( bind(&release, temp) ); return result; 註冊一個一秒後會呼叫的 function, return 應該不用執行一秒… 另外還有一個很有說服力的例子,被我提了好多次, 就是某個字串處理的問題,由 D 和 C++ 的程式分別寫成 我沒記錯的話,就是這個頁面裡的程式 http://www.digitalmars.com/d/cppstrings.html D 能夠跑比較快的優勢是擁有 sub-array view, 而實作這樣東西是需要 GC 的輔助,類似上面那樣的狀況。 其實這些討論我也是從 comp.lang.c++.moderated 看來的 有人說他可以把 C++ 寫到跟 D 差不多快,可是得用很多骯髒的手法… 寫得漂亮一點的話,執行效能就敗給 D 不少了 C/C++ 也有個名 GC 實作,叫 Boehm GC http://www.hpl.hp.com/personal/Hans_Boehm/gc/ 這東西的使用者其實還蠻多的,很多大型計劃也有使用 C++0x 的 GC 設計也跟此 GC 有很大的關聯 GC 已經差不多變成現代高階語言必備的東西了,C++ 在這裡走得稍嫌慢了點 : gc 是很消耗 resource 的行為 對於小程式來說,GC 是額外吃了不少資源,用處不大 畢竟小程式自己管理記憶體也不會是什麼難處 但對於大程式來說,GC 所消耗的資源會變得不明顯 當然,記憶體受限的 embedded 環境可能也不便用 GC 不過以 PC 來說,GC 所帶來的壞處其實很不明顯了 : 那麼,是要賭自己控制 resouce 會比較好 : 還是期望語言本身提供 gc 的演算法可以達到「可接受」的範圍? : 因為我是笨蛋,而且我相信開發 JVM 的人比我聰明百倍... 這個其實就比較難講了,客製的當然會更容易比通用的效率好 不過隨著時間不斷演進,通用的也越來越不會有什麼問題了… : 但是,又有人跟我講 : Java 沒辦法處理很大量資料的狀況 : 所以他雖然是從 Java 起家的,不過後來還是乖乖寫 C : (他好像是作即時影像處理的,然後隨便就是幾百MB 的資料在記憶體當中) : hmmm... 還沒寫過那種恐怖的東西... 很難想像 : 但是 Java 真的作不到嗎? 好像也很難想像... : 也許作起來要花很多功夫? 這我不知道 Orz 不過很多極端吃系統資源的程式,就我所知在 JVM 上都不好發揮 感覺會是綁手綁腳 : 但是... 能不能把這個狀況當作是極端狀況來對待? : 我的意思是... 畢竟一般人寫一般程式 : 用 Java 好像很快樂也不容易出大紕漏? : 我們畢竟會常常需要用到動態決定大小的陣列 : 而很少要處理很大量很大量的資料? 我可不可以說所以 Java 現在人口排行第一? :p http://www.tiobe.com/tpci.htm 其實 C++ 會排第三也蠻神奇的,我個人覺得 C++ 這種瘋狂複雜的東西,我不信能有那麼多人搞懂… 最上面貼的那篇文章(Scalable computer programming languages)也說: Even though C++ is monstrously complex, the ability to write code that moves smoothly from a bit-level of abstraction to a fairly high level of abstraction is extremely valuable for many projects, especially ones where efficiency is paramount. I intend to do more C++ programming and also to use the Boehm-Demers conservative GC to see how effective it is in combination with C++'s other features. 隨意翻譯: 「儘管 C++ 是妖獸(XD)般地複雜,能從位元等級的抽象層平順地 移動到高階等級的抽象層,對於很多專案來說都是極端有價值的, 尤其是那些效率極為重要的專案。 我有意進行更多的 C++ 程式設計,也開始使用傳統的 Boehm GC, 以之看看該 GC 如何有效地和 C++ 其他功能合併在一起。」 * 順便再提一下 Beyond Java 這本書。 其實我之所以對此書有相當的不以為然, 有一個很大的原因就是他很明顯不懂 C++, 然後卻把 C++ 罵個半死。 (用這種態度去評論,其他的評論可信度?存疑) 上文的作者一開始也是不懂 C++, 不過語句保留,且最後他也同意了 C++ 是如此 powerful, 他願意做更多的嘗試。(推測是被很多人 email 去罵了… XD) : 寫到這裡,似乎就能預料有神人級的人會跳出來說 : 「語言只不過是工具,視狀況而決定工具 : 所以討論工具好壞是沒有意義的」 我覺得這樣講當然不對,因為這樣講的話根本啥屁都不用討論了。 我們只要顧著使用工具,或是顧著亂做一堆工具出來,好壞不管, 每個工具自有他的用處?秉持著這種精神,又怎麼能夠進步? 每個遊戲都有他的愛好者,所以我們遊戲可以亂做?當然不對。 所以一個遊戲好壞不重要,因為自有愛好者?這也當然不對…。 : 這樣講好像很對,但是又好像很不對 : 畢竟,像我這種笨蛋... 連 Java 都寫的不是很好了 : 要視狀況在工具之間跳來跳去,似乎有摔死的可能 Orz : (當然,現實狀況是... 環境逼著你跳,你不得不跳) 這個嘛…應該還是要在自己會的工具裡面跳。 只有一個工具當然就不用跳了,那叫做沒得選擇 XD 所以學會越多工具,就要越能有分辨工具好壞的能力… 這算是一種期許吧? : 又反過來說,面對另外一群人 : 他們會 argue Java 不夠快 or 不夠簡單 : 像 Perl 的使用者會覺得 Java 宣告起來很麻煩、字串處理很麻煩 : Ruby 的使用者會說 Java 寫起來不夠快 : (恩... 不過看到的好像大部分是針對 Web 開發的部份?) 我好像沒聽過有什麼用 Perl 寫成的超大型程式。 我想這一群人,目標本來就不是那種超級大型的程式。 畢竟 Perl 又常常被稱為 glue langauge, 是吧 :p 根據這裡: http://en.wikipedia.org/wiki/Glue_language Ruby 也算呢…。 不同的語言當然有不同的著眼點,個人認為有些語言的比較, 其實也已經有點變成是沒搞清楚什麼語言該做什麼事了…。 不過有些時候確實是因為不會而沒得選擇,像是早先我常用 C++ 寫字串處理程式,理由很簡單,因為我只會這個…。 要我花十個小時學好最適合該問題的語言,然後再花十秒鐘解決問題, 我寧可花十分鐘用我現在會的東西趕快解決問題…。 : 另外一個... 囧點... : 是好像很少人會把 C 家族跟 Perl, Ruby 來作對比 : (至少 PTT 的討論版很少看到) : 但是 Java 會拿來跟 C 家族來比較,也會被拿來跟 Ruby 來比較 這個其實一直是我覺得很妙的地方,哈哈 XD Perl 和 Ruby 很明顯就是 scripting language, 他的目標很明確。 C/C++ 也很明確,就是 system language, 絕對是拿來處理大問題的。 可是 Java 呢…?我個人覺得 Java 本身的處境其實很尷尬, 因為他介於 system language 和 scripting language 之間。 他比 C++ 更動態,但是遠遠沒有 Perl 和 Ruby 來得動態。 於是這造成了一種,我覺得很詭異的局面。 最簡單的例子就是容器了,在 Java 1.5 之前,容器一律用 Object 存: Vector v = new Vector(); v.add("XD"); String s = (String)v.get(0); 看到這種東西,真的讓我很想翻桌。 啊既然我都要用靜態型別了,為什麼又要我在 runtime 轉型? 不過另外一個說法是,反正容器就是要泛用,所以可以存任何東西。 ok, 我沒意見,C++ 的 boost 也有 any 這種泛用指標。(which is type safe) Java 1.5 加入 generic 後,整個狀況其實變得更詭異了… Vector<String> v = new Vector<String>(); // ok, verbose 這件事這裡不討論,好的解決辦法叫 type inference v.add("XD"); String s = v.get(0); 用程式碼看起來,問題是解決了沒錯。可是 runtime 上他還是存 Object... 所以基本上只是提供了更多型別安全,還有讓你少打點字。(算是改進…吧?) 但是就整個設計面來看,實在是有點矛盾……要靜不靜,要動不動… 我覺得,Java 在很多地方都卡在這種矛盾之中,搖擺不定。 一方面想搶 C++ programmer(他成功了!), 另一方面又想搶 scripting language 的飯碗…… 問題是,根本不可能有這麼萬能的語言和系統,兩邊可以通吃。 於是 C++ 視 Java 為敵人,Ruby 也視 Java 為敵人…… 然後 Sun 為了打敗 C++, 加入 XX 特性(這邊再用 OO 就要誤解了 XD) 然後 Sun 為了打敗 Ruby, 加入 YY 特性 原本好像很單純的 Java, 現在對我來說,他真的長得有點畸形……。 不可否認他用起來是不難,但是,其實就像 Scalable computer programming languages 這篇文章所說, I think Java is a fine language for many types of applications, but it doesn't have the qualities of coolness that make me fall in love with a language, and the abstraction level is still less than many other languages, including C++. (不翻了…寫太久了) Java 用在寫應用程式上是不錯,但是他實在缺少一個讓人愛上他的…特質? 畸形也許很好用,但他不美。 (很多人說 Lisp 很美,大概是因為幾乎沒有語法吧 :) 我也很崇尚這種 simplicity.) : 這個問題的切入點,以我淺薄的知識也想得出一些 : 不過一開始還是先隨意吧... 這樣子標靶比較大一點... [茶] : 所以上頭就寫的很鬆散... XD : 反正收斂焦點 & 收精華區是版主要煩惱的... [逃] Orz 我扯太多了,害我現在很累,想睡覺了 收斂焦點無妨吧?但沒有焦點精華區很難處理倒是真的 Orz 幸好其實也不是要出書,有點亂我想是無妨 -- Hear me exalted spirits. Hear me, be you gods or devils, ye who hold dominion here: I am a wizard without a home. I am a wonderer seeking refuge. Sacrifice -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 220.135.28.18
coolcomm:推 2013/ 07/25 12:57