Apparently @assert
can be elided by the compiler for some optimization level.
What is the recommended easy and fool-proof ways of asserting program behaviours?
if !(condition)
error("error")
end
You can use @test
too, but previous one is better.
using Test
@test condition
Yes, that is possible. But @assert condition "Try again!"
is so much nicer.
macro myassert(ex, msgs...)
msg = isempty(msgs) ? ex : msgs[1]
if isa(msg, AbstractString)
msg = msg # pass-through
elseif !isempty(msgs) && (isa(msg, Expr) || isa(msg, Symbol))
# message is an expression needing evaluating
msg = :(Main.Base.string($(esc(msg))))
elseif isdefined(Main, :Base) && isdefined(Main.Base, :string) && applicable(Main.Base.string, msg)
msg = Main.Base.string(msg)
else
# string() might not be defined during bootstrap
msg = quote
msg = $(Expr(:quote,msg))
isdefined(Main, :Base) ? Main.Base.string(msg) :
(Core.println(msg); "Error during bootstrap. See stdout.")
end
end
return :($(esc(ex)) ? $(nothing) : error($msg))
end
@myassert condition "try again!"
Nice. But still: this means having to define this in all of your packages (or having one and using it).
Isn’t there something standard?
GitHub - jw3126/ArgCheck.jl: Package for checking function arguments has @check
macro
Just to confirm, If I don’t want to deal with packages, and want a macro that does exactly what @assert
does, I should take the definition of @assert
and rename the macro to something like @myassert
, as Amin_Yahyaabadi did, right? The compiler will not turn it off, right?
Correct.
Not quite. The last line of the @assert
macro reads
return :($(esc(ex)) ? $(nothing) : throw(AssertionError($msg)))
The last line of @myassert
provided above in this thread is
return :($(esc(ex)) ? $(nothing) : error($msg))
This ensures that if the compiler chooses to ignore AssertionError
s, the @myassert
macro will still throw on a false
value of its first argument.
Thanks for pointing out the distinction.
The documentation of @assert
gives a warning that the compiler might “disable” assertions. But you’re implying that this is a warning specifically about AssertionError
rather than anything else in the macro itself. Is that correct?
If so, it would be quite important to include that warning in the definition of AssertionError
itself I think. I’m on Julia 1.9, and AssertionError
has no such warnings.
I believe that is correct. Regarding adding the warning to the documentation for AssertionError
: To my knowledge, AssertionError
isn’t really thrown in practice except by the @assert
macro, for which it is intended. So it’s really enough to document the macro, which is what users are supposed to invoke to generate this flavor of Exception
.
The way the docs read to me is that the compiler could decide to elide @assert
, not that it could decide to ignore AssertionError
. Am I wrong?
You’re right. I don’t really know how this would be implemented. And after thinking about it, it’s probably easier to test the optimization level inside the macro logic, prior to macro expansion to achieve zero run-time cost.