Why is `promote_type` not applied by `div` with `Int` and `Rational`?

According to the docstring of promote_type:

promote_type represents the default promotion behavior in Julia when operators (usually mathematical) are given arguments of differing types.

And:

julia> promote_type(Int, Rational{Int})
Rational{Int64}

However, 1 ÷ (1//2) returns 2, not 2//1. In part it makes sense, because div always returns integers. But this is against the stated rules, isn’t it?

1 is promoted to 1//1 and

julia> (1//1) ÷ (1//2)
2

Looks consistent to me. Note that promotion only affects the inputs. What output type you get is up to the operator.

2 Likes

Also, promotion is the default. Specific methods are allowed to override this.

Often, this is done for performance reasons. For example, there is a specialized method for complex + real that works as if both arguments were promoted to the same complex type, but is faster (because it only needs to add the real parts).

5 Likes

It is consistent in the sense that div(::Rational{Int}, ::Rational{Int}) always produces an Int. But then, for two floats it returns a float:

julia> 1 ÷ 0.5
2.0

julia> 1 ÷ 0.5f0
2.0f0

I’d argue that it is still unexpected that sometimes div returns the same type as its arguments, sometimes not.

1 Like

For even more nuance, div returns integers, but not necessarily with an Integer type e.g. 2.0 == div(2.5, 1). So after the totally separate promotion of the inputs to Rational{Int}, an output type of Rational{Int} could be reasonable for div. It just wasn’t chosen.

2 Likes

It’s a reasonable argument but it has nothing to do with promotion.

1 Like