".+ is no longer a function object" using pmap(f, a) inside macro in 0.6/0.7


#1

I have the following, boiled down example of a pattern I use in my test suites, optionally running test sets only when requested by name from the command line.

The shouldtest macro checks ARGS and then emits the test set or emits nothing.

This works fine in 0.5, but in 0.6 and 0.7 the serialization by pmap throws, when started using ~/local/julia7/julia --depwarn=error test/runtests.jl computing

ErrorException(".+ is no longer a function object, use broadcast(+, ...) instead.")

What is the correct way to do this in 0.6/0.7 to avoid broadcast(+,a,1) all over the code? Or is this a regression?

Thanks a lot!

using Compat, Compat.Test
if VERSION.minor > 6
    using Distributed
end

macro shouldtest(name,code)
    if length(ARGS) > 0 && ARGS[1] == name
        :(@testset $name $code)
    end
end

a = [1 2 3]

# works in 0.5, 0.6, 0.7
@testset "computing" begin
    r = pmap( x->x .+ 1, a)
end

# works in 0.5, 0.6, 0.7
@shouldtest "computing" begin
    r = pmap( x->broadcast(+,x,1), a)
end


#  the following passes in 0.5
#  in 0.6 and 0.7 this throws a
#      ErrorException(".+ is no longer a function object, use `broadcast(+, ...)` instead.")

@shouldtest "computing" begin
    r = pmap( x->x .+ 1, a)
end

#2

I think you need to escape the input code.


#3

Thanks for the quick response!

Like this?

macro shouldtest(name,code)
    if length(ARGS) > 0 && ARGS[1] == name
        :(@testset $name $(esc(code)))
    end
end

This makes is now pass in 0.6 (and still in 0.5) but in 0.7 I now get:

ERROR: LoadError: LoadError: Expected begin/end block or for loop as argument to @testset
Stacktrace:
 [1] error(::String) at ./error.jl:33
 [2] @testset(::LineNumberNode, ::Module, ::Vararg{Any,N} where N) at /home/rene/local/julia7/usr/share/julia/site/v0.7/Test/src/Test.jl:980

#4

Turns out, to make it pass on 0.7 the macro needs an extra begin/end as indicated in the error message.

I.e. changing from

macro shouldtest(name,code)
if length(ARGS) > 0 && ARGS[1] == name
:(@testset name (esc(code)))
end
end

to

macro shouldtest(name,code)
if length(ARGS) > 0 && ARGS[1] == name
:(@testset name begin (esc(code)) end)
end
end

Out of curiosity, why is this additional begin/end necessary?

Shouldn’t code represent the entire original begin/end block, just like in 0.6?