I think it might be a good idea to sort out what could cause a conflict before discussing specific ways for isolation.
1. function name
I think it’s reasonable to assign different function names to different arithmetic and different operations.
That is, checked_add
, saturating_add
and saturating_sub
should all be unique function names.
(The names themselves are debatable, but the uniqueness is the key here.)
Julia allows you to access functions in a variety of ways. For example, we can define wrapper functions such as add(x, y, Val(:checked))
and checked_op(Val(:add), x, y )
. In fact, the argument in the OP is not “how” to implement an operator, but which function to assign to the operator.
https://github.com/JuliaMath/FixedPointNumbers.jl/blob/c6b8a9c134d0cade12c41749931a6b788695eeae/src/FixedPointNumbers.jl#L305-L319
Also, we have a powerful meta-programming feature.
The reason I value the uniqueness of the function names is that if we decide to introduce a more abstract API, it will interrupt my current plans on CheckedArithmetic
or cause a significant rework.
2. operator symbol
Syntactically, operator symbols and function names have almost the same meaning, but semantically they are quite different. (Edit: E.g. the difference between +
and -
is the difference in function names, not the difference between addition and subtraction.) In other words, there are only a limited number of symbols that make sense for a given function. Also, the operators we often use are unary or binary, and if we try to use more than three arguments (i.e. operands), they lose their syntactic charm. The conflict and ambiguity of operators occur in many places, not just in Julia.
Therefore, if you want the same operator symbols to have different functions, we need to differentiate by the (static) types of operands (i.e. multiple dispatch), or provide new types which contain “dynamic” metadata. The latter may seem impractical from a performance standpoint, but I think it’s a feasible approach for “containers” like images.
Another approach is to introduce a DSL for numerical expressions. @checked
is a kind of this approach, in the sense that it replaces the Julia-native operators.
Another solution, which is distinct from the above, is to not use the same symbols. This idea is (jokingly) brought to us by @tim.holy. I don’t think the new operator symbols will be acceptable to all people, but I think it’s worth considering for use in conjunction with another measure, as syntax sugar.
3. type name
If we look at the relationship between the operator and the operands in the opposite direction, we can consider that the operand types are in conflict.
4. promotion rule
Currently, FixedPointNumbers
“directly” overload the operators (e.g. +(::X, ::X) where X <: FixedPoint
), but we can also force a promotion phase by removing the direct overloading. In that case, the promotion rules can conflict. Differences in promotion rules do not manifest themselves as differences in user codes lexically. Although this is an advantage in terms of abstraction, it can cause major confusion.
I think these concepts are not necessarily orthogonal and probably not exhaustive.