Not sure why you need the function type in the type signature of your struct. But if that isn’t essential then this alternative will work:
mutable struct Foo{T<:Real}
a::T
f::Function
end
Foo is a concrete type so I would expect it to be efficient:
julia> foo = Foo(1,bar)
Foo{Int64}(1, var"#9#10"())
julia> foo.f = baz
#11 (generic function with 1 method)
julia> isconcretetype(typeof(foo))
true
@code_warntype suggests there might be a type instability but @code_llvm and @code_native both look very efficient.
This function benchmarks well
f(a,f1,f2) = (a.f === f1) ? a.f = f2 : a.f = f1
julia> @benchmark f($foo,$bar,$baz)
BenchmarkTools.Trial: 10000 samples with 1000 evaluations.
Range (min … max): 1.800 ns … 23.100 ns ┊ GC (min … max): 0.00% … 0.00%
Time (median): 2.100 ns ┊ GC (median): 0.00%
Time (mean ± σ): 2.161 ns ± 0.499 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
▅ ▄ █ ▄ ▄ ▅ ▁ ▁ ▁
█▁▁█▁▁▁█▁▁█▁▁▁█▁▁▁█▁▁█▁▁▁▇▁▁█▁▁▁█▁▁▁▅▁▁▆▁▁▁█▁▁▁▁▁▁▃▁▁▁▅▁▁▆ █
1.8 ns Histogram: log(frequency) by time 3.4 ns <
Memory estimate: 0 bytes, allocs estimate: 0.
so it looks like the compiler is generating efficient code for accessing the function field.