2010-03-11 11 views
12

Wir haben unseren Code vor kurzem erstellt und wir sind auf ein paar nervige Hotspots gestoßen. Sie sind in FormSlow Scala assert

assert(a == b, a + " is not equal to " + b) 

Da einige dieser behauptet in Code sein kann, eine riesige Menge an mal die Zeichenfolge Concat beginnt genannt aufzuaddieren. assert ist definiert als:

def assert(assumption : Boolean, message : Any) = .... 

, warum es nicht wie folgt definiert:

def assert(assumption : Boolean, message : => Any) = .... 

auf diese Weise es gemächlich bewerten würde. In Anbetracht dessen, dass es nicht so definiert ist, gibt es eine Inline-Methode zum Aufrufen von Assertion mit einem Nachrichtenparameter, der träge ausgewertet wird.

Dank

+6

Für diejenigen, die nicht wissen, dies wurde in 2,8 fixiert. – Dave

Antwort

16

Faule Bewertung hat auch einige Overhead für das Funktionsobjekt erstellt. Wenn Ihr Nachrichtenobjekt bereits vollständig erstellt ist (eine statische Nachricht), ist dieser Aufwand nicht erforderlich.

Die entsprechende Methode für Ihren Anwendungsfall wäre sprintf-style:

assert(a == b, "%s is not equal to %s", a, b) 

Solange es eine speciaized Funktion

ist
assert(Boolean, String, Any, Any) 

diese Implementierung hat keine Overhead oder die Kosten des var args array

assert(Boolean, String, Any*) 

für den allgemeinen Fall.

Implementierung toString würde lazily ausgewertet werden, ist aber nicht lesbar:

assert(a == b, new { override def toString = a + " is not equal to " + b }) 
+0

Danke Thomas. Ich hatte den Overhead der faulen Bewertung nicht bedacht. Von unserem Code ist der Overhead der Lazy Evaluation viel niedriger als der String Concat, daher denke ich, dass wir unsere eigene Assert Methode schreiben werden. Es ist nicht schön, aber beschleunigt die Dinge sehr. – Dave

-2

Versuchen: assert(a==b, "%s is not equals to %s".format(a,b)) Das Format nur aufgerufen werden soll, wenn die Assertion die Zeichenfolge muss. Das Format wird über implizite RichString hinzugefügt.

+1

Dies ist ** falsch ** genau aus dem Grund, dass der Fragesteller hervorgehoben hat: dass die Assert-Methode eine 'Any' und nicht eine' => Any ' –

+1

Ich bin mir ziemlich sicher, dass es keine Magie im Format gibt, so wird es nur als normal aufgerufen werden, ob a == b ist wahr oder nicht. – Dave

+0

d'oh. Ich bin ein Id10t. Es ist jetzt offensichtlich. –

1

Thomas' Antwort ist groß, aber nur, wenn Sie die Idee der letzten Antwort mögen, aber die Unlesbarkeit nicht mögen, können Sie drum herum kommen:

object LazyS { 
    def apply(f: => String): AnyRef = new { 
    override def toString = f 
    } 
} 

Beispiel:

object KnightSpeak { 
    override def toString = { println("Turned into a string") ; "Ni" } 
} 

scala> assert(true != false , LazyS("I say " + KnightSpeak)) 

scala> println(LazyS("I say " + KnightSpeak)) 
Turned into a string 
I say Ni 
7

Es ist By-Name, ich habe es vor über einem Jahr geändert.

http://www.scala-lang.org/node/825

Aktuelle Predef:

@elidable(ASSERTION) 
def assert(assertion: Boolean, message: => Any) { 
    if (!assertion) 
    throw new java.lang.AssertionError("assertion failed: "+ message) 
} 
+0

@Extempore: Ist das nur für 2.8? Oder 2,7 auch? –