看板 PLT 關於我們 聯絡資訊
嗯,剛好在『PHP 很爛』這篇文章裡看到了這個 Recovery From Addiction 的影片。 [1] PHP 很爛 http://blog.ez2learn.com/2010/01/06/php-sucks/ [2] Recovery From Addiction http://www.archive.org/details/SeanKellyRecoveryfromAddiction 基本上關於 PHP 爛不爛的部份每個人都有想法,但基本上我是論認為 PHP 很爛的那一派,我的碩士論文是實作 Drupal 的一個模組,用的是 PHP,可 是我還是覺得 PHP 很爛。 但不可否認的是,在我學 Scala 之前,要做用了就丟的東西時候我的第一 個選擇會是 PHP(因為我沒學 shell scrip),簡單,好用,用了就丟的東 西也不用講究什麼安全性或強固性,可以動就好了。 但自從學了 Scala 之後,Scala 會是我的首選,再不然,我也會選 Ruby, 雖然我的 Ruby 程度大概還只停留在 Hello World 而已。 回到正題,Recovery From Addiction 是一個很棒的影片,不過可惜的是裡 面的例子只有提到 Java vs Python 而已,但是個人私心很喜歡 Scala 還 有 Ruby ,所以就在這裡補上 Ruby 和 Scala 例子。 想從 Java 跳船的人可以參考一下 Recovery From Addiction 影片,以及 這些例子。 雖然影片是從座標的函式庫的設計開始講,不過這裡會從客戶端開始說。 我們先看 Java / Python / Ruby / Scala 三者的客戶端程式。 =============================================================== // This is Java. Coord coord = new Coord (); coord.lat = -93.0 // Souther than south! =============================================================== =============================================================== # This is Python. coord = Coord () coord.lat = -93.9 # Souther than south! =============================================================== =============================================================== # This is Ruby. coord = Coord.new coord.lat = -93.9 # Souther than south! =============================================================== =============================================================== // This is Scala. val coord = new Coord () coord.lat = -93.0F // Souther than south! =============================================================== 基本上都是一樣的,產生一個 Coord 物件,然後指定一個座標。接下來, 我們來看第一版的函式庫端。 =============================================================== // This is Java. public class Coord { public float lat; public float lon; public Coord () {} public Coord (float lat, float lon) { this.lat = lat; this.lon = lon; } } =============================================================== =============================================================== # This is Python. class Coord (object) def __init__ (self, lat = 0.0, lon = 0.0): self.lat, self.lon = lat, lon =============================================================== =============================================================== class Coord attr_accessor :lat, :lon def initialize(lat, lon) @lat = lat @lon = lon end end =============================================================== =============================================================== class Coord (var lat: Float, var lon: Float) { def this () = this (0, 0) } =============================================================== 到這邊為止,Python / Ruby / Scala 還是不算完全打敗 Java,畢竟 Java 也才九行程式碼,Ruby 也要七行。 重點是下面了,現在我們發現原來的設計有問題,因為 lat 不能小於 -90 或是大於 90 ,我們要如何在不更動原有的客戶端的情況下,把這個判斷加 到我們的函式庫呢?Python / Ruby / Scala 都可以很輕鬆的做到。 先看 Python 的: =============================================================== class Coord (object) def __init__ (self, lat = 0.0, lon = 0.0): self.lat, self.lon = lat, lon def getLat (slef): return self.__lat def setLat (self, lat): if not -90.0 <= lat <= 90.0: raise ValueError ("Bad latitude") self.__lat = lat lat = property (getLat, setLat) =============================================================== 這段程式碼裡面,我們設了 getLat 和 setLat 這兩個函式,接著再指定說 lat 的 getter / setter 就分別是 getLat 和 setLat。 這個則是 Ruby 的: =============================================================== class Coord attr_accessor :lon attr_reader :lat def initialize(lat = 0.0, lon = 0.0) @lat = lat @lon = lon end def lat=(lat) if (lat < -90 || lat > 90) raise "Bad latitude" end @lat = lat end end =============================================================== 在 Ruby 裡的做法,則是叫 Ruby 自己生一個 getter 給我們,然後我們再 定義 lat=(lat) 這個函數,而這個函數就是 lat 的 setter。 接著看 Scala 的做法: =============================================================== class Coord (var mLat: Float, var lon: Float) { def this () = this (0, 0) def lat = mLat def lat_= (lat: Float) { if ( lat < -90 || lat > 90 ) throw new Exception ("Bad latitude") mLat = lat } } =============================================================== 在 Scala 裡,我們也是自己定義了 lat 的 getter / setter,眼尖的朋 友可能發現了原來成員變數的 lat 現在變成了 mLat,這是 Scala 本身的 限制,因為 Scala 自己就會幫我們產生一組 getter / setter。 所幸的是,Scala 是靜態語言,所以你大可先改成員變數的名稱,然後叫編 譯器幫你抓出所有錯的地方,基本上很簡單就可以做程式碼的重構,很少遇 到什麼大問題。 另外,Scala 神奇的地方,就在於雖然他寫起來像 Ruby / Python 這種動 態型別的程式語言,可是實際上他是靜態型別的,所有的型別錯誤在編譯時 期就會被抓出來。 我完全不會 Python、Ruby 是初學、Scala 是漸漸上手,在這邊野人獻曝一 下,分享一下 Ruby 和 Scala 的程式碼。 順道一提,影片中有提到 Ruby 的 Unicode 問題,但如果我記得沒錯的話, 目前 Ruby 應該是支援 Unicode 了。 然後,雖然作者有說他不喜歡 Ruby 那些從 Perl 借來,看起來很像暗碼的 變數符號,但我自己就整個程式的觀點來看,其實我發現只要掌握了一些大 的原則,Ruby 的程式碼比 Python 更容易看懂。 舉一個實際一點的例子,我就看不出來為什麼 Python 裡成員函數要存取成 員變數的時候要用 self.__lat 這個方式,不清楚為什麼 lat 前面還要多 兩個底線。 相較之下,Ruby 只是用了變數開頭的符號來區別是哪種變數罷了,就程式 的閱讀和撰寫來說,和其他語言感覺沒有太大的隔閡。 當然,這只能說是個人的喜好就是了,畢竟 Python / Ruby 兩者本身所信 仰的 coding 哲學本來就不同,只能說我比較偏好 Scala / Ruby 這邊的設 計哲學而已。 最後的最後,其實我很訝異最後 Scala 的版本竟然會比 Python / Ruby 還 來得少行,再加上還是靜態型別,可見 Scala 狂勝 Python / Ruby !(大 誤) PS、程式語言比較的東西,看看就好,用自己順手,喜歡的工具最重要! -- ~ 白馬帶著她一步步地回到中原。白馬已經老了,只能慢慢地走, 'v' Brian Hsu 但終是能回到中原的。江南有楊柳、桃花,有燕子、金魚…… // \\ ( 墳 墓 ) /( )\ 但這個美麗的姑娘就像古高昌國人那樣固執。 【白馬嘯西風】 ^`~'^ http://bone.twbbs.org.tw/blog 『那都是很好很好的,可我偏不喜歡。』 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 59.120.199.114
brianhsu:BTW,Python 另一個我覺得很謎的地方是為什麼要傳 self 01/08 00:24
brianhsu:給 instance method。XD 01/08 00:24
sbrhsieh:為甚麼一堆 Java 新手會問在 static method 使用 this 01/08 00:48
sbrhsieh:keyword 會有錯誤? 01/08 00:49
poga:為什麼你的Py都有Parallel assignment, Ruby都沒用XD 01/08 08:34
brianhsu:因為我不會,就說我 Ruby 只會 Hello World 了嘛。XD 01/08 09:08
saxonex:這篇好眼熟~XD 01/09 21:23