Betreff: Default Local vs. explizite Deklaration von LocalsIch mag die explizite lokale Deklarationsliste. Wenn ich einen übersehe, landet er im globalen Namensraum und wird von showglobals() identifiziert.Aufschäumen, ausspülen, wiederholen, bis der globale Raum sauber bleibt.
Betreff: Default Local vs. explizite Deklaration von LocalsDarf ich fragen, wie Ihr Workflow ist, um dies zu überprüfen? Fügen Sie während der Entwicklung "Show Globals()" am Ende Ihrer Funktionen hinzu und überprüfen Sie manuell, ob Sie dem globalen Namespace nichts unbeabsichtigtes hinzugefügt haben? Oder kann man das mit Tests durchsetzen?
Nebenfrage: Ist es Show Globals oder Show Symbols, die ich verwenden sollte? Ich sehe keine Ausgabe von Show Globals, selbst wenn ich absichtlich lokale Variablen aus meinen Funktionen weglasse, aber wenn ich Show Symbols verwende, bekomme ich so viel Ausgabe, dass ich sowieso keine neuen Auflistungen bemerken würde.
Wenn es hilft, habe ich in allen meinen Skriptdateien den Modus "Namen standardmäßig hierher" aktiviert.
Betreff: Default Local vs. explizite Deklaration von LocalsMein Arbeitsablauf in der Vergangenheit bestand darin, Names Default To Here nicht zu verwenden und nur den globalen Namespace klar zu halten. Show Globals() sieht wahrscheinlich nie etwas, wenn Sie immer Names Default To Here verwenden. Show Symbols() ist verrauscht, da es Informationen über den Aufrufstapel nach oben meldet, wenn Sie es in einer tief verschachtelten Funktion verwenden. Hier ist mein Workflow-Beispiel, das überarbeitet wurde, um Names Default To Here und Show Symbols zu verwenden. Führen Sie es so aus, wie es ist, und es leckt nicht. kommentieren Sie Zeile 17 (g3) und es wird ein Fehler ausgegeben, da g3 in den Namensraum „here“ eingefügt wird. Die Verwendung von g2 im Beispiel hebt ein hässliches Problem hervor; standardmäßig lokal löst dieses Problem, fügt aber die von Ihnen festgestellten Probleme hinzu. Ich könnte versuchen, in einem zukünftigen Projekt wieder auf Default Local umzuschalten. Ich denke, es könnte eine sicherere Wahl für mich sein; Es ist wahrscheinlicher, dass ich eine Variable aus den expliziten Lokalen herauslasse, als eine Variable zu lesen, bevor ich sie schreibe.
Ich denke, Sie versuchen, einen genaueren Test durchzuführen als ich; Ich teste (globals oder hier) erst am Ende. Möglicherweise können Sie einige dieser Ideen verwenden, wenn Sie in jeder Funktion auf Namespace-Lecks testen müssen.
// **** 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
)
);
);Betreff: Default Local vs. explizite Deklaration von LocalsDanke das ist sehr hilfreich! Ich denke, dass ich in der Lage sein sollte, einiges von dem, was Sie hier geschrieben haben, zu verwenden, um einige automatische Überprüfungen zu schreiben, die sicherstellen, dass nichts durchsickert.
Betreff: Default Local vs. explizite Deklaration von LocalsAußerdem ist DEFAULT LOCAL etwas seltsam.Es liest das Skript tatsächlich und erstellt die lokalen Zuweisungen basierend auf seiner Interpretation dessen, welche Variablen erstellt werden.Es gibt mehr als ein paar Möglichkeiten, dies zu vermasseln. Das, was ich wahrscheinlich am häufigsten von Leuten sehe, ist, wenn sie versuchen, einen Variablennamen dynamisch zu erstellen.Was ich sagen würde, ist nicht großartig, und Sie könnten es auch nicht explizit sagen, also ist es irgendwie dasselbe.
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
}
)
/*Betreff: Default Local vs. explizite Deklaration von LocalsFür alle zukünftigen Leser habe ich schließlich einen Testhelfer geschrieben, mit dem ich erzwinge, dass alle Einheimischen explizit deklariert werden
/*
* 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, "" )
)
);Betreff: Standardmäßige lokale vs. explizite Deklaration von EinheimischenDas ist mir ziemlich oft passiert – es kann sehr frustrierend sein:
Dieses Skript blockiert die Namen (Namen entziehen sich dem lokalen Gültigkeitsbereich der Funktion):
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 )Hier ist eine Lösung, aber das Problem bei dieser Lösung besteht darin, dass es sich technisch gesehen um zwei Funktionsaufrufe handelt (zählt als 2 Stapelelemente und erreicht somit schneller die 225-Stack-Grenze).
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 )Es wäre schön, wenn die „Default Local“-Direktive keine Parse-Zeit-Direktive, sondern ein Laufzeit-Flag wäre, aber vielleicht passiert ja, dass die Namensauflösung zur Parse-Zeit durchgeführt wird, wodurch die Regeln für die Laufzeit-Namensuche hinfällig werden .
Standardmäßige lokale vs. explizite Deklaration von EinheimischenHallo, ich versuche zu verstehen, wie ich mein Risiko im Hinblick auf den lokalen Umfang in Funktionen am besten begrenzen kann. Nach meinem Verständnis bestehen meine Optionen zur Begrenzung der potenziellen Verschmutzung des Here-Bereichs innerhalb einer Funktionsausführung darin, entweder meine lokalen Variablen zu deklarieren oder Default Local zu verwenden. Allerdings weist jedes davon einige Probleme auf:
Standardlokal:
- Verweisende Werte können kontextabhängig sein, da Namen, die nicht lokal definiert wurden, auf „Hier“ zurückgreifen und dann möglicherweise (wenn „Namen standardmäßig hier“ deaktiviert ist) auf „Global“ und dann auf die aktuelle Tabelle zurückgreifen. Wie in den Dokumenten erwähnt, kann dies bedeuten, dass das Verhalten weniger vorhersehbar ist, da die Werte vom Kontext abhängen.
Explizite Erklärung:
- Verweisende Werte können kontextabhängig sein, da Namen dieses Fallback-Verhalten weiterhin verwenden, bis sie deklariert werden, sofern sie nicht in den lokalen Namen deklariert sind
- Zuweisungen können versehentlich in den Here-Bereich gelangen. Das heißt, wenn ein Name, der lokal sein soll, in den lokalen Namensdeklarationen weggelassen wird, wird dadurch der umgebende Here-Bereich verschmutzt
- Im Allgemeinen ist diese äußere Verschmutzung schwer aufzuspüren.
- Wenn Sie beispielsweise eine Funktion in einem For aufrufen, in dem Sie „i“ als Iterator verwenden, und diese Funktion auch über ein For verfügt, das i verwendet und es nicht als lokal deklariert, wirkt sich dies auf Ihre äußere For-Schleife aus. Zugegeben, das ist ein offensichtlicher Programmierfehler, aber er ist einfach zu machen und schwer zu debuggen.
Meiner Meinung nach wäre die ideale Option die Möglichkeit, so etwas wie „Strict Local“ zu deklarieren, das immer unqualifizierte Namen behandelt (sowohl beim Zuweisen von Werten als auch beim Referenzieren von Werten), da lokale und umgebende Bereiche nur mit qualifizierten Namen zugänglich wären. Dies würde es mir ermöglichen, nicht zu riskieren, umliegende Bereiche zu verschmutzen, und mich außerdem dazu zwingen, anzugeben, wann ich von diesen Bereichen abhängig bin, wodurch die lokale Verschmutzung durch umliegende Bereiche begrenzt wird.
Erweiterte statistische ModellierungVerbraucher- und MarktforschungDatenzugriffDatenexploration und -visualisierungMassenanpassungBetreff: Standardmäßige lokale vs. explizite Deklaration von lokalen VariablenBezüglich „Workflow“ – Ein kleiner Helfer wie dieser #NamespaceInspector wird sehr dabei helfen, den Überblick über Variablen zu behalten.
Werden sie in einem Here-Namespace oder in einem lokalen Namespace angezeigt?
Sobald das Debuggen abgeschlossen ist, werde ich es als AddIn hochladen ...