2009-08-13 5 views
11

Nachdem ich ein paar Scala-Tools geschrieben habe, versuche ich, den besten Weg zu finden, meinen Code zu arrangieren - besonders implicits. Ich habe 2 Ziele:Wie soll ich implicits in meiner Scala-Anwendung organisieren?

  • Manchmal möchte ich in der Lage sein, nur die implicits zu importieren, die ich bitte.
  • Othertimes möchte ich nur alles importieren.

zu vermeiden Um die implicits duplizieren, ich habe mit dieser Struktur kommen (scalaz ähnlich wie angeordnet ist):

case class StringW(s : String) { 
    def contrived = s + "?" 
} 

trait StringWImplicits { 
    implicit def To(s : String) = StringW(s) 
    implicit def From(sw : StringW) = sw.s 
} 

object StringW extends StringWImplicits 

// Elsewhere on Monkey Island 

object World extends StringWImplicits with ListWImplicits with MoreImplicits 

Dies erlaubt es mir nur

import StringW._ // Selective import 

oder (in den meisten Fällen)

import World._. // Import everything 

Wie funktioniert alle anderen tun es?

+0

Was ist daran implizit? –

+0

Ich nehme an, dass alle Definitionen in ihm implizit sein sollten? –

+0

Jetzt repariert, danke! –

Antwort

4

Ich denke, dass implicit Konvertierungen gefährlich sind, wenn Sie nicht wissen, woher sie kommen. In meinem Fall habe ich meine implicit s in einer Conversions Klasse und import es so nah an die Verwendung wie möglich

def someMethod(d: Date) ; Unit { 
    import mydate.Conversions._ 
    val tz = TimeZone.getDefault 
    val timeOfDay = d.getTimeOfDay(tz) //implicit used here 
    ... 
} 

Ich bin nicht sicher Ich mag implicits aus verschiedenen trait s für die gleichen „vererben“ Grund war schlechte Java-Praxis zu implementieren interface, so dass Sie ihre Konstanten direkt verwenden können (statische Importe sind stattdessen bevorzugt).

+1

Nicht, dass ich diesem Rat notwendigerweise widerspreche, aber es könnte darauf hingewiesen werden, dass Implits nützlich sind, weil sie, na ja, implizit sind. Wenn Sie jedes Mal vor der Verwendung eine import-Anweisung hinzufügen, gibt es vielleicht ein Argument, dass Sie die implizite Konvertierung auch explizit angewendet haben könnten. –

+0

Ich habe gerade über diesen Punkt nachgedacht, als ich gestern nach Hause ging (und ich folge es nicht immer selbst)! Ich bevorzuge jedoch immer noch Importe über die Vererbung. –

1

Normalerweise hatte ich implicit Konvertierungen in einem Objekt, das deutlich signalisiert, dass das, was es importiert wird, eine implicit Umwandlung ist. Wenn ich beispielsweise eine Klasse com.foo.bar.FilthyRichString habe, würden die impliziten Konvertierungen in com.foo.bar.implicit.FilthyRichStringImplicit gehen. Ich weiß, dass die Namen ein bisschen lang sind, aber deshalb haben wir IDEs (und die Scala-IDE-Unterstützung wird immer besser). So wie ich das tue ist es wichtig, dass alle impliziten Konvertierungen klar in einer 10 second code review angesehen werden können. Ich konnte auf den folgenden Code aussehen:


// other imports 
import com.foo.bar.FilthyRichString 

import com.foo.bar.util.Logger 
import com.foo.bar.util.FileIO 

import com.foo.bar.implicits.FilthyRichStringImplicit._ 
import com.foo.bar.implicits.MyListImplicit._ 
// other implicits 

und auf einen Blick alle impliziten Konvertierungen sehen, die in dieser Quelldatei aktiv sind. Sie würden auch alle zusammen gesammelt, wenn Sie die Konvention verwenden, dass Importe nach Paketen gruppiert sind, mit einer neuen Linie zwischen verschiedenen Paketen.

Entlang den Zeilen des gleichen Arguments möchte ich kein Catch-All-Objekt, das alle impliziten Konvertierungen enthält. Würden Sie in einem großen Projekt wirklich alle der impliziten Konvertierungen in allen Ihren Quelldateien verwenden? Ich denke, dass dies eine sehr enge Kopplung zwischen verschiedenen Teilen Ihres Codes bedeutet.

Auch ein Catch-All-Objekt ist nicht sehr gut für die Dokumentation. Wenn Sie explizit alle impliziten Konvertierungen schreiben, die in einer Datei verwendet werden, können Sie einfach Ihre Importanweisungen ansehen und sofort zur Dokumentation der impliziten Klasse springen. Im Falle eines Catch-All-Objekts müsste man das Objekt betrachten (was in einem großen Projekt sehr groß sein kann) und dann nach der impliziten Konvertierung suchen, nach der es suchen soll.

Ich stimme oxbow_lakes zu, dass die implizite Umwandlung in trait s ist schlecht wegen der Versuchung, davon zu erben, was, wie er sagte, schlechte Praxis ist. In diesem Sinne würde ich die Objekte, die die impliziten Konvertierungen enthalten, einfach so machen, dass die Versuchung gänzlich vermieden wird. Seine Idee, sie möglichst nahe an den Einsatz zu bringen, ist ebenfalls sehr hilfreich, wenn implizite Konvertierungen nur wenig im Code verwendet werden.

-- Flaviu Cipcigan