Function returning a constant vector (avoid recalculation and reallocation)

I have a function that returns a constant Vector. It is called frequently, and I would prefer if it generated the result once (eg when compiled), and from then on simply returned it without reallocation/regeneration. This is possible since the function is “pure”, in the sense that it always gives the same output for the same input. MWE:

immutable Foo{T <: Real}
    qL::T
    qM::T
    qH::T
    κ::T 
    λ::T 
    σ::T
    α::T
end

function transformations{T <: Foo}(::Type{T})
    [fieldname ∈ [:κ, :α] ? :UNIT_INTERVAL : :POSITIVE_REAL
     for fieldname in fieldnames(T)]
end

Questions:

  1. how to tell whether Julia is recreating the vector every time? I looked at @code_ results but I don’t know how to interpret them, some help with which one to look at and what to look for would be great.
  2. If it is recreating the vector every time, how to make it do what I want? Is this what Base.@pure is for?

A function that allocates an array is not pure, in the sense defined here:

https://github.com/JuliaLang/julia/issues/414#issuecomment-31042912

You can tell it is allocating a different array each time because transformations(Foo{Int}) === transformations(Foo{Int}) will return false. (=== checks whether two things are the same object in memory.)

You could use the Memoize.jl package. But in this case, it seems you return the same array of symbols for all allowed arguments, so I’m not sure why you even use a function at all. Why not just define a constant array? const transformations = [fieldname ∈ [:κ, :α] ? :UNIT_INTERVAL : :POSITIVE_REAL for fieldname in fieldnames(Foo{Int})] seems like it should do the trick.

Because I have various types, and I am using this generic function to provide the above information about them. Managing constants for each type would become unwieldy and error-prone.

If I return a Tuple instead, as in

function transformations{T <: Foo}(::Type{T})
    tuple([fieldname ∈ [:κ, :α] ? :UNIT_INTERVAL : :POSITIVE_REAL
           for fieldname in fieldnames(T)]...)
end

is it allocated and created every time? Can I make it @pure?

I don’t think @pure is the correct tool for this. AFAIU it is pretty much exclusively used when you do type computations but want inference to reason about the result.

Can’t you store them in a Dict with the type in the key?

You could define

const transformation_Foo = _transformation(Foo)
transformation{T<:Foo}(::Type{Foo}) = transformation_Foo

for each type Foo. That way, you still have a transformation(T) function, and it returns a different constant array for each type.

1 Like

In this case, you can actually just stick @generated in front of the function and get the behaviour you want.

1 Like