Both Java and Kotlin have “assert” statement, they look equals but are greatly different.
Java assert is per class enabled and expression evaluation is done only when assertion is enabled.
By default, assertions are disabled, so you must not assume that the Boolean expression contained in an assertion will be evaluated. Therefore, your expressions must be free of side effects.
The piece of documentation you quote is a great explanation for why the design of the Java assert is problematic: putting code with required side effects into an assert statement is such a common bug source in both C and Java.
And I would claim that the behavior of any sufficiently complex production system can’t be understood well enough to state that assert checks are unuseful.
putting code with required side effects into an assert statement is such a common bug source in both C and Java.
My experience is different: I use assert to early detect bugs and those work well.
I found this issue after a fine tuning session, unfortunately now I must comment all Kotlin assert in my code; I don’t see this as a benefit, really.
Do you consider this a bad practice?
Do you evaluate this check in a loop and you discard the result only in production?
IntelliJ IDEA and its plugins always run with the -ea option enabled. Assertion failures are reported to JetBrains via the exception reporter, and are an extremely useful tool for us to improve the stability of our products.
There may be always useful, but sometimes they’re more expensive than useful. In Java, I mostly use Guava checkArgument or verify (both doing an unconditional check) and only sometimes assert. I recall having used a lot of asserts when doing some numerical computation as there were many possible very time-consuming checks.
In places where you need optional asserts, you can use something like this (untested):
val assertionsEnabled = Thread.currentThread().javaClass.desiredAssertionStatus()
inline fun assert(message: String = "Assertion failure", test: () -> Boolean) {
if (assertionsEnabled && !test()) throw AssertionError(message)
}
I believe this will compile to bytecode similar to what javac produces, and that the JIT compilers are very good at eliminating if the -ea flag is not passed.
I have come up with a cool solution to get java like asserts that can be disabled in the class and it only requires adding one line of boilerplate in the companion object for the class and lets you decide what you want the assertion mechanism to be called.
And here is how it is used. Whatever name you give to the property is how you access it so you can call it assert, invariant, or whatever you want. But as I said this won’t work until Kotlin 1.1.1
class MyClass
{
companion object
{
val myAssert : AssertionsEnabled? by DisablableAssert
}
fun foo()
{
myAssert { 1 == 1 }
myAssert("this will only be checked if assertions enabled") { 1 == 2 }
}
}
Assertions are uniquely useful for manual testing, staging environments, and when behavior appears in production (or end-user processes) that really shouldn’t. If you leave assertions on all the time, you lose these capabilities, and gain nothing, because defining a custom class hierarchy of Throwables would work the same for your exception reporter.
Yes, the statement about the behavior of IntelliJ IDEA is still true, but I don’t think that discussing the details of IntelliJ IDEA testing and error reporting is really relevant for the Kotlin forum.
Not true at all! IntelliJ has an inspection for assertions with side effects that does an excellent job of eliminating this kind of bug. This claim is also entirely outside of my experience. It’s very easy to write assertions with no side-effects.
If that’s your experience, you may be doing something wrong. While large projects do get pretty complex, many classes and methods are conceptually very simple, and that is the level where assertions are useful. When I write assertions, they’re in methods with a simple structure, so it’s easy to see if an assertion is valid or not. I know how my methods work, and I know what assumptions I’m making, so it’s both easy and useful to write assertions to ensure that my code is doing what I expect it to do. The complexity of the entire system doesn’t change the validity of my assumptions.
Many people who object to assertions are misunderstanding their purpose. The whole point of an assertion is that you can remove it from production. If you want to leave it in production, there are other language elements that you can use to perform the same tests.
Assertions give you the freedom to write slower tests. This sounds strange to a lot of people, but my point is that I don’t have to worry about an inefficient test when I’m writing an assertion, since it won’t be in production. Steve Maguire, in his excellent book Writing Solid Code, gave a very good example from the early days of Microsoft Excel. To improve performance, they developed an algorithm to only calculate cells that would be effected by the recent changes, instead of slowly recalculating everything. But the algorithm had to work perfectly. So they put in an assertion that recalculated every cell, and tested to make sure the results were the same. Naturally, it ran very slowly when this was enabled, but they also caught every bug they needed to catch, so when they released their new app, this aspect worked perfectly. This illustrates the advantage of the “freedom to write slow tests.”
In short, assertions are for development-phase diagnostic tests. Some people ask, “if you don’t want them in production, why don’t you just remove them before your release?” Because you’ll want to put them back when you start working on version 2.
In Kotlin, I really want to see assertions that behave like in Java, where they are disabled by default but can be enabled at run time.
This is an old forum topic that may not be worth resurrecting unless there’s something new addressing the original post.
How assert works in Kotlin (same as Java*)
@MiguelMunoz you mention that you want assertions to work as they do in Java:
This is how assert currently works in Kotlin. See the docs here. As always, you can view these docs directly when using assert() in IntelliJ.
I hope that clears up any confusion.
EDIT:
As @fatjoe79 points out in a later comment and in the original post, the assert() arguments are evaluated even if assertions are turned off which is not like Java. More discussion on this earlier in this topic (before 2017).
Something new (for those coming from Java)
Although not intended to function like the Java assertion, I found Java assertions have been used as a poor substitute to accomplish a similar goal as these powerful functions. These functions may be useful to those who find this topic looking for information on assertions: require(), requireNotNull(), check(), checkNotNull()
Be sure to check the links to see the runnable examples (and edit the examples right from the docs!)
Contracts enable them to be used in flow-sensitive things like smart casts and more.
I’ll often use these functions to perform argument and state checks at the beginning of a function where I previously might have used assertions. These can’t be turned off like assertions though as they’re intended to solve a different kind of problem–and of course they wouldn’t be useful for flow-sensitive typing.