I am aware of some related discussion (Have a function field in a structure, using another field in the structure and Alternative to function as field in struct), but the discussion there is insufficient for my case. Therefore, it is probably useful to start a separate thread here.
If, for example, I need to define a type AtomicOrbital
as
struct AtomicOrbital
n::Int64
l::Int64
m::Int64
radial_function::Function
end
where the radial_function
should be specified by the user to describe the radial part of the atomic orbital. The definition above is not completely satisfactory, since Function
is an abstract type and such definition will hurt performance. However, storing the radial_function
inside the struct seems to be the most reasonable way to organize data.
To eliminate the abstract type, the above type can be defined as
struct AtomicOrbital{T<:Function}
n::Int64
l::Int64
m::Int64
radial_function::T
end
However, I am not completely comfortable with the above definition. One reason is that this definition does not seem to be logical to me. r -> exp(-r)
and r -> exp(-2r)
lead to two different concrete types, which is logically weird. Another reason is that I am not sure whether this approach will put too much pressure on the Julia compiler.
Another way to improve the performance is to define an abstract type
abstract type AbstractAtomicOrbital end
function get_radial end
and ask the user to defined custom types as
struct MyAtomicOrbital <: AbstractAtomicOrbital
n::Int64
l::Int64
m::Int64
end
function get_radial(orbital, r)
return exp(-r)
end
However, with this approach, I partially lose control of how AtomicOrbital
is defined. If, for some reason, I want to define
function transform_orbital(orbital::AbstractAtomicOrbital)
# do something to define new orbital
return new_orbital
end
to transform one atomic orbital into another (e.g., make the radial function decay quicker). I have no idea how transform_orbital
should be defined, since I don’t have information how MyAtomicOrbital
is defined by the user.
So how do people generally handle this kind of situation, which I believe is not that rare in the real world?
Another related question: why Julia does not have something like Function{Float64,Float64}
to specify the input and output of a function? It seems to solve the above issue.