Good clarifications and example, thanks. To answer your question I will not write test code/blocks that updates variables outside the block but someone else might and currently Base.Test (in 0.5-dev) would allow it. I want my PR to retain current functionality as much as possible. But you are right, tests in general shouldn't have effect outside the test...
Do you see any risks with doing it the run_code way in my foo2 macro? Den lördag 13 februari 2016 kl. 14:49:41 UTC+1 skrev Cedric St-Jean: > > 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! >>> >>