[Ruby] class 與 instance

看板Ruby作者 (godfat 真常)時間18年前 (2007/02/08 17:03), 編輯推噓2(202)
留言4則, 3人參與, 最新討論串1/1
在看 Ruby 的 class 與 instance 之前,先來看所謂 prototype-based language 是怎麼樣的東西, 當然是舉大家最耳熟能詳的例子,ECMAScript(即 Javascript) 所謂 prototype-based 的意思是,沒有 class 的概念,所有的一切都是 instance, 產生東西一律使用 clone 的手法,從 prototype clone 出來 如果有耐心慢慢看英文的話,這篇很詳細 http://en.wikipedia.org/wiki/Prototype-based_programming 在 ECMAScript 裡,要這樣操作 prototype: =begin 例子 // 產生一個 function object, 會輸出「我是 ooo」 function say(){ print('I am ' + this) } // 產生一個 function object, 拿這當 Duck 的 prototype function Duck(){} // 讓 Duck prototype 產生一個成員,也就是讓 say 變成他的 method Duck.prototype.say = say; // 定義 toString 讓 say 使用 Duck.prototype.toString = function(){ return 'Duck' } // 假設現在有一個讓某東西說話的 function function say_hello(who){ who.say() } // 於是我們可以這樣呼叫 say_hello say_hello(new Duck) =end 例子 new Duck 會去尋找 Duck 的 prototype, 然後 clone 一份該 prototype 後傳回 所以 say_hello 的 who 會是一份 Duck 的複製,執行 say 則會輸出 I am Duck ok, 回到 Ruby. 雖然說 Ruby 被分類成 class-based, 但事實上, everything(ok, almost) is an object in Ruby, 就算是 class, 他其實本質上也是某個 instance, 是 Class 的 instance. class A; end a = A.new a 是 A 的 instance, 所以 a 的 class 是 A. a.class # A A 是 Class 的 instance, 所以 A 的 class 是 Class A.class # Class 其實,我覺得可以把這個 Class 視為某種 meta-class, 即 class 的 class, 如果我們要把 A 當嚴格 class 的話。但如果我們依然把 class 當 instance 看的話,當然,Class 本身其實也是一個 instance, 他是他自己的 instance. Class.class # Class 有趣的是,這樣寫的話: Class.object_id == Class.class.object_id 答案是:true. Class.class 傳回來的,其實就是 Class, 也就是,他是他自己的 instance. 換句話說,其實 Class 是所有的 class 的 class, A.kind_of? Class # true Class.kind_of? Class # true A.class # Class Class.class # Class A.class.object_id == Class.object_id # true (btw, 其實更妙的是: Module.kind_of? Class # true # Module 是 Class 的 instance Class.kind_of? Module # true # Module 是 Class 的 superclass Module.new.kind_of? Class # false # Module 的 instance 不是 Class 再加上 Object 會更複雜,可以試著畫畫看物件結構) 但是回想一下,一般我們是怎麼定義 class 的? class A; end 其實,我個人會說這是一種 syntax sugar, 因為更合於 Ruby object system 的 定義方式,應該是這樣: A = Class.new A.send(:define_method, :say_hello, lambda{ puts "Hello from A's instance." }) a = A.new a.say_hello # Hello from A. 由於 define_method 是 private 的,所以要用 send 去呼叫 其第一參數是你所要回應的 message symbol, 第二參數是 Proc/Method/Block 都可 將會成為該 method 的 body. 也就是說,其實你寫 class A def say_hello puts "Hello from A's instance." end end 對於 A 來說,他是先從 Class 產生一個實體(instance) 然後將 A 這個「常數」指向那個實體,再對 A 呼叫 define_method 把 say_hello 變成 symbol, 將 Block 變成該 method 的 body. 哪一個比較容易寫?當然是後者,畢竟那是大家都很習慣的模式,簡潔易懂 所以我會說那種寫法其實在某種程度上來說,是 syntax sugar... 而 Ruby 其實也是用 prototype 建出其 class 體系, 這樣應該算是 prototype-based 還是 class-based, 看倌認為哩? OK! 回到最早發表這篇文章的動機之來源問題,怎麼刪掉某個 class? 由於以 GC 為記憶體核心模型的程式語言,通常不允許你對某個物件明白刪除 我們能做的只有把他設為 nil, 像是 a = A.new a = nil # 希望 GC 收回 A 當然也是某個 instance, 只是記得「大寫」開頭的 identifier 是常數吧? A 正是一個 const pointer 指向某個 instance(A 的 prototype) A = nil # 希望 GC 收回 這樣就可以很暴力地期望 GC 會回收 A... 我不知道這樣做能不能 work, 只知道肯定會噴 warning, 因為你竄改常數 安全性設高一點的話,這樣做甚至會失敗(因為不能修改常數) 很好!再回想一下,你不能寫 class a; end 因為 class 要大寫開頭(才是常數) 但是你可以這樣寫: a = Class.new a.send(:define_method, :say_hello, lambda{...}) a.new.say_hello # ok a = nil # ok 現在 a 不是常數了,但是他仍然是某個 class! 確實是可以正確地將他指為 nil 了… 可是話說回來,既然都在用 Ruby 了,刪除東西真的是很重要的一件事嗎? 當然不是!記住 scripting 的優勢在哪裡,如果放棄這個優勢,不如去用 system langauge, 如 C++ 之類的會遠比在這邊磨 Ruby 要來得好 最後最後講個題外話,跟本主題沒有關係。 說過很多次個人相當崇拜物件導向,也喜歡各種高度抽象、動態的特性。 而我 Ruby 特性看得越多,某種失落感就越大。 因為以我現在的能力,實在想不太到還有哪些是 Ruby 相當值得改進的部份。 也就是說,Ruby 讓我感覺不到有必要自己下去寫一個全新的語言,他已經夠好了。 剛開始碰 Ruby 時,勾起我很多的想法。可是越碰越多後,發現其實這些在 Ruby 裡面本來就已經有了,而且夠好用了。剩下的交由 lib 實作就可以了, 沒什麼語言可以置喙的地方…。 我想當然,一定還有很多可以改進的,只是以我現在的能力確實看不太出來。 之前貼過一篇文章,Ruby sucks (All those shaky laguages... ) http://www.lrde.epita.fr/~didier/comp/ruby.php 我一直很喜歡這篇,因為其實這篇對 Ruby 有很高的讚譽。 只是完全比不上 Lisp 而已,哈哈。而目前我還不太能夠理解 Lisp... 真的要說的話,目前我還是支持多重繼承,想不太到多重繼承有什麼大問題。 除了讓 compiler 變得很難寫、object system 變得錯綜複雜外,不覺得有什麼問題。 而每一個鋒銳的武器,當然都很有可能會傷到自己人,這是功力問題。 水能載舟亦能覆舟,但這不代表我們要把水給拋棄…。 The Truth about Multiple Inheritance http://www.eiffel.com/general/monthly_column/2006/October.html 這篇也是在讚揚多重繼承。雖然我不是很懂他對 C++ 有什麼不滿。 在 Common Lisp 的 CLOS 中,多重繼承的威力更是非常非常地驚人。 當然我是不太清楚多有威力,畢竟 Lisp 還是離我有點遠,只是, Ruby 如果加上多重繼承的話,也許是一個改進的方向吧。 2007.02.08 -- Nobody can take anything away from him. Nor can anyone give anything to him. What came from the sea, has returned to the sea. Chrono Cross -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 220.135.28.18

02/08 18:34, , 1F
大王m
02/08 18:34, 1F

02/08 20:15, , 2F
推 :) 關於class那部份的觀念其實是一樣
02/08 20:15, 2F

02/08 20:16, , 3F
不過把名詞的定義還是弄的清楚點 謝了 :D
02/08 20:16, 3F

02/08 20:40, , 4F
從善如流 XD 不客氣,有問題歡迎再提出
02/08 20:40, 4F
文章代碼(AID): #15okTSCk (Ruby)
文章代碼(AID): #15okTSCk (Ruby)