作者godfat (godfat 真常)
看板Ruby
标题[Ruby] class 与 instance
时间Thu Feb 8 17:03:21 2007
在看 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
1F:推 poga:大王m 02/08 18:34
2F:推 skyboy:推 :) 关於class那部份的观念其实是一样 02/08 20:15
3F:→ skyboy:不过把名词的定义还是弄的清楚点 谢了 :D 02/08 20:16
4F:→ godfat:从善如流 XD 不客气,有问题欢迎再提出 02/08 20:40