回复:默认本地与本地人的显式声明我喜欢显式的本地声明列表。 当我错过一个时,它会进入全局名称空间并由 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 上传...