Syntax for "impure" macros -- return/break/continue/etc


#1

Expanded on a thought by @kainino.

“Impure” Macros

I’ll start by defining what I mean by an “impure” macro: take for example try!, which, in a nutshell, takes a Result type and either unwraps the Ok(v) and evaluates to v or returns Err(e). Here’s where the impurity comes in: “evaluating” the try! macro expression does not always produce a value.

In the Ok case in the macro, a value is yielded as the macro expression result, and can be bound to a variable; in the Err case, a value is returned from the caller, and the control flow is interrupted. In other words, in the Err case, this macro creates side-effects that may not be inferred by the user without looking into the macro’s actual rules.

I’ve given the example of try! here because it’s a common macro, and it’s where I ran into this problem. However, this could ostensibly come up with other macros, and could come up in other flavors, e.g. macros that inject break, continue, or other control flow-modifying statements into their invoker’s context. These macros seem to me to border on violating macro hygienics rules, as they can modify their invoking context in unexpected ways.

macro_rules! try(
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => return Err(e)
    })
)

Changes

I’m not sure if this is considered to be a big enough issue to actually enforce, but if it is I would propose the following: either make it convention that impure macros are named a particular way that denotes their impurity, or have the compiler enforce some naming convention or other type of syntax for impure macro names. I prefer the latter, since it would be an enforced rule, rather than a suggestion.

Proposed Syntax

I haven’t been able to come up with a good syntax to denote impure macros, mostly because everything I’ve thought of has either been not descriptive enough or too verbose. I’m also focusing my scope to return, break, and continue for the moment, since they’re the three most obvious examples of control flow-breaking statements.

Potential syntax could be:

  • try!! or try_! -> I don’t think these are descriptive/obvious enough, and don’t distinguish between different types of statements. However, these would be compact, catch-all syntaxes for these kinds of macros.

  • try_return!/try_break!/try_continue! -> This is too long, and I imagine you might be invoking this macro quite often. Also only allows for these three types of statements, so I’m more in favor of the !! and _! variants than this or the kinds below.

  • try_ret!/try_brk!/try_con! -> Good, but might be confusing and might cause name confusion with other, user-defined macros that end in _ret/_brk/_con.

  • try_r!/try_b!/try_c! -> Same as above, not quite descriptive enough.

  • try(break)!, try!break -> Still verbose, but more explicit. This could use break to indicate any kind of “break” in control flow, including return/continue.