Update: Scala 2.8 has an annotation called elidable that will (when 2.8 is complete) allow one to remove method calls at compile time by setting a compiler flag. The assert, etc... methods are all marked with this flag and as a result can be removed at compile time for production environments.
Scala2.8
- scala> var called = 0
- called: Int = 0
- scala> called
- res0: Int = 0
- /*
- assert, require and assume have call by name parameters so the message is only
- calculated when the assertion fails.
- */
- scala> assert (called == 0, {called += 1; println("called is not 0")})
- scala> require (called == 0, {called += 1; println("called is not 0")})
- scala> assume (called == 0, {called += 1; println("called is not 0")})
- scala> called = 1
- called: Int = 1
- // demonstrating that the method is in fact called when the assertion fails
- scala> assert (called == 0, {called += 1; println("called is not 0")})
- called is not 0
- java.lang.AssertionError: assertion failed: ()
- at scala.Predef$.assert(Predef.scala:95)
- ...
-
- scala> called
- res4: Int = 2
- /*
- Require is intended to be used as a precondition of a method so
- it throws an IllegalArgumentException, not an AssertionError
- */
- scala> require (called == 0, {called += 1; println("called is not 0")})
- called is not 0
- java.lang.IllegalArgumentException: requirement failed: ()
- at scala.Predef$.require(Predef.scala:117)
- ...
-
- scala> called
- res6: Int = 3
- scala> assume (called == 0, {called += 1; println("called is not 0")})
- called is not 0
- java.lang.AssertionError: assumption failed: ()
- at scala.Predef$.assume(Predef.scala:107)
- ...
-
- scala> called
- res8: Int = 4
scala 2.7.7
- /*
- In Scala 2.7 the parameter is evaluated before the
- method is called so the side effect of the message causes
- the assertion to fail
- */
- scala> assert (called == 0, {called += 1; println("called is not 0")})
- called is not 0
- scala> called
- res2: Int = 1
This of course leaves us wondering what the difference between assert and assume is.
ReplyDeleteThere is no real difference. It just reads different.
ReplyDeleteI didn't realise assert() was always enabled. It's pretty important to be able to disable asserts: is there a way?
ReplyDeleteIn fact there is a way. I will address it in my next post. It is elidable compiler level Certain methods can be annotated so they will not be compiled given a certain compiler flag
ReplyDeleteHmm seems the elidable compiler flags are not yet available in the snapshot. So I will wait on that post. But the idea is to be able to pass a flag to the compiler and certain method calls will be removed by the compiler to not have the overhead
ReplyDeleteJesse - elidable has been in there for months and I just confirmed it's working fine. Don't know what issue you're having, but see the test case I just checked in if you need example usage.
ReplyDeleteShouldn't that be "It's pretty important to not disable asserts". In Java I never use the assert statement because it is (by default) disabled in the field. Instead I use my own methods that can't be disabled. Often it is as important or more so to detect errors that occur in production as it is to detect errors during testing. For one thing, if errors are found in production, it indicates that there is a problem with your testing practices -- something you would probably want to know about.
ReplyDelete