Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between require and assert?

Tags:

kotlin

With Kotlin 1.3 came a new feature, contracts, and with them the function require(), but it seems pretty similar to assert(). Here is what their KDoc says:

require(value: Boolean): Throws an IllegalArgumentException if the value is false.

assert(value: Boolean): Throws an AssertionError if the value is false and runtime assertions have been enabled on the JVM using the -ea JVM option.

So when should I use require() and when should I use assert()?

like image 930
Luca1152 Avatar asked Nov 04 '18 09:11

Luca1152


People also ask

What is difference between require and if in Solidity?

if(): when the first condition becomes false the next condition i.e else block gets executed. require(): it has a diffrent function. It is actually an error handling statement, and when the require condition is false, the execution stops and the transaction gets rolled back.

What does require mean Solidity?

'require' returns two boolean values that are either true or false, if the specified condition returns a true value it allows the code to flow and function accordingly. If the value returned is false, it throws an error and stops the code right there.

What is assert in Solidity?

In Solidity, three functions are provided by the language to check for the invariant, validations, and to fail the transaction. These functions are as follows: assert() : The assert() function should be used when you want to check for invariants in the code.

What is _; in Solidity?

In Solidity, there is the uncommon instruction _; . _; is used inside a modifier to specify when the function should be executed. A modifier is a piece of code that manipulates the execution of a function. The _; instruction can be called before and after the call of the function.


1 Answers

require and assert work differently. For this, you need to dive into the code.

assert(condition) calls a different method internally, which is where you see the actual code:

@kotlin.internal.InlineOnly
public inline fun assert(value: Boolean, lazyMessage: () -> Any) {
    if (_Assertions.ENABLED) {
        if (!value) {
            val message = lazyMessage()
            throw AssertionError(message)
        }
    }
}

AFAIK, this ties to the -ea flag; if -ea isn't present (or disabled), assert will not throw an exception.

As a result, this will not compile:

fun something(string: String?){
    assert (string != null)
    nonNull(string) // Type mismatch
}
fun nonNull(str: String){} 

This is where require comes in. require(condition) also calls a different method under the hood. If you replace assert with require, you'll see that smart cast will successfully cast it as non-null, because require is guaranteed to throw an exception if the condition fails.

@kotlin.internal.InlineOnly
public inline fun require(value: Boolean, lazyMessage: () -> Any): Unit {
    contract {
        returns() implies value
    }
    if (!value) {
        val message = lazyMessage()
        throw IllegalArgumentException(message.toString())
    }
}

The boolean-only function does the contract too, then calls that method if the contract fails.

Contracts are new, and I am not entirely sure how they work, but this is how I understand it:

The implies keyword is an infix fun; what this does is that it tells the compiler the condition is true if it returns from the method. This helps with auto-casting, like in the example I mentioned earlier. It doesn't actually cause the method to return (or at least that's what my current testing points to), but it's for the compiler.

It's also readable: returning implies condition is true

That's the contact part: the exception here is always thrown, as you can see by the condition. require uses if(!value), where as assert checks if(_Assertions.ENABLED && !value).

This isn't the only use for require though. It can also be used for validation of arguments. I.e. if you have this:

operator fun get(index: Int) : T {
    if (index < 0 || index >= size) 
        throw IllegalArgumentException("Index out of range")
    // return here
}

You could replace it with:

operator fun get(index: Int) : T {
    require (index >= 0 && index < size) { "Index out of range" }
    // return here
}

There are a lot different uses for this, but these are just some examples.

What this means:

  • assert is like in Java; it is only triggered if assertions are enabled. Using it does not guarantee the condition is met.
  • require always works, regardless of VM flags

Which means require can be used to help the compiler with i.e. smart cast, and it's better to use than assert for making sure arguments are valid. And since it also works regardless of VM flags, it can be used outside debugging cases, as forpas mentioned. If you're making a library written in Kotlin, you can replace argument checking with manual throwing with require, and it will still work. Obviously, this assumes Kotlin 1.3.0, but that's beside the point.

And it can be used internally to ensure smart cast works as expected, but throw an exception if the condition isn't met.

To answer your question though:

  • Use require when you want to to argument checking, even if it's in production.
  • Use assert if you're doing local debugging, and have the -ea flag enabled.
like image 153
Zoe stands with Ukraine Avatar answered Oct 22 '22 12:10

Zoe stands with Ukraine