@assert: what is the proper tool?

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!"
1 Like

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

3 Likes

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 AssertionErrors, the @myassert macro will still throw on a false value of its first argument.

1 Like

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.