On Saturday, February 13, 2016 at 8:58:46 AM UTC-5, Robert Feldt wrote:
>
> 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...
>

That's reasonable.

Do you see any risks with doing it the run_code way in my foo2 macro?
>

I'm not sure about the `eval`, but the for loop introduces a scope block 
(soft scope?)

for x=1:10
   b = 80
end
@show b # UndefVarError

It'll only work if b is declared/initialized above the loop. For a test, 
that seems like a problem, for instance, this won't work

@test begin
    env = Environment()
    foo1(env)
end
@test begin
    foo2(env
end

I don't think that's solvable. There are some built-in macros that suffer 
from the same thing, eg.

@profile oo=10

oo  # UndefVarError

Personally, I would use `do` instead of `begin`:

@test() do
   ...
end

That way it's clear that we're introducing a new function scope. But I can 
see why people wouldn't want to change the current syntax.

Cédric
 

>
> 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!
>>>>
>>>

Reply via email to