動的スコープを持つ言語で動作しない幸運をお持ちの方のために、それがどのように機能するかについて少しおさらいさせてください。次のように動作する「RUBELLA」と呼ばれる擬似言語を想像してください。
function foo() {
print(x); // not defined locally => uses whatever value `x` has in the calling context
y = "tetanus";
}
function bar() {
x = "measles";
foo();
print(y); // not defined locally, but set by the call to `foo()`
}
bar(); // prints "measles" followed by "tetanus"
つまり、変数はコールスタックを上下に自由に伝播します-で定義されたすべての変数は、foo
その呼び出し元に表示され、呼び出し元によって変更可能bar
です。逆もまた真です。これは、コードのリファクタリングに深刻な影響を及ぼします。次のコードがあると想像してください。
function a() { // defined in file A
x = "qux";
b();
}
function b() { // defined in file B
c();
}
function c() { // defined in file C
print(x);
}
これで、への呼び出しa()
は印刷されますqux
。しかし、その後、いつか、b
少し変更する必要があると判断します。すべての呼び出しコンテキスト(実際にはコードベースの外にあるものもあります)を知っているわけではありませんが、それは大丈夫です-変更は完全に内部になりますよb
ね?したがって、次のように書き換えます。
function b() {
x = "oops";
c();
}
そして、ローカル変数を定義したばかりなので、何も変更していないと思うかもしれません。しかし、実際には、あなたは壊れていa
ます!今でa
はoops
なく、印刷しqux
ます。
疑似言語の領域からこれを取り戻すと、異なる構文ではありますが、これがまさにMUMPSの動作です。
MUMPSのモダン(「モダン」)バージョンには、いわゆるNEW
ステートメントが含まれています。これにより、変数が呼び出し先から呼び出し元に漏れるのを防ぐことができます。したがって、上記の最初の例でinを実行NEW y = "tetanus"
したfoo()
場合、print(y)
in bar()
は何も出力しません(MUMPSでは、明示的に他の値に設定しない限り、すべての名前は空の文字列を指します)。しかし、変数が呼び出し元から呼び出し先に漏れることを防ぐことができるものは何もありません:function p() { NEW x = 3; q(); print(x); }
知っている限り、パラメータとして明示的に受け取っていなくても、q()
変異する可能性があります。これはまだ悪い状況ですが、おそらく以前ほど悪くはありません。x
x
これらの危険性を念頭に置いて、MUMPSまたは他の言語のコードを動的スコープで安全にリファクタリングするにはどうすればよいですか?
そこに簡単リファクタリング作るためのいくつかの明白な良い慣行は、あなたが(初期設定以外の機能で変数を使用したことがないように、あるNEW
自分は)または明示的なパラメータとして渡され、明示的パラメータ文書化されている暗黙のうちに、関数の呼び出し元から渡されたし。しかし、数十年前の〜10 8 -LOCコードベースでは、これらはしばしば持っていない贅沢品です。
そしてもちろん、字句スコープを持つ言語でのリファクタリングの基本的にすべての優れた実践は、動的スコープを持つ言語にも適用できます-テストの書き込みなど。質問は次のとおりです。リファクタリング時に、動的スコープのコードの脆弱性の増加に特に関連するリスクをどのように軽減しますか?
(動的言語で記述されたコードをどのようにナビゲートおよびリファクタリングしますか?は、この質問と似たタイトルを持っていますが、まったく無関係です。)