What have you found for these years?

2008-11-02

[rbx ] include_remove

 作者  godfat (godfat 真常)                                        看板  Ruby
標題 [rbx ] include_remove
時間 Sun Nov 2 01:45:34 2008
───────────────────────────────────────


我想應該大部份 ruby 玩得稍微深入一點的人,都會覺得需要 uninclude 吧?
像是之前在 ruby-talk 看到挺瘋狂的 namespace 概念,就需要這種功能。
而一般在 ruby 裡想幹種種事,會被建議這樣用:

BackupUser = User
User = BackupUser.dup

User.include Something
# ...
# ...
# 拋棄 Something 吧
User = BackupUser.dup

我個人是覺得這是個很爛的招式 XD

有人用 C 寫 extension 真的做到了 uninclude:
http://github.com/yrashk/rbmodexcl/tree/master

一點討論在這:
Any reason for having no module exclusion functionality in Ruby
http://www.ruby-forum.com/topic/150696



觀察了一下他在 rubinius (rbx) 上的實作,發現其實很單純:
http://github.com/yrashk/rbmodexcl/tree/master/rbxmodexcl.rb

不過程式有點醜,所以我改了一下...
http://github.com/godfat/rbx-include_remove/tree/master/include_remove.rb



基本上真的很單純,大概架構就是 module 本身是一個一個串起來的,
由 Module#superclass_chain 可以看出來。被 include 進去的 module,
會變成 IncludedModule 存在 superclass_chain 中。

而這個 chain 則是由類似 linked list 串起來的,由 superclass 串起。
藉由 Module#superclass= 即可改寫這個 linked list,
藉此移除 included module.

這邊比較神秘的是,superclass 本身是忽略 IncludedModule 的,
我想這是為了相容 MRI 的關係。所以查詢包含 IncludedModule 要用
direct_superclass. 其實 rubinius 類似這樣的動作還滿多的,
關於相容方面,JRuby 做得比較徹底。但 rubinius 彈性大到不可思議...

總之就是把 superclass_chain 當 linked list, 找到目標後移除目標 module,
像是這樣:

prev.superclass = next.superclass

而 extend_remove 就利用前面寫好的 include_remove 即可,
因為 extend 其實就是 metaclass 的 include...

metaclass.include_remove(mod)

這樣寫就好了。


==
比較神勇的是,rubinius 幾乎什麼都可以改寫,我甚至可以改寫
if condition
then_clause
else
else_clause
end
產生出來的 bytecode...

剛剛試了一陣子,要改寫 bytecode 的行為大概就不行了
本來想改寫 :goto_if_false 和 :goto_if_true, 但這好像是 c++ 的部份...
裡面還用到 reinterpret_cast 和 bitwise and, 不是很確定是什麼意思...
我想應該還有其他方法可以改寫 if 的行為才對,可能要改寫輸出的 bytecode.
把 if 再 wrap 一層,在外層呼叫 .nil?

不過雖然 rubinius 擴充性真的強到不可思議,跑起來也真的是好慢...
改寫 lib 後重新 compile 都要等好幾秒,啟動也要好幾秒...

--
By Gamers, For Gamers - from the past Interplay

--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 220.135.28.18

0 retries:

Post a Comment

Note: Only a member of this blog may post a comment.



All texts are licensed under CC Attribution 3.0