C'è un motivo per non modificare i valori dei parametri passati per valore?

9

Esistono argomenti oggettivi, supportati da ingegneria del software a favore o contro la modifica dei valori dei parametri di valore nel corpo di una funzione?

Uno sputo ricorrente (per lo più di buon divertimento) nella mia squadra è se i parametri passati o meno devono essere modificati. Un paio di membri del team sono fermamente convinti che i parametri non dovrebbero mai essere assegnati, in modo che il valore originariamente passato alla funzione possa sempre essere interrogato. Non sono d'accordo e ritengo che i parametri non siano altro che variabili locali inizializzate dalla sintassi di chiamare il metodo; se il valore originale di un parametro di valore è importante di una variabile locale può essere dichiarato per memorizzare esplicitamente questo valore. Non sono sicuro che nessuno di noi ha un ottimo supporto per la nostra posizione.

Si tratta di un conflitto religioso non risolvibile o ci sono buone ragioni per l'ingegneria del software in entrambe le direzioni?

Nota: la questione del principio rimane indipendentemente dai dettagli di implementazione della lingua specifica. In JavaScript, ad esempio, dove l'elenco degli argomenti è sempre dinamico, i parametri possono essere considerati come zucchero sintattico per l'inizializzazione della variabile locale dall'oggetto arguments . Anche così, uno potrebbe considerare gli identificatori dichiarati dai parametri come "speciali" perché catturano ancora il passaggio di informazioni dal chiamante al chiamato.

    
posta Joshua Honig 16.04.2018 - 16:49
fonte

3 risposte

15

I disagree and hold that parameters are nothing more than local variables initialized by the syntax of calling the method

Adotto una terza posizione: i parametri sono come le variabili locali: entrambi devono essere considerati come immutabili per impostazione predefinita. Quindi le variabili vengono assegnate una sola volta e poi lette solo da, non alterate. Nel caso di cicli, for each (x in ...) , la variabile è immutabile nel contesto di ciascuna iterazione. Le ragioni di questo sono:

  1. rende il codice più facile da "eseguire nella mia testa",
  2. consente nomi più descrittivi per le variabili.

Di fronte a un metodo con un gruppo di variabili che vengono assegnate e quindi non cambiano, posso concentrarmi sulla lettura del codice, piuttosto che cercare di ricordare il valore corrente di ciascuna di queste variabili.

Di fronte allo stesso metodo, questa volta con meno variabili, ma che cambiano valore continuamente, ora devo ricordare lo stato corrente di quelle variabili, oltre a lavorare su ciò che sta facendo il codice.

Nella mia esperienza, il primo è molto più facile sul mio povero cervello. Altri, più intelligenti, più popolari di me potrebbero non avere questo problema, ma mi aiuta.

Come per l'altro punto:

double Foo(double r)
{
    r = r * r;
    r = Math.Pi * r;
    return r;
}

vs

double Foo(int r)
{
    var rSquared = r * r;
    var area = Math.Pi * rSquared;
    return area;
} 

Esempi controversi, ma a mio avviso è molto più chiaro di quello che succede nel secondo esempio a causa dei nomi delle variabili: trasmettono molte più informazioni al lettore di quella massa di r di fare nel primo esempio .

    
risposta data 16.04.2018 - 17:06
fonte
4

Is this a non-resolvable religious conflict, or are there good, objective software engineering reasons in either direction?

Questa è una cosa che mi piace molto del C ++ (ben scritto): puoi vedere cosa aspettarti. const string& x1 è un riferimento costante, string x2 è una copia e const string x3 è una copia costante. conosco cosa accadrà nella funzione. x2 sarà modificato, perché se così non fosse, non ci sarebbe motivo di renderlo non const.

Quindi, se hai una lingua che consente , dichiara cosa stai per fare con i parametri. Questa dovrebbe essere la scelta migliore per tutte le persone coinvolte.

Se la tua lingua non lo consente, temo che non ci sia una soluzione di proiettili d'argento. Entrambi sono possibili. L'unica linea guida è il principio di minima sorpresa. Prendi un approccio e seguilo nel tuo codice base, non mischiarlo.

    
risposta data 16.04.2018 - 17:11
fonte
1

Sì, è un "conflitto religioso", a parte il fatto che Dio non legge i programmi (per quanto ne so), quindi è declassato in un conflitto di leggibilità che diventa una questione di giudizio personale. E certamente l'ho fatto e l'ho visto, in entrambi i modi. Ad esempio,

void propagate(OBJECT *object, double t0, double dt) {
  double t = t0; /* local copy of t0 to avoid changing its value */
  while ( whatever) {
    timestep_the_object(...);
    t += dt; }
  return; }

Quindi, proprio a causa dell'argomento name t0 , probabilmente sceglierei di non cambiare il suo valore. Ma supponiamo invece, abbiamo semplicemente cambiato il nome dell'argomento in tNow , o qualcosa del genere. Quindi mi sarei dimenticato più di una copia locale e ho scritto tNow + = dt; per quell'ultima istruzione.

Ma al contrario, supponiamo di sapere che il cliente per cui è stato scritto il programma sta per assumere alcuni nuovi programmatori con pochissima esperienza, che leggere e lavorare su quel codice. Quindi probabilmente mi preoccuperei di confonderli con il valore pass-by-value, mentre le loro menti sono impegnate al 100% nel tentativo di digerire tutta la logica aziendale. Quindi in questo tipo di casi dichiarerei sempre una copia locale di qualsiasi argomento che verrà modificato, indipendentemente dal fatto che sia più o meno leggibile per me.

Le risposte a questi tipi di domande di stile emergono con l'esperienza e raramente hanno una risposta religiosa canonica. Chiunque pensi che ci sia una risposta sola (e che lui lo conosca) probabilmente ha bisogno di un po 'più di esperienza.

    
risposta data 17.04.2018 - 12:56
fonte

Leggi altre domande sui tag