Durante la visione di un video di YouTube su Tipi di valore in Swift , sono rimasto sorpreso da un semplice esempio ( intorno al minuto 3:00) che è stato dato per dimostrare le insidie dei tipi di riferimento.
Codice di esempio:
let home = House()
let temp = Temperature()
temp.fahrenheit = 75
home.thermostat.temperature = temp.copy()
temp.fahrenheit = 425
home.oven.temperature = temp.copy()
home.oven.bake()
Nel codice precedente, House
e Temperature
sono classi e quindi hanno semantica del tipo di riferimento. La giustificazione per invocare il metodo copy () in più punti è quello di garantire che la modifica della variabile temp
per l'impostazione del forno non modifichi la temperatura del termostato della casa (ovvero impedisca la mutazione non intenzionale dovuta alla semantica di riferimento).
Personalmente trovo questo uno stile di codifica molto strano, ma il presentatore va avanti per diversi minuti su come questa cosiddetta "copia difensiva" sia usata nelle core librairie di Apple per prevenire i bug, quindi mi chiedo se sono stato fare cose sbagliate.
Personalmente, avrei scritto questo seguendo le seguenti linee:
let home = House()
home.thermostat.temperature = Temperature()
home.thermostat.temperature.fahrenheit = 75 //actually I would personally have supplied this as a parameter to the initializer but I'm trying to remain as close to the original code as possible.
home.oven.temperature = Temperature()
home.oven.temperature.fahrenheit = 425
home.oven.bake()
In altre parole, creerei esplicitamente nuove istanze della classe Temperature
chiamando il suo inizializzatore (costruttore) invece di riutilizzare una variabile locale di quel tipo e assegnarne delle copie. Non solo evita l'ultima copia, che è inutile, ma il codice mi sembra più chiaro.
Ora concesso, questo è un esempio banale. Nel caso di una classe complessa con molti membri che condividono gli stessi valori tra le istanze, ricreare un nuovo tipo da zero e assegnare ogni valore più e più volte è un sovraccarico di programmazione. Tuttavia, almeno nella mia esperienza, di solito ho creato inizializzatori o metodi di fabbrica che eseguono questi compiti comuni, quindi devo apportare solo alcune modifiche laddove necessario.
Nei rari casi in cui non si applica quanto sopra, trovo che chiamare esplicitamente un metodo clone () o copy () sia corretto. Solo facendo così raramente, mi trasmette il fatto che sta succedendo qualcosa di speciale (ad esempio, una copia profonda di un albero per esempio).
Pertanto, la mia domanda è: il codice sopra di Apple è una pratica consigliata? E se no, in quali circostanze (a parte le copie profonde) la copia manuale come sopra sarebbe il modo preferito di fare le cose?