2010-03-11 11 views
12

Hemos estado elaborando nuestro código recientemente y hemos encontrado algunos puntos de acceso molestos. Están en la formaSlow Scala assert

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

Debido a que algunos de ellos afirma puede ser en el código llama una enorme cantidad de veces que el concat cadena comienza a tener sentido. assert se define como:

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

por qué no se lo define como:

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

De esa manera se evaluaría con pereza. Dado que no está definido de esa manera, ¿existe una forma en línea de invocar afirmar con un parámetro de mensaje que se evalúa de forma diferida?

Gracias

+6

Para aquellos que no saben, esto fue fijado en 2,8. – Dave

Respuesta

16

La evaluación diferida también tiene cierta sobrecarga para el objeto de función creado. Si su objeto de mensaje ya está completamente construido (un mensaje estático), esta sobrecarga no es necesaria.

El método apropiado para su caso de uso sería sprintf de estilo:

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

Mientras hay una función speciaized

assert(Boolean, String, Any, Any) 

esta implementación tiene ninguna sobrecarga o el costo de la var matriz args

assert(Boolean, String, Any*) 

para el caso general.

toString La implementación sería evaluado con pereza, pero no se puede leer:

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

Gracias Thomas. No había considerado la sobrecarga de la evaluación perezosa. Según nuestro código, la sobrecarga de la evaluación perezosa es mucho más baja que la cadena concat, por lo que creo que vamos a escribir nuestro propio método assert. No es bonito, pero acelera mucho las cosas. – Dave

-2

Probar: assert(a==b, "%s is not equals to %s".format(a,b)) El formato sólo debería existir cuando la aserción necesita la cadena. El formato se agrega a RichString por implícito.

+1

Esto está ** mal ** precisamente por la razón que el interrogador ha resaltado: que el método assert toma 'Any' y no a' => Any' –

+1

Estoy bastante seguro de que no hay magia en el formato así que solo se llama como normal, si a == b es verdadero o no. – Dave

+0

d'oh. Soy un id10t Es obvio ahora. –

1

respuesta de Thomas es grande, pero por si acaso te gusta la idea de la última respuesta, pero no les gusta la ilegibilidad, se puede conseguir alrededor de él:

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

Ejemplo:

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

Se es por nombre, lo cambié hace más de un año.

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

actual Predef:

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

@extempore: ¿Es solo para 2.8? ¿O 2.7 también? –