Abbiamo già parlatori di REPL in QUESTO articolo, ora traduciamo un post sul blog Apple Swift di pochi giorni fa!

Redefining Identifiers

Il compilatore Swift evita automaticamente una vasta gamma di errori di programmazione, tra cui ambiguità involontarie derivate dalla definizione dello stesso identificatore due volte:

swiftc -
var x = "The Answer"
var x = 42
^D
error: invalid redeclaration of 'x'

Questo ha senso quando si codifica in un editor non interattivo, ma nell’ambiente interattivo REPL è utile avere la possibilità di apportare modifiche in modo semplice. Il REPL è stato specificamente progettato per questo scopo:

  1> var x = "The Answer"
x: String = "The Answer"
  2> var x = 42
x: Int = 42
  3> x + 10
$R0: Int = 52

La definizione più recente sostituisce la definizione esistente per tutti i riferimenti successivi. Come illustrato in precedenza, anche il tipo di definizione può essere modificata durante il processo. Ciò consente una vasta gamma di esperimenti attraverso modifiche successive, in modo del tutto interattivo. Ad esempio, si può iniziare con un’ implementazione ricorsiva di una funzione:

  4> func fib(index: Int) -> Int {
  5. 	if index <= 1 {
  6. 		return 1
  7. 	}
  8. 	return fib(index - 1) + fib(index - 2)
  9. }
 10> fib(40)
$R1: Int = 165580141

Questo è solamente un modo come un altro di scrivere questa funzione. Si può sperimentare con il codice, provando diversi algoritmi e API. Il REPL rende facile definire una nuova e migliore attuazione:

 11> func fib(index: Int) -> Int {
 12. 	var lastValue = 1
 13. 	var currentValue = 1
 14. 	for var iteration = 2; iteration <= index; ++iteration {
 15. 		let newValue = lastValue + currentValue
 16. 		lastValue = currentValue
 17. 		currentValue = newValue
 18. 	}
 19.  	return currentValue
 20. }
 21> fib(40)
$R2: Int = 165580141

Digitando la stessa espressione nel REPL ora esegue la nuova implementazione. Questo è un esempio semplice, ma illustra in modo chiaro il motivo per cui REPL è stato ideato.

E’ possibile ridefinire costanti, variabili e tipi in modo interattivo e la stessa cosa si può fare con le funzioni. Questo solleva una domanda ovvia: come questo interagisce con l’overload in una funzione?  REPL sostituisce solo una definizione esistente quando ha lo stesso nome , come mostrato nell’esempio Fibonacci sopra. Se c’è una funzione con lo stesso nome ma una firma diversa, si definisce solo un nuovo overload. Tenete a mente che Swift consente l’overload anche quando due firme si differenziano solo per il loro tipo di ritorno. Per esempio:

 22> func foo() {
 23. 	println("Foo!")
 24. }
 25> func foo() -> String {
 26. 	return "Foo!"
 27. }
 28> foo()
error: ambiguous use of 'foo'

Le dichiarazioni di cui sopra definiscono due funzioni distinte che devono essere chiamate in un modo in cui solo uno degli overload disponibili può dedurre che tipo di valore restituire:

 28> var foo: String = foo()
foo: String = "Foo!"
 29> foo() as Void
Foo!

Catturare Definizioni

Ogni riga di codice che è già stato compilato dal REPL conserva il suo riferimento alla precedente definizione. È come se la nuova definizione oscuri quella vecchia, ma non la elimini del tutto. Di seguito viene illustrato in pratica il suo funzionamento:

 30> var message = "Hello, World!"
message: String = "Hello, World!"
 31> func printMessage() {
 32. 	println(message)
 33. }
 34> printMessage()
Hello, World!
 35> message = "Goodbye"
 36> printMessage()
Goodbye
 37> var message = "New Message"
 38> printMessage()
Goodbye
 39> println(message)
New Message

Nella linea 30 viene dichiarata una variabile denominata “messaggio con un saluto”. Le linee 31-33 dichiarano una funzione denominata printMessage () che stampa il contenuto della variabile dichiarata sulla linea 30. la linea 34 chiama il metodo e produce il risultato previsto. Finora è estremamente semplice.

La linea 35 assegna un nuovo valore alla variabile dichiarata in linea 30 e la linea 36 che consente di stampare questo nuovo valore come previsto. D’altra parte, la linea 37 dichiara una nuova variabile con lo stesso nome. Questo nasconde efficacemente la variabile originale da ogni codice successivo, ma la chiamata sulla linea 38 richiama una funzione che è stata compilato prima della ridefinizione. La funzione conserva il suo significato originale e ne stampa il valore della variabile originale.

 

REPL concede la libertà di ridefinire un identificatore senza restrizioni, mentre i riferimenti precedenti sono stati compilati con forti controlli semantici .