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:
- 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.
- 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