Efficient use of test or assert

Suppose you want to check a property of some arguments given to a function, for instance, that x is positive.

What is the best practice regarding this?

I’m tempted to use @test x>0 instead of writing a block such as

if x > 0
else 
	error("x<=0")
end

I’ve also came accross @assert but this seems to be for debugging purposes right?

So what is the best practice, considering that those conditions may be checked many times and thus may impact performance?

  • @test is very slow and for tests.
  • @assert is for double-checking invariants you are certaint are true. The only way it can fire, is when there are bugs in the program. E.g.
# good
y = _my_fast_sum_of_squares(xs)
@assert y >= 0
# bad
function public_api(x)
    @assert x >= 0
end
  • ArgCheck.jl is specifically designed for fast argument checks with nice error messages.
4 Likes

Perfect, this is exactly what I needed! Thanks.

For a package-free alternative, throw(DomainError(...)) also seems to be recommended in this other thread.

Example:

dB(x) = (x > 0) ? 20*log10(x) : throw(DomainError(x, "argument <= 0"))
dB(0.5)     # -6.0
dB(-0.5)    # ERROR: DomainError with -0.5: argument <= 0

Sorry, why @assert is “bad” to use in that circumstances? Should assert only trigger if the error is inside your code and not because external input? Ultimately, if it triggers for some inputs and not others, the input will be involved as the cause of the error.

@assert is documented that it can be turned off as an optimization, so it shouldn’t be used for validating input or anything like that; in the future it might only be run when running in a debug mode (eg https://github.com/JuliaLang/julia/pull/37874). I have an open PR to add a macro @check that is just like @assert but would never be disabled: https://github.com/JuliaLang/julia/pull/41342

7 Likes

I was not aware of these current and planned characteristics of the @assert macro, thank you for the info. Seems like I will need to rewrite some code in the future.

1 Like