作者godfat (godfat 真常)
看板Ruby
标题[心得] dynamic scoping
时间Thu Jan 25 22:56:20 2007
原文是 CSSE 186 篇
令以下程式:
class A
def f
puts 'A::f'
end
def g t
t.call
end
end
def f
puts '::f'
end
def g t
t.call
end
b = lambda{f}
g b # ::f
A.new.g b # 问号
问号应该填什麽?
依照 static scoping, 是 ::f
依照 dynamic scoping, 是 A::f
Ruby 是 static scoping 的,所以是 ::f
那麽要如何达到 dynamic scoping 的能力?
可以依靠 eval 这个好东西(但我想执行效能应该蛮差的)
这次,t 不能写成 Proc, 因为成为 Proc 时就已经 binding 完成了
这意味着我们不能用 lambda. 把 t.call 的地方改写成:
eval t
如此就能达到 dynamic scoping 的能力
只是,我们就不能用合乎直觉的写法,所有的 Ruby code 都得写成字串的形式
不能写成
b = f
要写成纯字串模式:
b = 'f' 或是
b = 'send :f'
如此在 eval t 之处,就能依照该处的 scope 来做 binding
输出结果就会是 A::f
这里其实有改进之处,因为我们只是要执行某个 function 而已
所以把 eval t 改成 send t
再把 b = 'f' 改成 b = :f
这样应该会获得一点效率上的优势
不过这样做就使得弹性下降了,因为你的 :f 不能存取当地的 lexical content
f = lambda{ print i } # i ?
字串的话
f = 'print i'
def loop n, f
n.times{|i| eval f}
end
loop 10, f
这样 'print i' 中的 i 就能存取到当地的 lexical content
不过我不知道 Ruby 的 Binding object 是否可以帮得上什麽忙
不是很懂 Binding 要怎麽用
另外,我还有试了一下 ECMAScript 和 Flash 的 ActionScript
乍看之下可以做到像是上面的动作,但是其实只是假像
function A(){}
A.prototype.f = function(){
print('A::f')
}
A.prototype.g = function(t){
eval(t)
}
function f(){
print('::f')
}
function g(t){
eval(t)
}
b = 'this.f()'
g(b)
new A().g(b)
这样可以印出
::f
A::f
没问题,可是如果把 b = 'this.f()' 改成 b = 'f()' 的话,结果会变
::f
::f
我想是因为他可能没有隐喻 this 的关系吧(没有查 spec, 猜的)
可是如果加上 this 的话,把 A.prototype.f 拿掉,
就会出现 undefined function call 了
这点在 Ruby 里没有问题,因为不用强制写下 this(self),
所以 this(self) 中找不到人的话,就会往上一层 scope 去找,进而找到 ::f
ActionScript 的结果和 ECMAScript 一样,系出同源的关系吧
PHP 不试了,物件导向的能力实在太差了
reference:
http://en.wikipedia.org/wiki/Scope_(programming)#Dynamic_scoping
或
http://en.wikipedia.org/wiki/Scope_%28programming%29#Dynamic_scoping
edited:
於是我们可以更进一步去想,那麽在字串中的程式,是否失去语法检查?
f = 'print i'
不可能会有语法检查,如果写成
f = 'print (i}'
要等到真正 eval 时,才会报 error
字串里应该要有语法检查,不过不用检查语意
f = 'say i'
说不定当地有 say 这个 method, 不能先行检查
所以用字串还是有蛮大的缺点
regular expression 可以用 // 夹起来
这种可植入的程式码,也应该用另一种形式夹起来
像是
f = <% say i %>
不过如果可以的话,一个符号就好了
f = < say i > 会简洁一些
一种可能的改进方向吧
--
生死去来、棚头傀儡、一线断时、落落磊磊
《花镜》-世阿弥
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 220.135.28.18
※ 编辑: godfat 来自: 220.135.28.18 (01/25 23:05)