Vectornaut
Vectornaut

Reputation: 531

How do I grow a Julia array in a type-respecting way?

I'm writing a function that searches through a collection and collects the outputs of some user-supplied functions f and g applied to things it finds.

function search_map_collect(f::Function, g::Function)
  output = []
  # searching through the collection
    # oh look we found an x and a y
      push!(output, f(x, y))
    # whoa, we even found a z
      push!(output, g(x, y, z))
  # end loopy stuff
  return output
end

As the function is written, the output will always have type Array{Any,1}, because that's the type of the empty array. However, it will often be the case that f and g always return values of the same type T. In this case, a built-in function like map would return an output of type Array{T,1}, and I'd like my function to behave the same. Is there a nice way to do this?


If Julia supported function types with signatures, this would be easy. Unfortunately, it doesn't.


If I could easily predict when f or g would first be applied, I could initialize the output array as

  output = [f(x_first, y_first)]

to set the type. Unfortunately, I can't predict the first application.


I realize I could do something horrific like

function complicated_collect(f::Function, g::Function)
  output = Union{}[]
  # searching through the collection
    # oh look we found an x and a y
      if isempty(output)
        output = [f(x, y)]
      else
        push!(output, f(x, y))
      end
    # whoa, we even found a z
      if isempty(output)
        output = [g(x, y, z)]
      else
        push!(output, g(x, y, z))
      end
  # end loopy stuff
  return output
end

but this makes the code much less readable, and it doesn't feel very efficient either.

Upvotes: 2

Views: 452

Answers (1)

Vincent Zoonekynd
Vincent Zoonekynd

Reputation: 32351

If you know the return type when you call the function, you can add it as an argument.

function test1(t::Type, f::Function)
  output = t[]
  for x in 1:5
    push!( output, f(x) )
  end
  output  
end
test1( Float64, exp )
@code_warntype test1(exp)

Since it is type-stable, it should be more efficient than using the type of the first element found.

Upvotes: 5

Related Questions