-
-
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
add builtin @__FUNCTION__ macros #6733
Comments
Superseded by #8066 |
Hi @ihnorton, I'm trying to do this:
https://github.com/JuliaWeb/HTTP.jl/blob/master/src/debug.jl#L38 CC @quinnj @Keno re: JuliaWeb/HTTP.jl#148 |
I see you are using |
With the Using It would be great to have something like @FUNCITON and or @METHOD. |
Reopening at the request of @samoconnor. |
Does anyone have a particular implementation in mind here? One possibility would be to add a Another idea could be to have a special |
Still not implemented in Julia 1.5.4 or am I missing something? |
It is actually possible to implement this without special lowering, but it is relying on internals of course: julia> macro __FUNCTION__()
return :($(esc(Expr(:isdefined, :var"#self#"))) ? $(esc(:var"#self#")) : nothing)
end
@__FUNCTION__ (macro with 1 method)
julia> @__FUNCTION__() === nothing
true
julia> f() = @__FUNCTION__
f (generic function with 1 method)
julia> f()
f (generic function with 1 method) You can even get just the name: julia> f() = nameof(@__FUNCTION__)
f (generic function with 1 method)
julia> f()
:f The question is whether this is something we want to officially expose. |
I love this hack :-) I wonder, is it possible to make it work when julia> module X
macro __FUNCTION__()
return :($(esc(Expr(:isdefined, :var"#self#"))) ? $(esc(:var"#self#")) : nothing)
end
end
julia> macro A()
:(X.@__FUNCTION__)
end this works: julia> @macroexpand f() = X.@__FUNCTION__
:(f() = begin
#= REPL[18]:1 =#
if $(Expr(:isdefined, Symbol("#self#")))
var"#self#"
else
Main.X.nothing
end
end) whereas this doesn't because julia> @macroexpand f() = @A
:(f() = begin
#= REPL[17]:1 =#
if $(Expr(:isdefined, :(Main.:(var"#self#"))))
Main.:(var"#self#")
else
Main.X.nothing
end
end) |
I think that's a more general issue with macro hygiene and composability of macros. The easiest way would probably be to do the macro expansion manually inside of the macro julia> macro A()
X.var"@__FUNCTION__"(__source__, __module__)
end
@A (macro with 1 method)
julia> @macroexpand f() = @A
:(f() = begin
#= REPL[7]:1 =#
if $(Expr(:isdefined, Symbol("#self#")))
var"#self#"
else
Main.nothing
end
end) Playing around with this, I started to wonder, whether this kind of nested escaping of only a macro's body could itself be inplemented as a macro and it turns out it can: julia> macro esc(x::Expr)
@assert x.head === :macrocall
return esc(Core.eval(__module__, x.args[1])(x.args[2], __module__, x.args[3:end]...))
end
@esc (macro with 1 method)
julia> macro A()
:(@esc X.@__FUNCTION__)
end
@A (macro with 1 method)
julia> @macroexpand f() = @A
:(f() = begin
#= REPL[25]:1 =#
if $(Expr(:isdefined, Symbol("#self#")))
var"#self#"
else
Main.nothing
end
end) It can even be used in front of the macrocall to julia> macro A()
:(X.@__FUNCTION__)
end
@A (macro with 1 method)
julia> @macroexpand f() = @esc @A
:(f() = begin
#= REPL[22]:1 =#
if $(Expr(:isdefined, Symbol("#self#")))
var"#self#"
else
Main.X.nothing
end
end) Not sure if this is actually that useful, but I find it quite fun to play around with. It probably also doesn't really address the issue you were pointing out, since the user still needs to be the one taking care of escaping for such a definition of the |
yes, it is a general problem that julia> macro A()
esc(:($Main.@inline f()))
end
@A (macro with 1 method)
julia> @macroexpand1 @A
:((Main).@inline f()) in the above example, that would look like this: julia> module X
macro __FUNCTION__()
return :($(esc(Expr(:isdefined, :var"#self#"))) ? $(esc(:var"#self#")) : nothing)
end
end
Main.X
julia> macro A()
:(X.@__FUNCTION__)
end
@A (macro with 1 method)
julia> macro A()
esc(:($X.@__FUNCTION__))
end
@A (macro with 1 method)
julia> f() = @A
f (generic function with 1 method)
julia> f()
f (generic function with 1 method) I think the main question would be of what precisely it would return (a Method, Symbol, or Function object). There's already precedent for this sort of reflection feature, so it just remains for someone to add this: julia> f(x, ::Any) = Base.@locals
f (generic function with 3 methods)
julia> f(1, 2)
Dict{Symbol, Any} with 1 entry:
:x => 1 |
Yes. I've only ever wanted the Also, what would |
FWIW, my vote would be for it to just return a symbol that could be used for debugging or in another macro to build up a new expression. I do think a separate |
Julia already has
@__FILE__
, but doesn't appear to have@__LINE__
or@__FUNCTION__
, both of which are really helpful when debugging.The text was updated successfully, but these errors were encountered: