L'uso di blocchi di ambito interni in uno stile di funzione non è corretto?


10

Esistono alcuni casi (piuttosto rari) in cui esiste il rischio di:

  • riutilizzare una variabile che non è prevista per essere riutilizzata (vedi esempio 1),

  • o usando una variabile invece di un'altra, semanticamente chiusa (vedi esempio 2).

Esempio 1:

var data = this.InitializeData();
if (this.IsConsistent(data, this.state))
{
    this.ETL.Process(data); // Alters original data in a way it couldn't be used any longer.
}

// ...

foreach (var flow in data.Flows)
{
    // This shouldn't happen: given that ETL possibly altered the contents of `data`, it is
    // not longer reliable to use `data.Flows`.
}

Esempio 2:

var userSettingsFile = SettingsFiles.LoadForUser();
var appSettingsFile = SettingsFiles.LoadForApp();

if (someCondition)
{
    userSettingsFile.Destroy();
}

userSettingsFile.ParseAndApply(); // There is a mistake here: `userSettingsFile` was maybe
                                  // destroyed. It's `appSettingsFile` which should have
                                  // been used instead.

Questo rischio può essere mitigato introducendo un ambito:

Esempio 1:

// There is no `foreach`, `if` or anything like this before `{`.

{
    var data = this.InitializeData();
    if (this.IsConsistent(data, this.state))
    {
        this.ETL.Process(data);
    }
}

// ...

// A few lines later, we can't use `data.Flows`, because it doesn't exist in this scope.

Esempio 2:

{
    var userSettingsFile = SettingsFiles.LoadForUser();

    if (someCondition)
    {
        userSettingsFile.Destroy();
    }
}

{
    var appSettingsFile = SettingsFiles.LoadForApp();

    // `userSettingsFile` is out of scope. There is no risk to use it instead of
    // `appSettingsFile`.
}

Sembra sbagliato? Eviteresti tale sintassi? È difficile da capire per i principianti?


7
Potresti sostenere che ogni "blocco dell'ambito" indipendente dovrebbe invece essere il suo metodo o la sua funzione?
Dan Pichelman,

Direi "spesso" non ben implementato come potrebbe essere (ma probabilmente non è un problema di "progettazione"). A volte, in base alla progettazione, è inevitabile (ad esempio, scoping di eccezione / risorse).
Giustino

Risposte:


35

Se la tua funzione è così lunga che non riesci più a riconoscere alcun effetto collaterale indesiderato o il riutilizzo illegale delle variabili, allora è tempo di dividerlo in funzioni più piccole, il che rende inutile un ambito interno.

A sostegno di questa esperienza personale: alcuni anni fa ho ereditato un progetto legacy C ++ con ~ 150K righe di codice e conteneva alcuni metodi usando esattamente questa tecnica. E indovina un po '- tutti quei metodi erano troppo lunghi. Dato che abbiamo riformattato la maggior parte di quel codice, i metodi sono diventati sempre più piccoli e sono quasi sicuro che non ci siano più metodi di "ambito interno" rimanenti; semplicemente non sono necessari.


4
Ma perché è male? Anche avere molte funzioni nominate è fonte di confusione.
Kris Van Bael,

1
+1 Esatto, se hai bisogno di un ambito, probabilmente stai eseguendo una particolare azione che può essere estratta in una funzione. Kris, non si tratta di creare molte e molte funzioni, è che quando si verificano questi casi (in cui l'ambito di un blocco potrebbe essere in conflitto con quello di un altro) che di solito avrebbe dovuto essere usata una funzione. Lo vedo sempre in altre lingue (vale a dire JavaScript, con IIFE anziché semplici "vecchie funzioni").
Benjamin Gruenbaum,

10
@KrisVanBael: "Avere molte funzioni nominate è anche fonte di confusione" - se usi nomi descrittivi, è vero il contrario. La creazione di funzioni troppo grandi è il motivo principale per cui il codice diventa difficile da mantenere e ancora più difficile da estendere.
Doc Brown,

2
Se ci sono così tante funzioni che nominarle distintamente diventa un problema, forse alcune di esse possono essere raggruppate in un nuovo tipo in quanto potrebbero avere una significativa indipendenza dal loro corpo di funzione originale. Alcuni potrebbero essere così strettamente correlati da poter essere eliminati. Improvvisamente, non ci sono molte funzioni.
Giustino

3
Ancora non convinto. Spesso le funzioni lunghe sono davvero pessime. Ma dire che ogni esigenza di ambito richiede una funzione separata è troppo bianco e nero per me.
Kris Van Bael,

3

È molto più facile per un principiante (e qualsiasi programmatore) pensare a:

  • non usare una variabile che non è rilevante

che pensare a:

  • aggiungere strutture di codice volte a impedirsi di non utilizzare una variabile non pertinente.

Inoltre, dal punto di vista del lettore, tali blocchi non hanno un ruolo apparente: rimuoverli non ha alcun impatto sull'esecuzione. Il lettore può grattarsi la testa cercando di indovinare ciò che il programmatore voleva ottenere.


2

L'uso di un ambito è tecnicamente corretto. Ma se vuoi rendere il tuo codice più leggibile, dovresti estrarre quella parte in un altro metodo e dargli un nome completo di significato. In questo modo puoi dare un ambito alle tue variabili e anche dare un nome al tuo compito.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.