Does anyone program like this?

Voting for @Tamas_Papp’s solution.
Maybe even more idiomatic is to put such things into a struct that would always contain consistent values:

struct VoltCurRes{T<:Number}
    voltage::T
    current::T
    resistance::T
    function VoltCurRes(volt::V, cur::I, res::R) where {V<:Number, I<:Number, R<:Number}
        struct_type = reduce(promote_type, (V, I, R))
        new{struct_type}(volt, cur, res)
    end
end

VoltCurRes(volt::Missing, cur::Number, res::Number) = VoltCurRes(cur * res, cur, res)

VoltCurRes(volt::Number, cur::Missing, res::Number) = VoltCurRes(volt, volt / res, res)

VoltCurRes(volt::Number, cur::Number, res::Missing) = VoltCurRes(volt, cur, volt / cur)

Update: While the logic here is almost the same as with ismissing() checks, there is at least one logical and one performance-relevant difference.
The logical difference is, the functions as written by Tamas and myself explicitly require exactly one missing argument and will give an error if there are more.
The performance difference is that the type matching can be done at compile time while the ismissing() checks have to be done at runtime, which makes the version employing multiple dispatch faster in some cases.

9 Likes