2011年10月21日 星期五

Perl:Lexical Scoping 與 Dynamic Scoping 觀念比較



Lexical (Static) Scoping :從block 中找變數 從內層找到外層(my operator)

Dynamic Scoping:由函數呼叫順序逆序將變數找出來(local operator)

先前我們提到 shadow 的觀念; 這節我們要談的是 shadow 沒有發生的狀況: 在程式原始碼的某一點 (例如在副程式 h 當中), 用到一個變數 x, 但 local variables 當中並沒有 x。 先前我們的答案很簡單: 那麼這個 x 指的當然就是 global 的 x 嘍!
問題是: 那一個 global 的 x? 在 pascal 與 lisp 語系 等等允許副程式定義裡面又有其他副程式定義的語言裡, 單單講 global 與 local 並不清楚。 如果最內層的副程式裡面沒有宣告 x 但卻用到了 x, 那麼究竟要去那裡找其他 (比較 global) 的 x? 像這個 例子
最直覺的答案是: 看程式碼, 找最內層 (最 local) 的 x。 這種「根據程式碼當中, 變數出現的位置, 來決定未在本地宣告的變數究竟來自何處」的規則, 叫做 lexical scoping 也叫做 static scoping。 大部分的語言 (例如 pascal) 都採取這個規則。
還可能有別種規則嗎? Lisp 語系的眾多方言 (dialects) 當中, 有許多 (例如 emacs lisp) 採取的是 dynamic scoping: 光看程式碼還不夠, 必須真的知道程式執行的過程, 畫出程式執行到使用 x 那句話當時的 系統堆疊, 由內 (最近放上去的 A.V.) 向外找到何處有宣告 x。 在 lisp 的某些方言 (例如 librep) 當中, 平常採取的是 lexical scoping; 但如果你用 defvar 宣告變數, 則這個名稱的變數就變成了 dynamic scoping。 在 perl 當中, 比較常用 lexical 變數 (用 my 宣告); 如果要用 dynamic scoping, 必須用 use vars 宣告全域變數, 用 local 宣告局部變數。
用術語來講, lexical scoping 循的是 static ancestors 的族譜向上找 (h -> f -> 最外層); 而 dynamic scoping 循的是 dynamic ancestors 的族譜向上找 (h -> g1 -> f -> 最外層 或 h -> g2 -> f -> 最外層)。

沒有留言:

張貼留言