Skip to content
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

suggestion: define at-invokelatest macro: #37971

Merged
merged 3 commits into from
Dec 2, 2020

Conversation

aviatesk
Copy link
Sponsor Member

  • offers easier syntax to call Baes.invokelatest
  • @invokelatest f(args...; kwargs...) will simply be expanded into Base.invokelatst(f, args...; kwargs...)

@aviatesk aviatesk changed the title define at-invokelatest macro: suggestion: define at-invokelatest macro: Oct 10, 2020
@aviatesk
Copy link
Sponsor Member Author

aviatesk commented Oct 10, 2020

I made this PR just as a suggestion; if @invokelatest seems better to live within a community package, I'm totally okay with it and will close this.

@jw3126
Copy link
Contributor

jw3126 commented Oct 10, 2020

I have seen the pattern @foo f(args...; kw...) as syntax for foo(f, args...; kw...) at a couple of places in the ecosystem. If it occurs multiple times in Base, this macro could share code with those other macros.

@StefanKarpinski StefanKarpinski added the triage This should be discussed on a triage call label Oct 19, 2020
base/util.jl Outdated Show resolved Hide resolved
@StefanKarpinski
Copy link
Sponsor Member

Triage is in favor! It would be nice to factor out the code that transforms @m f(args...) into f(m, args) and similar so that it can be shared. But otherwise this would be convenient.

@aviatesk
Copy link
Sponsor Member Author

It would be nice to factor out the code that transforms @m f(args...) into f(m, args) and similar so that it can be shared.

Could you kindly provide an example of those transformations ?
I've looked at gen_call_with_extracted_types (, which is used within @code_typed, etc), but imo it's not such a simple function that can be factored out to share a common piece of code with @invokelatest.

@aviatesk
Copy link
Sponsor Member Author

fwiw, I have somewhat same kind of macro @invoke like below, and it has a similar structure as @invokelatest:

"""
    @invoke f(arg::T, ...; kwargs...)

Provides a convenient way to call [`invoke`](@ref);
`@invoke f(arg1::T1, arg2::T2; kwargs...)` will be expanded into `invoke(f, Tuple{T1,T2}, arg1, arg2; kwargs...)`.
When an argument's type annotation is omitted, it's specified as `Any` argument, e.g.
`@invoke f(arg1::T, arg2)` will be expanded into `invoke(f, Tuple{T,Any}, arg1, arg2)`.
"""
macro invoke(ex)
    f = first(ex.args)
    argtypes = []
    args = []
    kwargs = []
    for x in ex.args[2:end]
        if isexpr(x, :parameters)
            append!(kwargs, x.args)
        elseif isexpr(x, :kw)
            push!(kwargs, x)
        else
            arg, argtype = isexpr(x, :(::)) ? (x.args...,) : (x, Any)
            push!(args, arg)
            push!(argtypes, argtype)
        end
    end
    return if isempty(kwargs)
        :(invoke($(f), Tuple{$(argtypes...)}, $(args...))) # might not be necessary
    else
        :(invoke($(f), Tuple{$(argtypes...)}, $(args...); $(kwargs...)))
    end |> esc
end

I may try to make a PR to introduce @invoke into Base in a separate PR, and we can refactor the code then, I think.

else
push!(args, x)
end
end
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the loop is not necessary --- wouldn't just splatting all of ex.args[2:end] into the expression work?

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

na, I think the current parser requires the loop to correctly handle keyword arguments, e.g.:

julia> macro invokelatest(ex)
           @assert is_expr(ex, :call) "call expression f(args...; kwargs...) should be given"
       
           f = first(ex.args)
           args = ex.args[2:end]
           return esc(:($(GlobalRef(Base, :invokelatest))($(f), $(args...))))
       end
@invokelatest (macro with 1 method)

julia> @macroexpand @invokelatest printstyled(stdout, "blue"; color = :blue)
:(Base.invokelatest(printstyled, $(Expr(:parameters, :($(Expr(:kw, :color, :(:blue)))))), stdout, "blue"))

julia> @invokelatest printstyled(stdout, "blue"; color = :blue)
ERROR: syntax: invalid syntax ; color = :blue
Stacktrace:
 [1] top-level scope
   @ none:1

@JeffBezanson JeffBezanson added forget me not PRs that one wants to make sure aren't forgotten and removed triage This should be discussed on a triage call labels Nov 12, 2020
aviatesk added a commit to aviatesk/julia that referenced this pull request Nov 14, 2020
- provides easier syntax to call `Core.invoke`, e.g. `@invoke 
f(a::Integer)` will be expanded into `invoke(f, Tuple{Integer}, a)`
- when type annotation is omitted, the argument type is specified as 
`Any`

Built on top of JuliaLang#37971
aviatesk added a commit to aviatesk/julia that referenced this pull request Nov 17, 2020
- provides easier syntax to call `Core.invoke`, e.g. `@invoke 
f(a::Integer)` will be expanded into `invoke(f, Tuple{Integer}, a)`
- when type annotation is omitted, the argument type is specified as 
`Any`

Built on top of JuliaLang#37971
aviatesk added a commit to aviatesk/julia that referenced this pull request Nov 19, 2020
- provides easier syntax to call `Core.invoke`, e.g. `@invoke 
f(a::Integer)` will be expanded into `invoke(f, Tuple{Integer}, a)`
- when type annotation is omitted, the argument type is specified as 
`Any`

Built on top of JuliaLang#37971
aviatesk added a commit to aviatesk/julia that referenced this pull request Nov 19, 2020
- provides easier syntax to call `Core.invoke`, e.g. `@invoke 
f(a::Integer)` will be expanded into `invoke(f, Tuple{Integer}, a)`
- when type annotation is omitted, the argument type is specified as 
`Any`

Built on top of JuliaLang#37971
base/util.jl Outdated
`Base.invokelatest(f, args...; kwargs...)`.
"""
macro invokelatest(ex)
@assert is_expr(ex, :call) "call expression f(args...; kwargs...) should be given"
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be an assert; it should throw an ArgumentError.

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@aviatesk aviatesk force-pushed the at-invokelatest branch 2 times, most recently from 8360266 to d3f9cdb Compare November 28, 2020 16:58
aviatesk and others added 3 commits December 1, 2020 23:55
- offers easier syntax to call `Baes.invokelatest`
- `@invokelatest f(args...; kwargs...)` will simply be expanded into 
`Base.invokelatst(f, args...; kwargs...)`
Co-authored-by: Jeff Bezanson <[email protected]>
aviatesk added a commit to aviatesk/julia that referenced this pull request Dec 1, 2020
- provides easier syntax to call `Core.invoke`, e.g. `@invoke 
f(a::Integer)` will be expanded into `invoke(f, Tuple{Integer}, a)`
- when type annotation is omitted, the argument type is specified as 
`Any`

Built on top of JuliaLang#37971
@StefanKarpinski
Copy link
Sponsor Member

This would be nice to finish off. What's required to make forward progress here?

@aviatesk
Copy link
Sponsor Member Author

aviatesk commented Dec 2, 2020

I think we can merge this as is ?

@JeffBezanson JeffBezanson merged commit 97bdd8b into JuliaLang:master Dec 2, 2020
@aviatesk aviatesk deleted the at-invokelatest branch December 3, 2020 00:20
aviatesk added a commit to aviatesk/julia that referenced this pull request Dec 3, 2020
- provides easier syntax to call `Core.invoke`, e.g. `@invoke 
f(a::Integer)` will be expanded into `invoke(f, Tuple{Integer}, a)`
- when type annotation is omitted, the argument type is specified as 
`Any`

Built on top of JuliaLang#37971
aviatesk added a commit to aviatesk/julia that referenced this pull request Dec 3, 2020
- provides easier syntax to call `Core.invoke`, e.g. `@invoke 
f(a::Integer)` will be expanded into `invoke(f, Tuple{Integer}, a)`
- when type annotation is omitted, the argument type is specified as 
`Any`

Built on top of JuliaLang#37971
aviatesk added a commit to aviatesk/julia that referenced this pull request Dec 4, 2020
- provides easier syntax to call `Core.invoke`, e.g. `@invoke 
f(a::Integer)` will be expanded into `invoke(f, Tuple{Integer}, a)`
- when type annotation is omitted, the argument type is specified as 
`Any`

Built on top of JuliaLang#37971
aviatesk added a commit to aviatesk/julia that referenced this pull request Dec 8, 2020
- provides easier syntax to call `Core.invoke`, e.g. `@invoke 
f(a::Integer)` will be expanded into `invoke(f, Tuple{Integer}, a)`
- when type annotation is omitted, the argument type is specified as 
`Any`

Built on top of JuliaLang#37971
aviatesk added a commit to aviatesk/julia that referenced this pull request Dec 25, 2020
- provides easier syntax to call `Core.invoke`, e.g. `@invoke 
f(a::Integer)` will be expanded into `invoke(f, Tuple{Integer}, a)`
- when type annotation is omitted, the argument type is specified as 
`Any`

Built on top of JuliaLang#37971
Keno pushed a commit that referenced this pull request Dec 25, 2020
- provides easier syntax to call `Core.invoke`, e.g. `@invoke 
f(a::Integer)` will be expanded into `invoke(f, Tuple{Integer}, a)`
- when type annotation is omitted, the argument type is specified as 
`Any`

Built on top of #37971
ElOceanografo pushed a commit to ElOceanografo/julia that referenced this pull request May 4, 2021
- provides easier syntax to call `Core.invoke`, e.g. `@invoke 
f(a::Integer)` will be expanded into `invoke(f, Tuple{Integer}, a)`
- when type annotation is omitted, the argument type is specified as 
`Any`

Built on top of JuliaLang#37971
@simeonschaub simeonschaub removed the forget me not PRs that one wants to make sure aren't forgotten label May 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants