2

There are some similar designs in the go interface. For example, the results of reading and writing can only be values >= 0. Why not just use the unsigned int type? What is the purpose of using signed types?

// The Copy function uses ReaderFrom if available.
type ReaderFrom interface {
    ReadFrom(r Reader) (n int64, err error)
}

// The Copy function uses WriterTo if available.
type WriterTo interface {
    WriteTo(w Writer) (n int64, err error)
}
Time Killer
  • 693
  • 8
  • 21
  • I would imagine that int64 is more efficient on most modern hardware. Of course they could use uint64, but why bother? Nobody's ever going to read 18 exabytes in a single operation. – Jonathan Hall Apr 21 '20 at 07:53
  • 1
    Possible duplicate: https://stackoverflow.com/q/29658892/13860 – Jonathan Hall Apr 21 '20 at 07:55
  • 1
    First of all: Such functions should use the nativ integer type, that is either `int` or `uint` and not a specific bitsize variant. So it is either `int` or `uint`. What lots of people do get wrong is: `uint` is **not** a "positive integer number". A uint is a bitpattern, it is _not_ per se a number. (The fact that +, - etc are defined on uints doesn make them conceptualiy numbers). – Volker Apr 21 '20 at 08:12
  • 5
    Working with uints as if they were numbers is a loaded footgun as over/underflow occurs at _both_ _ends_ of the value range, that is 0 and "a lot". Values around 0 are very common and lead to ugly bugs. (Overflow happens for ints too, but on modern systems a int is 64 bits and it overflows at _highly_ _uncommon_ values but not around the common 0). It is wrong to treat uints as "non negative integers": You gain nothing at the increased risk of underflow bugs. – Volker Apr 21 '20 at 08:18
  • @Volker Can you submit it to the answer area so that novices can get a correct idea. – Time Killer Apr 21 '20 at 09:12

1 Answers1

10

I found a good explanation in the book Go Programming Language (A. Donovan, B. Kernighan):

Although Go provides unsigned numbers and arithmetic, we tend to use the signed int form even for quantities that can’t be negative, such as the length of an array, though uint might seem a more obvious choice. Indeed, the built-in len function returns a signed int, as in this loop which announces prize medals in reverse order:

medals := []string{"gold", "silver", "bronze"}
    for i := len(medals) - 1; i >= 0; i-- {
    fmt.Println(medals[i]) // "bronze", "silver", "gold"
}

The alternative would be calamitous. If len returned an unsigned number, then i too would be a uint, and the condition i >= 0 would always be true by definition. After the third iteration, in which i == 0, the i-- statement would cause i to become not −1, but the maximum uint value, and the evaluation of medals[i] would fail at run time, or panic, by attempting to access an element outside the bounds of the slice. For this reason, unsigned numbers tend to be used only when their bitwise operators or peculiar arithmetic operators are required, as when implementing bit sets, parsing binary file.

Anton
  • 1,793
  • 10
  • 20