Int v UInt

Is there any reason Int, and not UInt, is the canonical type for sizes? E.g. typeof(length(some_array)) is Int.

Unrelated to Julia, but here is the C++ library Eigen’s answer to that question:

At a first glance it is indeed very tempting to use an unsigned type for values that are expected to be positive or zero. However, unsigned types relies on modulo 2^k arithmetic, which is definitely not what we want here. Moreover, in many places we can have negative indices and offsets. Mixing signed and unsigned integers is costly, error prone, and highly correlated to bugs. As a result, it is much simpler and safer to use signed integers everywhere, and reserve the usage of unsigned integers for bitwise manipulation and modulo 2^k arithmetic.

Hm… but the STL use unsigned integers everywhere. Right, but this has been acknowledge as a mistake by several members of the C++ standardization committee and C++ experts (Bjarne Stroustrup, Herb Sutter, Chandler Carruth, Eric Niebler, etc.).

http://eigen.tuxfamily.org/index.php?title=FAQ#Why_Eigen.27s_API_is_using_signed_integers_for_sizes.2C_indices.2C_etc..3F

11 Likes

Also unsigned integers don’t buy you that much: you only get a factor of 2 increase. Perhaps in the 32-bit days there was an argument to be made (e.g. so I can have 4GB instead of 2GB arrays), but now that 64-bit platforms are basically standard there are very few cases where integers between 2^63 and 2^64 are especially useful.

3 Likes

Excellent reference! Basically: I will use negative values elsewhere in my code and mixing signed/unsigned easily introduces bugs, so it is preferable to maintain a uniform representation across the codebase.

I always used unsigned values so as to avoid domain errors, but an assert can easily take care of that too.

You’ll automatically get a bounds error if you’re using a negative index:

julia> x[-2]
ERROR: BoundsError: attempt to access 4-element Array{Float64,1} at index [-2]
Stacktrace:
 [1] getindex(::Array{Float64,1}, ::Int64) at ./array.jl:549

Unless you opt out with @inbounds, or using something like an offset array where those indices are valid.

So you don’t need to manually test. You can also start julia with --check-bounds=yes to ignore @inbounds while debugging. That also happens automatically when running tests.

While you’ll probably never intentionally want an index higher than a 64 bit signed integer offers, some strange bug could cause you to shoot that high. Rolling over makes it less likely you’ll notice:

julia> x = 1:4;

julia> x[typemax(Int)+2]
ERROR: BoundsError: attempt to access 4-element UnitRange{Int64} at index [-9223372036854775807]
Stacktrace:
 [1] throw_boundserror(::UnitRange{Int64}, ::Int64) at ./abstractarray.jl:434
 [2] getindex(::UnitRange{Int64}, ::Int64) at ./range.jl:477

julia> x[typemax(UInt)+2]
1

(With the caveat there that typemax(UInt) is twice typemax(Int), so the two cases in the example above aren’t strictly equivalent.)

3 Likes