Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slow Scala assert

We've been profiling our code recently and we've come across a few annoying hotspots. They're in the form

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

Because some of these asserts can be in code called a huge amount of times the string concat starts to add up. assert is defined as:

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

why isn't it defined as:

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

That way it would evaluate lazily. Given that it's not defined that way is there an inline way of calling assert with a message param that is evaluated lazily?

Thanks

like image 914
David Avatar asked Mar 11 '10 13:03

David


3 Answers

Lazy evaluation has also some overhead for the function object created. If your message object is already fully constructed (a static message) this overhead is unnecessary.

The appropriate method for your use case would be sprintf-style:

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

As long as there is a speciaized function

assert(Boolean, String, Any, Any)

this implementation has no overhead or the cost of the var args array

assert(Boolean, String, Any*)

for the general case.

Implementing toString would be evaluated lazily, but is not readable:

assert(a == b, new { override def toString =  a + " is not equal to " + b })
like image 194
Thomas Jung Avatar answered Nov 04 '22 08:11

Thomas Jung


It is by-name, I changed it over a year ago.

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

Current Predef:

@elidable(ASSERTION)
def assert(assertion: Boolean, message: => Any) {
  if (!assertion)
    throw new java.lang.AssertionError("assertion failed: "+ message)
}
like image 36
psp Avatar answered Nov 04 '22 09:11

psp


Thomas' answer is great, but just in case you like the idea of the last answer but dislike the unreadability, you can get around it:

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

Example:

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
like image 1
Rex Kerr Avatar answered Nov 04 '22 09:11

Rex Kerr