Summing an array does not return type that matches eltype of the array

This seems strange to me:

julia> typeof(sum(ones(Int32,3,4)))
Int64

Shouldn’t the result be type Int32?

This seems related to Allow to specify the result type of a sum #5311, which was closed way back in 2016. You can, indeed, specify the result type of sum, but the type gets promoted anyway:

julia> typeof(sum(Int32, ones(Int32,3,4)))
Int64

Even explicitly requesting an output type for sum doesn’t do as asked. At some point a sum of a giant array might overflow, so promoting to a bigger integer makes sense. I guess the function/compiler can’t guess when that might occur, so it always promotes. But, it seems like a try/catch could do it. But, we wouldn’t like that in a function used so much.

Is this one of those “it’s gotta work that way” things?

From the help for sum:

The return type is Int for signed integers of less than system word size, and UInt for unsigned integers of less than system word size. For all other
  arguments, a common return type is found to which all arguments are promoted.

...

Note the important difference between sum(A) and reduce(+, A) for arrays with small integer eltype:

  julia> sum(Int8[100, 28])
  128

  julia> reduce(+, Int8[100, 28])
  -128


  In the former case, the integers are widened to system word size and therefore the result is 128. In the latter case, no such widening happens and integer
  overflow results in -128.
4 Likes

If you do a REPL help:

help?> sum

search: sum sum! summary cumsum cumsum! isnumeric VersionNumber issubnormal get_zero_subnormals set_zero_subnormals

  sum(f, itr)

  Sum the results of calling function f on each element of itr.

  The return type is Int for signed integers of less than system word size, and UInt for unsigned integers of less
  than system word size. For all other arguments, a common return type is found to which all arguments are promoted.

  Examples
  ≡≡≡≡≡≡≡≡≡≡

  julia> sum(abs2, [2; 3; 4])
  29

  Note the important difference between sum(A) and reduce(+, A) for arrays with small integer eltype:

  julia> sum(Int8[100, 28])
  128

  julia> reduce(+, Int8[100, 28])
  -128

  In the former case, the integers are widened to system word size and therefore the result is 128. In the latter
  case, no such widening happens and integer overflow results in -128.

it’s explicitly documented together with how to avoid this (reduce). (ninjad by @hendri54 :slight_smile:
So your guess is accurate.
In general I prefer it as it is. It would be more annoying for me, if I had to expect overflows using sum as it is widely used.

I think some deep thoughts have been put into this explicit implementation.

1 Like

… and the reason why “requesting” the return type does not work, as in

is that this syntax is not actually requesting a return type. It is equivalent to

sum(Int32.(ones(Int32, 3, 4)))

So the Int32 is applied before summing (which widens the type). Of course,

julia> typeof(Int32.(sum(ones(Int32, 3,2))))
Int32

is always an option.

3 Likes

Great, thanks. My misunderstanding.

I could always do the conversion of the result explicitly.

It’s in a hot loop and I was trying to minimize other unintended conversions.

Solved by other means.