I'm not sure there's a way to achieve exactly what you're asking, but I'll
note that your problem comes from Julia's scoping rules for assignment.
I.e. if you replace
a = 1
@foo1 begin
a += 1 # UndefVarError!
end
with
a = 1
@foo1 begin
2 * a
end
then you don't get any UndefVarError. Why do you want assignment inside a
test to apply outside the test? Not sure if this will apply to you, but I
sometimes have code that's written this way to get around the scoping rules:
w = initial_value()
w = fixed_point(max_iter=10) do w
w = blah(w)
...
w
end
On Saturday, February 13, 2016 at 7:41:35 AM UTC-5, Robert Feldt wrote:
>
> To clarify the possible solution hinted at in my previous message here is
> code to show how it could be done:
>
> function run_code(t::Type{Runner}, runnername::Symbol, block::Expr)
> quote
> for i in 1:($runnername.reps)
> $block
> end
> end
> end
>
> macro foo2(runnertypename, ex)
> rt = eval(runnertypename) # But what if Runner type not defined in
> global scope? Risky!?
> quote
> local r = $(esc(runnertypename))()
> $(run_code(rt, :r, esc(ex)))
> end
> end
> a = 1
> @foo2 Runner begin
> a += 1
> end
> @show(a);
>
> This works as intended and gives a lot of power for people to write their
> own Runners but feels a bit inelegant and error prone. If there is a more
> idiomatic way please share.
>
> /Robert
>
> Den lördag 13 februari 2016 kl. 12:16:43 UTC+1 skrev Robert Feldt:
>>
>> When working on a possible PR for the new Base.Test infrastructure I run
>> into a design problem of how to allow flexible control of how the expr
>> available to a macro is executed. Sorry if this is trivial but I'd
>> appreciate any design ideas/pointers. Simplified code below to try and
>> explain what I mean.
>>
>> # A macro can eval in the calling context:
>> macro foo(ex)
>> quote
>> $(esc(ex))
>> end
>> end
>> a = 1
>> @foo begin
>> a += 1
>> end
>> @show(a); # a = 2
>>
>> # But lets say I want to be able to dynamically control how the expr
>> # of a macro is executed via a Runner (this is a convoluted/dummy example
>> but
>> # simplified from a more complex case where there are multiple types
>> # of Runners)
>> type Runner
>> reps::Int64
>> Runner() = new(2)
>> end
>> run(f::Function, r::Runner) = begin
>> for i in 1:r.reps
>> f()
>> end
>> end
>>
>> # Is there any way I can "package" the expr a macro has so that its
>> execution
>> # is controlled by an instance of the Runner above while still evaluating
>> # the expr in the scope where the macro is called?
>>
>> # First try:
>> macro foo1(ex)
>> quote
>> r = Runner()
>> run(r) do # UndefVarError since do-block creates new scope?
>> $(esc(ex))
>> end
>> end
>> end
>> @foo1 begin
>> a += 1 # UndefVarError!
>> end
>> @show(a);
>>
>> # What I could do is maybe have dispatch on Type{Runner}to generate the
>> run code to be spliced into
>> # the macro but this seems inelegant and maybe error prone since it mixes
>> compile-time
>> # and runtime (since Type{Runner} is needed at macro expansion time).
>> # Any ideas on a clean and elegant way to accomplish this?
>>
>> # Further details at the bottom of:
>> https://github.com/JuliaLang/julia/pull/14971
>>
>> Thanks!
>>
>