Warum ist Scala zurückgekehrt, macht aber keine Pause und fährt fort?

22

In Scala gibt es kein breakoder continue, daher erfordert ein gewisses Loop-Verhalten ein wenig mehr Nachdenken.

Das vorzeitige Beenden einer Schleife erfordert eine Endrekursion, Ausnahmen oder scala.util.control.Breaks(die Ausnahmen verwendet).

Der Grund dafür ist, gotodass es sich um Strömungskonstrukte handelt, die die Strömung verdecken und auf bessere, weniger überraschende Weise erreicht werden können.

Aber es scheint, dass die gleichen Argumente verwendet werden könnten return.

Warum hat Scala bewusst auf breakund verzichtet continue, aber nicht return?

Paul Draper
quelle
1
Ich kann mir vorstellen , dass die Autoren der Sprache Endrekursion wie betrachten die Art und Weise Iteration zu konstruieren. Das kann ich mir vorstellen breakund continuebrauche zusätzliche Aufräummaschinen. OTOH returnist eine Möglichkeit, eine Funktion ordnungsgemäß zu beenden, und Reinigungsmaschinen sind ohnehin bereits vorhanden.
9000,
1
Es gibt breakable { for { break; } }nur einen nachträglichen Gedanken und wahrscheinlich alles andere als effizient.
Joop Eggen
Denn bei Funktionen gibt es eigentlich keinen Grund dafür. In Python ist es dasselbe. Jedes Mal, wenn Sie eine for-Schleife mit break verwenden, können Sie stattdessen eine Funktion schreiben, Ihre Schleife in die Funktion einfügen und return verwenden. Ich kann mir keine Situation vorstellen, in der dies in Bezug auf Clean-Code keine gute Idee ist. Für die Leistung ist eine Bereinigung vielleicht besser, aber die Leistung hat in Scala nicht die höchste Priorität.
Valentinstag
2
Diese Frage scheint
Michael Shaw
3
@PaulDraper: Die Antwort für breakund continueist in Ihrer Frage und im Link in Ihrer Frage enthalten. Die Frage für returnist genau das, worum es bei der von mir verlinkten Frage ging, und wurde zumindest in der am besten bewerteten, akzeptierten Antwort beantwortet. Wenn die beiden Antworten Ihre Frage nicht beantworten, können Sie sie möglicherweise bearbeiten, um sie zu klären.
Michael Shaw

Antworten:

16

Unterbrechen und fortfahren:

In einem Vortrag über Scala gab Martin Odersky 3 Gründe an, keine Pause einzuschließen oder auf Folie 22 fortzufahren:

  • Sie sind ein bisschen zwingend; Verwenden Sie besser viele kleinere Funktionen.
  • Fragen zur Interaktion mit Abschlüssen.
  • Sie werden nicht benötigt!

Und dann sagt er: "Wir können sie rein in den Bibliotheken unterstützen." Auf Folie 23 gibt er Code an, der implementiert wird break. Obwohl ich Scala nicht genau genug kenne, um sicherzugehen, scheint es, dass das kurze Snippet auf dieser Folie alles ist, was zur Implementierung benötigt wird break, und das continuekönnte in Code implementiert werden, der ähnlich kurz ist.

Solche Dinge in Bibliotheken implementieren zu können, vereinfacht die Kernsprache.

In "Programming in Scala, Second Edition" von Martin Odersky, Lex Spoon und Bill Venners wird Folgendes erklärt:

Möglicherweise haben Sie bemerkt, dass breakoder nicht erwähnt wurde continue. Scala lässt diese Befehle aus, weil sie nicht gut mit Funktionsliteralen zusammenpassen. Es ist klar, was continuein einer whileSchleife bedeutet, aber was würde es in einem Funktionsliteral bedeuten? ... Es gibt viele Möglichkeiten, ohne breakund zu programmieren. continueWenn Sie Funktionsliterale nutzen, können diese Alternativen häufig kürzer als der ursprüngliche Code sein.

Rückkehr:

Rückgaben können als ein bisschen zwingend angesehen werden, da Rückgabe ein Verb ist, ein Befehl, etwas zu tun. Sie können aber auch rein funktional / deklarativ gesehen werden: Sie definieren den Rückgabewert der Funktion (auch wenn in einer Funktion mit mehreren Rückgaben nur jeweils eine Teildefinition angegeben wird).

Im selben Buch heißt es return:

Wenn keine explizite returnAnweisung vorliegt, gibt eine Scala-Methode den letzten von der Methode berechneten Wert zurück. Der empfohlene Stil für Methoden besteht darin, explizite und insbesondere mehrfache returnAnweisungen zu vermeiden . Stellen Sie sich stattdessen jede Methode als Ausdruck vor, der einen Wert ergibt, der zurückgegeben wird.

Methoden beenden und geben einen Wert zurück, auch wenn keine returnAnweisung verwendet wird. Daher kann es keine Probleme mit Closures geben, da Closures andernfalls nicht funktionieren würden.

Es kann auch kein Problem geben, gut mit Funktionsliteralen zu verzahnen, da die Funktion ohnehin einen Wert zurückgeben muss.

Michael Shaw
quelle
2
In Bezug auf die Rückkehr scheinen einige milde Gefahren zu bestehen: tpolecat.github.io/2014/05/09/return.html
bbarker
0

Ich denke, die vorherigen Antworten werden den Problemen gerecht, Semantik für Scala breakoder continueauf eine sprachweite Weise zu definieren, mit relativ uneingeschränkten Kontexten.

Ich habe eine kleine Bibliothek geschrieben , die definiert breakund continuein einem engeren Kontext: Iteration über Sequenzen mittels Scala für das Verständnis. Wenn ich mich auf diesen Kontext konzentriere, glaube ich, dass die Semantik eindeutig und leicht zu erklären ist.

Die Bibliothek ist hier verfügbar: https://github.com/erikerlandson/breakable

Hier ist ein einfaches Beispiel, wie es im Code aussieht:

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))
eje
quelle