Here is a case where I could use
either a function or a struct/type:
function bounded(val::Real, lo::Real, hi::Real)
@assert isfinite(lo) && isfinite(hi) && isfinite(val)
lo <= val <= hi
end
struct Bounds{T <: Real}
lo::T
hi::T
Bounds(lo::T, hi::T) where {T} = (@assert isfinite(lo) && isfinite(hi); new{T}(lo, hi))
end
(b::Bounds)(val::Real) = (@assert isfinite(val); b.lo <= val <= b.hi)
@assert Bounds(0, 1)(0.5)
@assert bounded(0.5, 0, 1)
I understand that if I am checking lots of values against the same bounds, a struct/type might make sense. What if that’s not the case?
Here’s another case where I can define a vector of objects or object containing a vector.
struct OnlyZero{T <: Real}
x::T
OnlyZero(x::T) where {T} = (@assert iszero(x); new{T}(x))
end
struct OnlyZeros{T <: Real}
x::Vector{T}
OnlyZeros(x::Vector{T}) where {T} = (@assert all(iszero.(x)); new{T}(x)) # Can do `iszero(x)` instead of `all(iszero.(x))` in new versions of Julia
end
one is safer than the other in the following sense:
veczeros = [OnlyZero(0 - 0), OnlyZero(1 - 1)]
# veczeros[1] = OnlyZero(0 - 1) # errors. safe.
vec_zeros = OnlyZeros([(0 - 0), (1 - 1)])
vec_zeros.x[1] = 0 - 1 # does not error. unsafe.
I like the idea of making structs constructors do validation. But are objects costly to create? Are they more/less costly in Julia than in other languages?