2016-03-18 6 views
5

Gibt es das Konzept einer Future, die in Scala nicht fehlschlagen kann?Zukunft, die in Scala nicht fehlschlagen kann

Ich bin ein Future[Result] Transformation, die daher ausfall kann ich mit beiden ein Failure und ein Success -INTO einem Future[Option[String]], eine optionale Fehlermeldung von den Erfolg oder Misserfolg Zustände abgeleitet tragen. So weit, ist es gut.

Die Sache ist jetzt, ich möchte formal (d. H. Mit Hilfe des Typsystems) daran denken, dass diese Zukunft immer einen Success halten wird und dass ich den Fehlerfall in Zukunft nicht mehr behandeln muss.

Gibt es eine kluge Möglichkeit, dies zu tun?

+0

Warum brauchen Sie das? edit: Sie ignorieren nur einige: Ergebnis, optionale Fehlermeldung zurückzugeben: String? –

+0

Warum nicht 'Future [Try [T]]'? – cchantep

+0

@cchantep Ich sehe den Punkt damit nicht: Ich würde sowohl mit dem Versagen der Zukunft fertig werden, als auch mit der Tatsache, dass die Zukunft, selbst wenn sie ein Erfolg ist, einen "Fehler" -Wert haben könnte. Ganz im Gegenteil von dem, was ich will. –

Antwort

3

Ist das nicht was Typ-Tagging ist?

scala> type Tagged[U] = { type Tag = U } 
defined type alias Tagged 

scala> type @@[T, U] = T with Tagged[U] 
defined type alias $at$at 

scala> trait OK ; trait Uncertain 
defined trait OK 
defined trait Uncertain 

scala> type Sure[A] = Future[A] @@ OK 
defined type alias Sure 

scala> type Unsure[A] = Future[A] @@ Uncertain 
defined type alias Unsure 

scala> val f = Future.successful(42).asInstanceOf[Sure[Int]] 
f: Sure[Int] = Future(Success(42)) 

dann

scala> object X { def p(f: Sure[_]) = "sure" ; def p(f: Unsure[_])(implicit d: DummyImplicit) = "unsure" } 
defined object X 

scala> X.p(f) 
res1: String = sure 

Es ist nicht sicher, bleiben unter der Karte, natürlich.

+0

Das ist in der Tat ziemlich nett. (a) Kann ich einem solchen 'Sure [A]' - Typ neue Methoden hinzufügen? (b) Kann ich den Compiler irgendwie dazu bringen, mir zu sagen: "Rufe nicht auf" Sure [A] ', dummy"? –

+0

Sie können Erweiterungsmethoden wie gewohnt über Typklassen ausführen. Sie könnten eine Typklasse für ein benutzerdefiniertes "onFailing" erstellen, das nicht für "Sure" gelten würde, indem Sie ein mehrdeutiges Implizit einführen. Ihr normales onFailing würde einfach auf f.onFailure weiterleiten. –

+0

Danke. Ich nehme an, Sie meinten "Sie können Erweiterungsmethoden über ** implizite ** Klassen durchführen." –

6

Sie können das nicht "mit Hilfe von Typ System" tun, weil es keine Möglichkeit für das Typsystem gibt, ein Future wird nicht fehlschlagen, auch wenn Sie versprechen, dass es nicht wird.

Bedenken Sie:

Future { doStuff(); } 
    .recover { case _ => "Failed!" } // Now it always succeeds 
    .map { _ => Seq.empty[String].head } // Now it does not. 

Auch wenn Sie noch weitere Transformationen unmöglich machen würden, sobald die Future erklärt worden ist, immer gelingt, das immer noch nicht helfen, weil die Exception-Handler (oder was auch immer Sie tun, um die ursprüngliche Zukunft in die "immer folgenden" umwandeln könnte werfen.

Update: wie unten in einem Kommentar darauf hingewiesen, über den Code-Snippet ist falsch: das Ergebnis .map ist nicht die gleiche Future als Ergebnis .recover. Der Punkt steht jedoch. Hier ist die richtige Illustration:

+0

Ist '' recover {case _ => "Failed!"} nicht eine schlechte Idee, da Sie 'java.lang.Error' auch fangen? –

+0

@KevinMeredith Ja ... es war nur ein Beispiel für die Illustration. Setzen Sie es nicht in Produktion :) – Dima

+1

Das Ergebnis der Wiederherstellung und das Ergebnis der Karte sind zwei verschiedene Futures, so ändert "es" Referent. Es gibt nichts an sich falsch mit der Behauptung an den Compiler, "Ich weiß etwas, was Sie nicht über das Ergebnis der Wiederherstellung wissen." Vielleicht wird ein Side-Effect-Checker offline ausgeführt. Außerdem müssen Sie nur über "nicht tödliche" Ausnahmen nachdenken. Wenn es InterruptedException auslöst, wird die Zukunft einfach nicht abgeschlossen. Also "Erfolg" ist auf Abschluss angewiesen. –