Using reserved words/syntax (try, ?) as macro names

TL;DR: I’d like to be able to use @try or @? as macro names for try-catch-like syntax in code using Result types. Would this be reasonable to allow?


I’ve been exploring ResultTypes.jl as an alternative to throwing exceptions. I quite like it so far, but I found the code to be somewhat verbose:

Base.convert(::Type{FooError}, err::BarError) = FooError("Got a BarError: \$(err.msg)")

function foo(x)::Result{Int, FooError}
    result = isbar(x)  # result is a Result{Bool, BarError}
    ResultTypes.iserror(result) && return unwrap_error(result)
    is_b = unwrap(result)
    return is_b ? 42 : 13

# ResultTypes.jl has `convert` methods for converting the return values
# above into the proper `Result` type.

Rust, in particular, uses Result (and similar types) exclusively, instead of exceptions. For the syntax above, they used to have a try! macro, which would look something like this in Julia:

function foo(x)::Result{Int, FooError}
    is_b = @try! isbar(x)  # expands to the version of foo() above
    return is_b ? 42 : 13

This is much nicer!

Using try makes sense, because it’s playing the role of try-catch for Result types.

I would prefer @try over @try! (the ! in try! indicates a macro call in Rust; in Julia, it hints that we’re modifying an argument, but we’re not doing that here). However, try is a reserved word in Julia, and can’t be used for macro names.

Rust now actually uses ? to accomplish the same thing. In Julia, this would look like

function foo(x)::Result{Int, FooError}
    is_b = isbar(x)?  # doesn't actually work in Julia
    return is_b ? 42 : 13

To somewhat mimic this, I also tried defining @? instead of @try, but that didn’t work either (? is syntax).

My question to the mainline devs: would it be reasonable to allow either of these to be used as macro names?

For anyone, any other ideas/suggestions on how to name or implement this? (See for the current pull request.)


It’s already possible to use @try etc as macro names:

julia> macro foo(ex) ex end
@foo (macro with 1 method)

julia> @eval $(Symbol("@try")) = $(Symbol("@foo"))
@foo (macro with 1 method)

julia> @try(1)

Note that in Julia 1.3+, you can write the second line a bit nicer without eval as

const var"@try" = var"@foo"