# How to calculate a constant the first time a function is called?

Hello, how to calculate a constant the first time a function is called?
not when compiling
not every call

``````foo() = (sleep(1); 1)  # foo calculate a constant
bar(x) = foo() + x  # ????

# first call:
@time bar(2)  # -> 1.001082 seconds (5 allocations: 144 bytes)
# second call:
@time bar(2)  # -> 0.000001 seconds
``````

may be, i dont know
but looks like *hit

``````global FOO = nothing  #

foo() = (sleep(1); global FOO = 1)  # foo calculate a constant

bar(x) = try
FOO + x
catch
foo()
@eval bar(x) = \$FOO + x
return FOO + x
end

@time bar(22)  # -> 1.001544 seconds (247 allocations: 12.344 KiB)
@time bar(22)  # -> 0.000001 seconds
``````
1 Like

Here’s a pretty simple way to do it:

``````const FOO = Ref{Union{Int, Nothing}}(nothing)

function foo()
if FOO[] === nothing
println("expensive calculation running...")
sleep(1)
FOO[] = 1
end
FOO[]
end

bar(x) = foo() + x
``````

Demo:

``````julia> bar(1)
expensive calculation running...
2

julia> bar(2)
3
``````
1 Like

Or, if you do not trust union splitting, you can have one global with a boolean to indicate if the function was already called or not; and the global with the Ref starting with a dummy/undef value.

1 Like

If your function has some input, you might better avoid at all this global state, and wrap the constant precomputed in the input, such that the function is completely self-contained. Something like:

``````julia> struct MyInput
x::Vector{Float64}
constant::Float64
end

julia> MyInput(x::Vector{Float64}) = MyInput(x, length(x)*sum(x)) # invented a calculation for the constant
MyInput

julia> input = MyInput(rand(3)) # here the constant is computed
MyInput([0.607776859483833, 0.630463715553019, 0.01606684134650216], 3.762922249150063)

julia> function foo!(input)
(;x, constant) = input
x .= constant .* x  # mutates the `x` entry of input
end
foo (generic function with 1 method)

julia> foo!(input)
MyInput([2.2870170670702663, 2.372385942536272, 0.06045827477631713], 3.762922249150063)

julia> foo!(input)
MyInput([8.605867405864627, 8.92710384674058, 0.22749978730103176], 3.762922249150063)

``````
1 Like