How to specify the element type of the vector that is returned

Hello,
I want to Modify this macro @collect such that I can specify the element type
of the vector that is returned. any ideas?

macro collect(expr::Expr)
    quote
         let v = Vector()
             function $(esc(:remember))(x)
             push!(v, x)
             end
          $(esc(expr))
           v
          end
    end
end

Do you mean this?

macro collect(T,expr::Expr)
    quote
        let v = Vector{$T}()
            function $(esc(:remember))(x)
                push!(v, x)
            end
            $(esc(expr))
            v
        end
    end
end
julia> @macroexpand @collect(Float64,remember(42))
quote
    #= REPL[4]:3 =#
    let var"#5#v" = Main.Vector{Main.Float64}()
        #= REPL[4]:4 =#
        function remember(var"#7#x")
            #= REPL[4]:5 =#
            Main.push!(var"#5#v", var"#7#x")
        end
        #= REPL[4]:7 =#
        remember(42)
        #= REPL[4]:8 =#
        var"#5#v"
    end
end

Maybe it would help if you gave a little more detail of what you are trying to achieve. I have a feeling, there might be easier ways to achieve what you are aiming for.

1 Like

(e.g. why are you using a macro for this at all?)

let me clear what i am trying to do with example

v=[1,2,3,4,5.5,6.6]
i=1
@collect(Float64,for i in 1:6
        if v[i]<7
            remember(v[i])
        end
        end )

the output will be

6-element Array{Float64,1}:
1.0
2.0
3.0
4.0
5.5
6.6

I want to decide the data type that I need to return from the Array V

for example, if I need the Integral numbers it should return [ 1 , 2 , 3 , 4 ] only not every element in the vector

So this is what you want?

julia> v = [1,2,3,4,5.5,6.6,7.6,8,9]
       [w for w in v if w < 7]
6-element Array{Float64,1}:
 1.0
 2.0
 3.0
 4.0
 5.5
 6.6
1 Like

Why not do [x for x in v if x < 7]? And if you want a specific type, do e.g. Int[x for x in v if x < 7 && isinteger(x)]?

(90% of the time, if you are writing a macro or doing some other form of metaprogramming, you are making a mistake. In the remaining 10% of cases it is an extremely useful technique.)

4 Likes

not this i want to return for example all Int64 element in the vector so if

v = [ 1 , 2 , 3 , 4.3, 5,6 ]
the output will be
[ 1 , 2 , 3 ]
using the previsue Macro @collect

julia> v = [1,2,3,4,5.5,6.6,7.6,8,9]
       Int[w for w in v if isinteger(w)]
6-element Array{Int64,1}:
 1
 2
 3
 4
 8
 9

yes but i want to do this using macro … the Int64 is an example so i want to make the user able to specify the element type of the vector that is returned.

The #1 rule of macros is don’t use them unless you have to. They will be slow and complicated (unless they are your only option).

f(T, v) = T[w for w in v if typeof(w) <: T]?

1 Like

Keep in mind that there are no Int64 elements in the vector v, it’s a vector of floats:

julia> v = [ 1 , 2 , 3 , 4.3, 5,6 ]
6-element Array{Float64,1}:
 1.0
 2.0
 3.0
 4.3
 5.0
 6.0

If you want to pick out the integers, you should use isinteger which finds numbers that are “numerically equal” to some integer, that is, 2.0 is an integer, 2.1 is not.

If you want actual Int64 in there, you can use a heterogeneous vector with abstract eltype, for example, Real:

julia> v = Real[1, 2, 3, 4.3, Int32(5), 6]
6-element Array{Real,1}:
 1
 2
 3
 4.3
 5
 6

julia> myfind(T, v) = filter(x->isa(x, T), v)
myfind (generic function with 1 method)

julia> myfind(Int64, v)
4-element Array{Real,1}:
 1
 2
 3
 6

julia> myfind(Int32, v)
1-element Array{Real,1}:
 5

julia> myfind(Float64, v)
1-element Array{Real,1}:
 4.3

julia> myfind(Integer, v)
5-element Array{Real,1}:
 1
 2
 3
 5
 6

At any rate I don’t see anything in your examples that indicate that you need (or should use) a macro.

3 Likes