I'd like to ask about some bizarre behavior I noticed in Julia. Consider the following snippet:
function wut()
mat::Array{Number,2}=[1 2 3; 5 6 7]
mat2::Array{Number,2}=[1 1; 2 3]
return typeof(mat2*mat)
end
wut()
Enormously proud of itself, this outputs Array{Any,2}
. What is going on here? Why isn't the output Array{Number,2}
? If one replaces Number
with Float64
the output is Array{Float64,2}
as it should be, but why does julia think that the multiplication of two matrices made of abstract "numbers" should come out as a matrix made up of "anything under the sun"?
Here's an alternative answer: this is a quirk and implementation detail that should ideally not exist. It's not a result of Julia's type design or dispatch, nor is it really a great design pattern. It's just the status quo.
Matrix multiplication is based upon an in-place API. That is, A*B
becomes mul!(output_array, A, B)
. Thus, we need to pre-allocate the result before actually knowing what will happen. The computation of this output element type is done by a quirky and ill-specified function: promote_op
. It's something that really should be removed but would require a huge and difficult refactor... and thus we have strange cases like this.
For more details, see the docstring of Base.promote_op
(note that it's unexported and doesn't even appear in the online manual):
help?> Base.promote_op
promote_op(f, argtypes...)
Guess what an appropriate container eltype would be for storing results of
f(::argtypes...). The guess is in part based on type inference, so can
change any time.
│ Warning
│
│ Due to its fragility, use of promote_op should be avoided. It is
│ preferable to base the container eltype on the type of the actual
│ elements. Only in the absence of any elements (for an empty result
│ container), it may be unavoidable to call promote_op.
For more internal details on promote_op
see issue #19669, comments in #25689, and their discussion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With