回复:默認本地與本地人的顯式聲明我喜歡顯式的本地聲明列表。 當我錯過一個時,它會進入全局名稱空間並由 showglobals() 識別它。起泡、沖洗、重複,直到全局空間保持乾淨。
回复:默認本地與本地人的顯式聲明我可以問一下您檢查這個的工作流程是什麼嗎? 您是否在開發過程中將“Show Globals()”添加到函數的末尾並手動檢查您是否沒有向全局名稱空間添加任何無意的內容? 或者這是您可以通過測試強制執行的內容嗎?
附帶問題:我應該使用 Show Globals 還是 Show Symbols? 即使我故意從我的函數中省略局部變量,我也沒有看到 Show Globals 的任何輸出,但是當我使用 Show Symbols 時,我得到了太多的輸出,以至於我無論如何都不會注意到任何新的列表。
如果有幫助,我在所有腳本文件中都啟用了“名稱默認為此處”模式。
回复:默認本地與本地人的顯式聲明我過去的工作流程是不使用 Names Default To Here,只是保持全局名稱空間清晰。 如果您始終使用此處的默認名稱,則 Show Globals() 可能永遠看不到任何內容。 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
)
);
);回复:默認本地與本地人的顯式聲明謝謝,這很有幫助! 我認為我應該能夠使用您在此處編寫的一些內容來編寫一些自動檢查以確保沒有任何洩漏。
回复:默認本地與本地人的顯式聲明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
}
)
/*回复:默認本地與本地人的顯式聲明對於任何未來的讀者,我最終寫了一個測試助手,我用它來強制所有局部變量都被顯式聲明
/*
* 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, "" )
)
);回复:默認本地與本地人的顯式聲明這對我來說經常出現——這可能非常令人沮喪:
這個腳本破壞了名字(名字逃脫了函數的本地範圍):
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 個堆棧項目,因此會更快地達到 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 範圍的可能性的選項是聲明我的局部變量或使用默認局部變量。 然而,這些都存在一些問題:
默認本地:
- 引用值可能與上下文相關,因為尚未在本地定義的名稱可能回退到此處(如果“名稱默認到此處”關閉)全局然後當前表。 正如文檔中所述,這可能意味著行為不太可預測,因為值取決於上下文。
明確聲明:
- 引用值可能與上下文相關,因為名稱仍然使用此後備行為,直到它們被聲明(如果未在本地名稱中聲明)
- 賦值可能會意外洩漏到 Here 範圍。 也就是說,如果本地名稱聲明中省略了本地名稱,那麼它將污染周圍的 Here 範圍
- 一般來說,這種向外範圍的污染很難追踪。
- 例如,如果您在 For 中調用一個函數,其中使用“i”作為迭代器,並且該函數也有一個使用 i 的 For,但未能將其聲明為本地,這將影響您的外層 For 循環。 誠然,這是明顯的程序員錯誤,但它很容易犯,但很難調試。
在我看來,理想的選擇是能夠聲明類似“嚴格本地”的內容,它始終將不合格的名稱(在分配值和引用值時)視為本地和周圍範圍只能使用合格的名稱訪問。 這將使我不會冒污染周圍範圍的風險,也不會迫使我在依賴這些範圍時進行聲明,從而限制周圍範圍的局部污染。
高級統計建模消費者和市場研究數據存取數據探索和可視化大規模定制回覆:預設本地與顯式本地聲明關於「工作流程」 - 像 #NamespaceInspector 這樣的小助手將有助於追蹤變數。
它們出現在此命名空間還是本地命名空間?
調試完成後,我會將其作為 AddIn 上傳...