Using a macro argument as a symbol, inside the returned quote

156 views
Skip to first unread message

Tomas Lycken

unread,
Jul 25, 2015, 6:30:08 PM7/25/15
to julia-users
Hi everybody!

Is there a way to use a macro argument as an actual Symbol in the quote that the macro returns? The following can hopefully help explaining what I want:

```
julia> macro foo(bar)
           :(isdefined($bar))
       end

julia> macroexpand(:(@foo baz))
:(isdefined(baz)) # I had hoped for :(isdefined(:baz)) - with :baz instead of baz
```

I've tried various combinations of interpolation, escaping and passing arguments to `symbol`, but to no avail. Is there a way to accomplish this?

--- Actual use case below ---

I noticed a very common pattern in my workflow that I wanted to abstract away to make it quicker and easier:

I want to load module X. If it's in LastMain, it's much faster to get it from there, but otherwise I need to load it from scratch.

I can easily write code that does this. Take, for example, Gadfly:

```
(isdefined(:LastMain) && isdefined(LastMain, :Gadfly) && using LastMain.Gadfly) || using Gadfly
```

When I execute that code, Gadfly will load from LastMain if available there, and from scratch otherwise. And it won't error out if I haven't called `workspace()` at all yet. Perfect! But having to type that for each module I want to use the workflow for is a hassle - what if `@quickload Gadfly` would do the same thing? This is my attempt so far:

```
julia> macro quickload(m)
       :((isdefined(:LastMain) && isdefined(LastMain, $m #= what do I put here?=#) && using LastMain.$m) || using $m)
       end

julia> macroexpand(:(@quickload Gadfly))
:((isdefined(:LastMain) && isdefined(LastMain,Gadfly #= <-- ...to make that :Gadfly instead of Gadfly =#)) && using LastMain.Gadfly || using Gadfly)

```

Thanks in advance!

// T

David Gold

unread,
Jul 25, 2015, 6:58:28 PM7/25/15
to julia-users, tomas....@gmail.com
This seems to work:

julia> macro foo(bar)
           _bar = Expr(:quote, bar)
           res = Expr(:call, :isdefined, :($_bar))
           return res
       end

julia> macroexpand(:( @foo(baz) ))
:(isdefined(:baz))

Tomas Lycken

unread,
Jul 25, 2015, 7:09:26 PM7/25/15
to julia-users, david....@gmail.com

Fantastic - thanks a lot!

The final form of the macro is then the following:

macro quickload(m)
    _m = Expr(:quote, m)

    quote
        if isdefined(:LastMain) && isdefined(LastMain, $_m)
            using LastMain.$m
        else
            using $m
        end
    end
end

This works very well - except that I have to define it in each new workspace… Adding it to .juliarc.jl does make it available on start, but after workspace() it’s not available anymore, and kind-of looses its point…

Any suggestions?

// T

David Gold

unread,
Jul 25, 2015, 7:48:43 PM7/25/15
to julia-users, tomas....@gmail.com
Hmm...

You could write an `@workspace` macro that calls `workspace()` and then declares itself and the `quickload` macro... =p

Tomas Lycken

unread,
Jul 25, 2015, 8:04:01 PM7/25/15
to julia-users, david....@gmail.com
Actually, I probably don't need a macro for this - all I need to do is to call both `workspace()` and `include(`~/.juliarc.jl`) :)

It turns out there's already a function that does most of the plumbing: `Base.load_juliarc()`. Thus, `workspace(); Base.load_juliarc()` does exactly what I need.

I'll file a PR that makes `workspace()` call `load_juliarc()`, since it feels intuitive that it should, but since it's possible to just call both functions manually I'm in no way blocked by it :)

Thanks for the help!

// T

Tomas Lycken

unread,
Jul 25, 2015, 8:10:10 PM7/25/15
to julia-users, david....@gmail.com, tomas....@gmail.com

David Gold

unread,
Jul 26, 2015, 8:40:03 AM7/26/15
to julia-users, tomas....@gmail.com
Until this gets merged, I'm finding that including 

macro workspace()
    return quote
        workspace()
        Base.load_juliarc()
    end
end

in `~/.juliarc.jl` does the trick.
Reply all
Reply to author
Forward
0 new messages