-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
macro hygine escape stripped late for macros calling macros #23221
Comments
Yes, incorrect placement of Most of the time, the simplest replacement is simply to move the
However, note that this also affects the scope resolution of |
What is the correct way to combine expressions that needs to be resolved in caller scope and callee scope then? |
i.e. the equivalent of macro m(ex)
quote
a = 1
@another_macro_in_callee_module a $(esc(ex)) global_in_callee_module
end
end |
If you know it must be a global, my current recommendation is to splice it in explicitly: We also may need to update some macro implementations to be hygiene-annotation aware. |
Seems to be a step backward since there's almost no way one can get things working without wrapping everything in a big And there's also the |
manual hygiene ( |
That's why I mentioned why It also means that whenever one include a nested macro, they'll likely need to replace all local variables that is used in the macro with This doesn't seem like the behavior we want. We should (and previous did) make sure that at macro templates can be written as normal code apart from the part that needs to deal with user input. That's the lowest level of hygiene-by-default we can/should provide. |
Let's not romanticize past bugs. In the past, we got macro hygiene wrong, but did so randomly and unpredictably. Hygiene doesn't (and can't) know whether to replace a symbol with a gensym or a globalref until after it has finished expanding all macros. Using |
Well, in both cases there are correct way to write code that will give the correct result and the previous behavior was much easier to use. None of them should be the final solution but I don't think we should make writing correct macros much harder. |
And so the predictable behavior now is that
|
This may be expected behavior, but the change introduced in #22985 has proven to be hugely breaking, so something about this should be addressed. |
@vtjnash, closing this with no comment is not ok. This situation is unpopular, severely breaking, and as far as I can see, you've made zero attempt to clarify what the new rules for macros are or help mitigate the massive fallout that we're seeing. |
Thanks guys for taking this one seriously. I haven't had the time to understand the subtle differences between the three possible solutions (#10940 vs #22985 vs the previous hygiene situation in 0.6) so I can't comment in detail. I would certainly like the rules for how hygiene interacts with scoping (in multiple macros vs multiple modules) described clearly somewhere. If that's not possible, perhaps it's a sign that the right solution hasn't yet arrived :-) |
Yeah definitely. At the very least, the recent change should have documentation and/or NEWS so that people know how to write 0.7-compatible macros and can fix the large number of currently broken packages. |
I think we're not done here yet and the macro system will continue to evolve before 1.0. Hopefully some form of #10940 will be merged, and then there will be a better and more complete story to tell. |
Do we leave it as-is for now in a state where so many things are broken with the story known to be incomplete so that people are actively discouraged from trying to fix it because they know it will change again? That seems less than ideal. I know master is unstable, but this is unusually bad and seems like work that might be better suited for a long-lived branch. |
For anyone who hits this and wants to try to work around the issue with escaping, I tried tracking the escaping depth inside expressions passed to |
Use fully qualified names everywhere to work around macro hygiene issues, either on 0.6 or 0.7 (JuliaLang/julia#23221) or both. Alternative to #55, which breaks Julia 0.7.
If there's no desire to change the current situation, could the hygiene section of the documentation at least be updated with an example of how to handle a case like #23221 (comment)? I still don't know what the correct way to handle such cases is. |
You're apparently just using |
In Parametron.jl, that's what I chose for now, yes. I know this is not correct. I also don't know how to do it correctly, while I did in 0.6.
No it isn't, apparently. In >=0.7 that doesn't work, because Note by the way that I'm not claiming that the version before the changes above was correctly escaping inputs on 0.6, but I tried doing what you proposed and ran into the current issue. |
If you want proof that I grasp the basic concept of escaping, see e.g. https://github.com/tkoolen/LoopThrottle.jl/blob/master/src/LoopThrottle.jl. But again note that if I were to call |
@tkoolen you're not crazy; there's not been a satisfactory resolution to this yet. While it's great that Jameson has fixed the bugs in the old system, #23221 (comment) is still a good assessment of the usability problems. |
Hey all! What's the current state of this issue? Currently there's some need for calling a macro within a macro such that it runs in the outer scope (as with @tkoolen, calling JuMP's Currently, the only solution @akshayka (CC) and I have found was to do something like the original approach, where we simply escape everything (which... doesn't really follow hygiene rules) macro fancy_variable(m, v)
return quote
_do_something($(esc(m)), $(quot(v)))
$(esc(quote
@variable($m, $v)
@constraint($m, $v = 1)
end))
end
Here, In particular, it would also be great to have some good documentation on how to "wrap" macros within other macros (as in the above case, for example), or to know the current state of affairs with the late escapes. I would be very happy to help write the documentation, but I'm afraid I'm not sure I fully understand hygiene and escaping well enough to give clear explanations. If anyone could also point me to some more examples, that would be fantastic (and, perhaps, after being a bit more confident, I could help write some docs ;). |
It's an unresolved problem: nested inner macros must be prepared to deal with I don't think there's a clear solution in sight. The macro expander needs some information about the module scope of each At the moment the expander gets access to this information by processing the nested The expander could in principle resolve symbols into I believe there was a proposed solution from long ago (#6910) which did an end run around these constraints by hiding the module information in the address of the |
The PR #6910 basically changes from requiring recursive macros from dealing with In short, the rule now for when you use |
I don't think we should close this, unless we have a different issue tracking the usability problems of macros-calling-macros. The problem is not that the current system is wrong (not exactly), but that it's very difficult for macro users to use correctly. |
Having bugs and being difficult to learn aren't actionable (though certainly related). When you encounter specific bugs, please open issues for them. |
For simple interpolation that's fine, but ignores the case when you'd like to pattern match the argument to extract subexpressions. The pattern matching must be aware that Therefore, most macros can't be used in the AST generated by another macro. This is the specific usability problem. |
Yes, tooling like MacroTools.jl is generally recommended so that you aren't trying to deal with every case yourself. |
MacroTools.jl doesn't seem to handle this. But I agree that pattern matching tooling with proper I think the problem is well defined and we haven't solved it. Therefore I don't know why we'd close this issue. |
I am also finding it difficult to understand why this was closed. Macro hygiene for the case @c42f mentioned above continues to be a tricky issue in Julia --- if this issue is considered too low level/mechanical for a discussion about that, another one should be opened. |
Just because it is difficult to write a proper macro doesn't mean that anything is wrong, and it's not helpful to repeat that. There are definitely remaining bugs that need to to be fixed, but this issue has thus far not talked about them. |
Perhaps this should be considered a feature request then. |
I've done my best to clearly restate this as a usability problem with the current system here: #37691 |
In julia 0.7, escaping with
esc
seems to be stripped out later than in julia 0.6.This means that macros which are called by other macros need to have code for
dealing with input ASTs including
Expr(:escape, ...)
. For example:Is this intentional? From a user perspective the 0.6 behavior made more sense
to me, as it allowed the inner macro to work with surface syntax not including
Expr(:escape, ...)
nodes. It also meant that the outer macro would be requiredto properly escape
$ex
in the example above.The text was updated successfully, but these errors were encountered: