Re: デフォルトのローカルとローカルの明示的な宣言私は明示的なローカル宣言リストが好きです。 私が見逃した場合、グローバルネームスペースに着陸し、showglobals() がそれを識別します。全体的な空間がきれいなままになるまで、泡立てて、すすぎ、繰り返します。
Re: デフォルトのローカルとローカルの明示的な宣言これを確認するためのワークフローを教えてください。 開発中に関数の最後に「Show Globals()」を追加し、グローバル名前空間に意図しないものを追加していないことを手動で確認しますか? それとも、これはテストで強制できるものですか?
副次的な質問: Show Globals と Show Symbols のどちらを使用する必要がありますか? 関数からローカル変数を意図的に省略した場合でも、Show Globals からの出力は表示されませんが、Show Symbols を使用すると、とにかく新しいリストに気付かないほど多くの出力が得られます。
それが役立つ場合は、すべてのスクリプト ファイルで「Names Default To Here」モードをオンにしています。
Re: デフォルトのローカル vs ローカルの明示的な宣言これまでの私のワークフローは、Names Default To Here を使用せず、グローバル名前空間を明確にしておくことでした。 Names Default To Here を常に使用している場合、Show Globals() はおそらく何も表示しません。 Show Symbols() は、深くネストされた関数で使用すると、コール スタックを介して情報を報告するため、ノイズが多くなります。 これが私のワークフローの例で、 Names Default To Here と Show Symbols を使用するように作り直されました。 そのまま実行して、漏れません。 17 行目 (g3) をコメントすると、g3 が「here」名前空間に配置されるため、エラーがスローされます。 この例での g2 の使用は、厄介な問題を浮き彫りにしています。デフォルトのローカルその問題を解決しますが、指摘した問題を追加します。 今後のプロジェクトで Default Local に戻してみるかもしれません。 それは私にとってより安全な選択かもしれません。変数を書き込む前に読み取るよりも、明示的なローカルから変数を除外する可能性が高くなります。
あなたは私よりも細かいテストをしようとしていると思います。最後に(グローバルまたはここで)テストするだけです。 すべての関数で名前空間の漏れをテストする必要がある場合は、これらのアイデアのいくつかを使用できる場合があります。
// **** you will probably need to restart JMP to really understand each change you make. ****
xyzzy = "before names default to here"; // this goes into globals. If you run again it goes into 'here'.
Names Default To Here( 1 ); // takes effect when executed
New Namespace( // don't put the functions in the here namespace, keep them in appDemo.
"appDemo" // this keeps the here namespace free of voluminous function definitions.
);
appDemo:originalLeakState = Log Capture( Show Symbols() ); // remember the original state
appDemo:f1 = Function( {p1}, // parameter list
{
//g2, // <<<< comment this use f2's local
g3, // <<<< comment this to make a leak
g1}, // local list
Write( "\!ng2=", g2 );
g1 = 1; // very local to this function
g2 = 2; // not local, in this example it is local to f2, a bug if unintentional
g3 = 3; // not local, lands in the 'here'
);
appDemo:f2 = Function( {p2},
{g2},
g2 = 42; // this will be over written by f1
appDemo:f1( p2 );
);
appDemo:f2( "x" );
// if you call f1 from here, the here:g2 gets written
// g2 = 142;
// appDemo:f1( "x" );
// a test might look like this
If( Log Capture( Show Symbols() ) != appDemo:originalLeakState,
Write( "\!n=============leak report==============" );
Show Symbols();
Throw( "variable namespace leaks, see log!" );
,
Write( "\!n========= no change to symbols =======" );
If( Length( appDemo:originalLeakState ),
Write(
"\!n========= original leak state: =======",
appDemo:originalLeakState
)
);
);Re: デフォルトのローカルとローカルの明示的な宣言ありがとうこれはとても役に立ちます! 漏れがないことを保証する自動チェックを書くために、ここに書いたことのいくつかを使用できるはずだと思います。
Re: デフォルトのローカル vs ローカルの明示的な宣言また、DEFAULT LOCAL には奇妙な点があります。実際にスクリプトを読み取り、作成される変数の解釈に基づいてローカル割り当てを作成します。これを台無しにする方法はいくつかあります。 おそらく最も頻繁に目にするのは、変数名を動的に作成しようとするときです。私が言いたいのは、それを行うのは素晴らしいことではなく、あなたもそれを明示的に述べることができなかったので、同じようなものです.
Names default to here(1);
f = function({},
{DEFAULT LOCAL},
x = 14;
Eval(Parse("x"||char(x)||"=28"));//not that anyone should ever do this BUT ...
return(x);
);
f();
namespace("here"); // notice how x14 is in the here namespace
/*
New Namespace(
{
f = Function( {},
{Default Local},
x = 14;
Eval( Parse( "x" || Char( x ) || "=28" ) );
Return( x );
),
x14 = 28
}
)
/*Re: デフォルトのローカルとローカルの明示的な宣言将来の読者のために、私は最終的にすべてのローカルが明示的に宣言されていることを強制するために使用するテストヘルパーを書きました
/*
* Test that `invocation` does not add any variables to the Here namespace. It is important that
* this test be run first, else whatever variables may leak will leak before running this test and
* so they will already be present in `hereVariablesBefore`.
*
* Example:
* someFunction1 = Function( {}, {}, leakedVar = 1);
* someFunction2 = Function( {}, {safeVar}, safeVar = 1);
* assertNoLeakedVariables( Function( {}, {}, someFunction1() ) ); // Fails
* assertNoLeakedVariables( Function( {}, {}, someFunction2() ) ); // Passes
*/
assertNoLeakedVariables = Function( {invocation},
{hereVariablesBefore, hereVariablesAfter},
Try(
// Declare both of these in advance, because otherwise the key `hereVariablesBefore` will not be
// present in `hereVariablesBefore` and it makes the assertion confusing.
hereVariablesBefore = .;
hereVariablesAfter = .;
hereVariablesBefore = Namespace( "here" ) << Get Keys;
invocation();
hereVariablesAfter = Namespace( "here" ) << Get Keys;
UT Assert( Expr( Length( hereVariablesBefore ) ), Length( hereVariablesAfter ) );
If( Length( hereVariablesBefore ) != Length( hereVariablesAfter ),
showLeakedVariableNames( hereVariablesBefore, hereVariablesAfter )
);
,
UT Assert( exception_msg, "" )
)
);Re: ローカルのデフォルトのローカル宣言と明示的な宣言これは私にとって非常に頻繁に起こります。非常にイライラすることがあります。
このスクリプトは名前を上書きします (名前は関数のローカル スコープをエスケープします)。
Names Default to Here( 1 );
some expr = Expr(
a = 4;
b = 5;
g = 6;
);
f = Function( {input expr},
{Default Local},
Print( "running expr" );
input expr
);
f( Name Expr( some expr ) );
show( a, b, g )これが解決策ですが、この解決策の問題は、技術的には 2 つの関数呼び出しであることです (2 つのスタック項目としてカウントされるため、225 のスタック制限に早く到達します)。
Names Default to Here( 1 );
some expr = Expr(
a = 4;
b = 5;
g = 6;
Show( Eval List( {a, b, g} ) );
);
f = Function( {input expr},
{Default Local},
Print( "running expr" );
Eval( Eval Expr(
Local( {Default Local},
Expr( Name Expr( input expr ) )
)
) );
1
);
f( Name Expr( some expr ) );
show( a, b, g )「Default Local」ディレクティブが解析時ディレクティブではなく実行時フラグであれば良いのですが、おそらく何が起こっているのかというと、名前解決が解析時に実行されているため、実行時の名前検索ルールが意味をなさなくなっています。 。
ローカルのデフォルトのローカル宣言と明示的な宣言こんにちは。関数のローカル スコープに関するリスクを制限する最善の方法を理解しようとしています。 私の理解では、関数の実行内から Here スコープを汚染する可能性を制限するためのオプションは、ローカル変数を宣言するか、Default Local を使用することです。 ただし、これらにはそれぞれ次のような問題があります。
デフォルトのローカル:
- ローカルで定義されていない名前は、場合によっては Here then (Names Default To Here がオフの場合) Global then current table にフォールバックするため、値の参照はコンテキストに依存する可能性があります。 ドキュメントに記載されているように、これは、値がコンテキストに依存するため、動作が予測しにくいことを意味する可能性があります。
明示的な宣言:
- ローカル名で宣言されていない場合、名前は宣言されるまでこのフォールバック動作を使用するため、値の参照はコンテキストに依存する可能性があります。
- 割り当てが誤って Here スコープに漏れる可能性があります。 つまり、ローカルであることを意図した名前がローカル名の宣言から省略されると、周囲の Here スコープが汚染されてしまいます。
- 一般に、この外側範囲の汚染を追跡するのは困難です。
- たとえば、反復子として "i" を使用する For で関数を呼び出し、その関数にも i を使用する For があり、それをローカルとして宣言できなかった場合、外側の For ループに影響します。 確かに、これは明らかなプログラマ エラーですが、作成するのは簡単ですが、デバッグは困難です。
私の考えでは、理想的なオプションは「Strict Local」のようなものを宣言でき、非修飾名 (値の割り当て時と値の参照時) を常にローカルとして扱い、周囲のスコープは修飾名でのみアクセスできるようになります。 これにより、周囲のスコープを汚染するリスクを回避できるだけでなく、それらのスコープに依存している場合に申告を強制することができるため、周囲のスコープからの局所的な汚染を制限できます。
高度な統計モデリング消費者および市場調査データアクセスデータの探索と視覚化マスカスタマイゼーションRe: デフォルトのローカルとローカルの明示的な宣言「ワークフロー」に関して - この #NamespaceInspector のような小さなヘルパーは、変数を追跡するのに大いに役立ちます。
それらは Here 名前空間に表示されますか、それともローカル名前空間に表示されますか?
デバッグが完了したら、アドインとしてアップロードします...