Ri: Locale predefinito vs Dichiarazione esplicita di localiMi piace l'elenco delle dichiarazioni locali esplicite. Quando ne perdo uno, arriva nello spazio dei nomi globale e showglobals() lo identifica.Insaponare, risciacquare, ripetere fino a quando lo spazio globale rimane pulito.
Ri: Locale predefinito vs Dichiarazione esplicita di localiPosso chiederti qual è il tuo flusso di lavoro per verificarlo? Aggiungi "Show Globals ()" alla fine delle tue funzioni durante lo sviluppo e controlli manualmente di non aver aggiunto nulla di involontario allo spazio dei nomi globale? O è qualcosa che puoi imporre con i test?
Domanda a margine: è Show Globals o Show Symbols che dovrei usare? Non vedo alcun output da Show Globals anche quando ometto intenzionalmente variabili locali dalle mie funzioni, ma quando utilizzo Show Symbols ottengo così tanto output che non noterei comunque alcun nuovo elenco.
Se aiuta, ho attivato la modalità "Nomi predefiniti per qui" in tutti i miei file di script.
Ri: Locale predefinito vs Dichiarazione esplicita di localiIl mio flusso di lavoro in passato consisteva nel non utilizzare Names Default To Here e mantenere semplicemente chiaro lo spazio dei nomi globale. Show Globals() probabilmente non vede mai nulla se usi sempre Names Default To Here. Show Symbols() è rumoroso perché riporta informazioni attraverso lo stack di chiamate se lo usi in una funzione profondamente nidificata. Ecco il mio esempio di flusso di lavoro, rielaborato per utilizzare Nomi predefiniti per qui e Mostra simboli. Eseguilo così com'è e non perde. riga di commento 17 (g3) e genererà un errore perché g3 è inserito nello spazio dei nomi "qui". L'uso di g2 nell'esempio evidenzia un brutto problema; locale predefinito risolve quel problema ma aggiunge i problemi che hai notato. Potrei provare a tornare a Default Local in un progetto futuro. Penso che potrebbe essere una scelta più sicura per me; È più probabile che lasci una variabile fuori dai locali espliciti piuttosto che leggere una variabile prima di scriverla.
Penso che tu stia cercando di fare un test più dettagliato di me; Provo solo (globali o qui) alla fine. Potresti essere in grado di utilizzare alcune di queste idee se hai bisogno di testare la perdita dello spazio dei nomi in ogni funzione.
// **** 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
)
);
);Ri: Locale predefinito vs Dichiarazione esplicita di localiGrazie questo è molto utile! Penso che dovrei essere in grado di utilizzare parte di ciò che hai scritto qui per scrivere alcuni controlli automatici che assicurino che non vi siano perdite.
Ri: Locale predefinito vs Dichiarazione esplicita di localiInoltre c'è qualcosa di strano in DEFAULT LOCAL.In realtà legge lo script e crea le assegnazioni locali in base alla sua interpretazione di quali variabili vengono create.Ci sono più di pochi modi per rovinare tutto. Quello che probabilmente vedo più spesso dalle persone è quando provano a creare dinamicamente un nome di variabile.Il che direi che non è fantastico da fare e non puoi nemmeno dichiararlo esplicitamente, quindi è più o meno lo stesso.
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
}
)
/*Ri: Locale predefinito vs Dichiarazione esplicita di localiPer tutti i futuri lettori, alla fine ho scritto un test helper che utilizzo per imporre che tutti i locali siano esplicitamente dichiarati
/*
* 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, "" )
)
);Ri: Locale predefinito vs Dichiarazione esplicita di localiQuesto mi è venuto in mente abbastanza spesso - può essere molto frustrante:
questo script cancella i nomi (i nomi sfuggono all'ambito locale della funzione):
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 )Ecco una soluzione, ma il problema con questa soluzione è che si tratta tecnicamente di due chiamate di funzione (conta come 2 elementi dello stack, quindi raggiungerà il limite di 225 stack più velocemente)
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 )Sarebbe bello se la direttiva "Default Local" non fosse una direttiva del tempo di analisi ma un flag di runtime, ma forse ciò che sta accadendo è che la risoluzione del nome viene eseguita al momento dell'analisi, rendendo così discutibili le regole di ricerca del nome in fase di esecuzione .
Locale predefinito vs Dichiarazione esplicita di localiCiao, sto cercando di capire come limitare al meglio il mio rischio per quanto riguarda l'ambito locale nelle funzioni. Nella mia comprensione, le mie opzioni per limitare il potenziale di inquinare l'ambito Here dall'interno di un'esecuzione di Function sono dichiarare le mie variabili locali o utilizzare Default Local. Tuttavia, ognuno di questi presenta alcuni problemi:
Locale predefinito:
- I valori di riferimento possono dipendere dal contesto, poiché i nomi che non sono stati definiti localmente fanno fallback a Here quindi possibilmente (se Names Default To Here è off) Global then current table. Come notato nei documenti, ciò può significare che il comportamento è meno prevedibile in quanto i valori dipendono dal contesto.
Dichiarazione esplicita:
- I valori di riferimento possono dipendere dal contesto, poiché i nomi utilizzano ancora questo comportamento di fallback fino a quando non vengono dichiarati se non dichiarati nei nomi locali
- Le assegnazioni possono fuoriuscire accidentalmente nell'ambito Here. Cioè, se un nome che dovrebbe essere locale viene omesso dalle dichiarazioni del nome locale, inquinerà l'ambito Here circostante
- Generalmente questo inquinamento di portata esterna è difficile da rintracciare.
- Ad esempio, se chiami una funzione in un For in cui usi "i" come iteratore e quella funzione ha anche un For che usa i e non riesce a dichiararlo come locale, questo influenzerà il tuo ciclo For esterno. Certo, questo è un ovvio errore del programmatore, ma è facile da realizzare ed è difficile eseguire il debug.
Nella mia mente, l'opzione ideale sarebbe in grado di dichiarare qualcosa come "Strict Local", che tratterebbe sempre i nomi non qualificati (sia durante l'assegnazione di valori che di riferimento) poiché gli ambiti locali e circostanti sarebbero accessibili solo con nomi qualificati. Ciò mi consentirebbe di non rischiare di inquinare gli ambiti circostanti oltre a costringermi a dichiarare quando dipendo da tali ambiti, limitando così l'inquinamento locale dagli ambiti circostanti.
Modellazione statistica avanzataConsumatori e ricerche di mercatoAccesso ai datiEsplorazione e visualizzazione dei datiPersonalizzazione di massaRe: Dichiarazione predefinita locale vs dichiarazione esplicita di variabili localiPer quanto riguarda il "flusso di lavoro": un piccolo aiuto come #NamespaceInspector sarà di grande aiuto per tenere traccia delle variabili.
Vengono visualizzati in uno spazio dei nomi Here o in uno spazio dei nomi locale?
Una volta completato il debug, lo caricherò come componente aggiuntivo...