Perché Scala ha un ritorno ma non si rompe e continua


22

Scala non ha breako continue, quindi alcuni comportamenti in loop richiedono un po 'più di pensiero.

La fine anticipata di un ciclo richiede ricorsione della coda, eccezioni o scala.util.control.Breaks(che utilizza eccezioni).

La logica di ciò è che, come goto, sono costrutti di flusso che oscurano il flusso e possono essere realizzati in modi migliori e meno sorprendenti.

Ma sembra che si possano usare quegli stessi argomenti return.

Perché Scala ha deliberatamente omesso breake continue, ma non return?


1
Posso immaginare che gli autori del linguaggio considerino la ricorsione della coda come il modo per costruire l'iterazione. Posso immaginarlo breake ho continuebisogno di altri macchinari per la pulizia. OTOH returnè un modo per terminare in modo ordinato una funzione e qualsiasi macchinario di pulizia è già lì comunque.
9000,

1
C'è breakable { for { break; } }solo un ripensamento, e probabilmente lungi dall'essere efficiente.
Joop Eggen,

Perché con le funzioni non c'è in realtà alcun motivo per questo. È lo stesso in Python. Ogni volta che usi un for-loop con break, puoi invece scrivere una funzione, inserire il tuo loop nella funzione e usare return. Non riesco a pensare a una situazione in cui questa non è una buona idea per quanto riguarda il codice pulito. Per quanto riguarda le prestazioni, una pulizia potrebbe essere migliore, ma le prestazioni non hanno la massima priorità in scala.
valenterry,

2
Questa domanda sembra avere una risposta qui: stackoverflow.com/questions/3770989/…
Michael Shaw,

3
@PaulDraper: la risposta per breaked continueè contenuta nella tua domanda e nel link nella tua domanda. La domanda returnè esattamente per quale sia la domanda che ho collegato e alla quale è stata data risposta, almeno nella risposta accettata dai votati più in alto. Se le due risposte messe insieme non rispondono alla tua domanda, forse potresti modificarla per chiarirla.
Michael Shaw,

Risposte:


16

Rompere e continuare:

In un discorso su Scala , Martin Odersky ha fornito 3 motivi per non includere l'interruzione o continuare sulla diapositiva 22:

  • Sono un po 'imperativi; usare meglio molte funzioni più piccole.
  • Problemi su come interagire con le chiusure.
  • Non sono necessari!

E poi dice: "Possiamo supportarli solo nelle biblioteche". Nella diapositiva 23, fornisce il codice che implementa break. Sebbene non conosca abbastanza bene Scala per essere certi, sembra che lo snippet breve su quella diapositiva sia tutto ciò che è necessario per implementare breake che continuepotrebbe essere implementato in un codice che è allo stesso modo breve.

Essere in grado di implementare cose come questa nelle biblioteche semplifica il linguaggio di base.

In "Programming in Scala, Second Edition", di Martin Odersky, Lex Spoon e Bill Venners, viene fornita la seguente spiegazione:

Potresti aver notato che non è stato menzionato breako continue. Scala esclude questi comandi perché non si adattano bene ai letterali delle funzioni ... È chiaro cosa continuesignifica all'interno di un whileloop, ma cosa significherebbe all'interno di una funzione letterale? ... Esistono molti modi per programmare senza breake continue, e se si sfruttano i letterali delle funzioni, queste alternative possono spesso essere più brevi del codice originale.

Ritorno:

I rendimenti potrebbero essere considerati un po 'imperativi nello stile, poiché return è un verbo, un comando per fare qualcosa. Ma possono anche essere visti in un modo puramente funzionale / dichiarativo: definiscono quale sia il valore di ritorno della funzione (anche se, in una funzione con più ritorni, danno solo una definizione parziale).

Nello stesso libro, dicono quanto segue su return:

In assenza di returnun'istruzione esplicita , un metodo Scala restituisce l'ultimo valore calcolato dal metodo. Lo stile raccomandato per i metodi è infatti quello di evitare di avere dichiarazioni esplicite, e soprattutto multiple return. Invece, pensa a ciascun metodo come un'espressione che produce un valore, che viene restituito.

I metodi terminano e restituiscono un valore, anche se returnun'istruzione non viene utilizzata, quindi non possono esserci problemi con le chiusure, poiché altrimenti le chiusure non funzionerebbero.

Inoltre, non può esserci alcun problema con il meshing corretto con i letterali delle funzioni, poiché la funzione deve comunque restituire un valore.


2
Per quanto riguarda il ritorno, sembrano esserci alcuni lievi pericoli: tpolecat.github.io/2014/05/09/return.html
bbarker

0

Penso che le risposte precedenti rendano giustizia ai problemi di definire la semantica per breako continuein una lingua per Scala, con contesti relativamente non vincolati.

Ho scritto una piccola biblioteca che definisce breake continuein un contesto più limitato: iterazione su sequenze tramite Scala per comprensione. Concentrandomi su quel contesto, credo che la semantica diventi chiara e facile da ragionare.

La libreria è disponibile qui: https://github.com/erikerlandson/breakable

Ecco un semplice esempio di come appare nel codice:

scala> import com.manyangled.breakable._
import com.manyangled.breakable._

scala> val bkb2 = for {
     |   (x, xLab) <- Stream.from(0).breakable   // create breakable sequence with a method
     |   (y, yLab) <- breakable(Stream.from(0))  // create with a function
     |   if (x % 2 == 1) continue(xLab)          // continue to next in outer "x" loop
     |   if (y % 2 == 0) continue(yLab)          // continue to next in inner "y" loop
     |   if (x > 10) break(xLab)                 // break the outer "x" loop
     |   if (y > x) break(yLab)                  // break the inner "y" loop
     | } yield (x, y)
bkb2: com.manyangled.breakable.Breakable[(Int, Int)] = com.manyangled.breakable.Breakable@34dc53d2

scala> bkb2.toVector
res0: Vector[(Int, Int)] = Vector((2,1), (4,1), (4,3), (6,1), (6,3), (6,5), (8,1), (8,3), (8,5), (8,7), (10,1), (10,3), (10,5), (10,7), (10,9))
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.