2

What is the memory implication of storing an integer as a particular numeric type (uint8, int16, uint32, int64, etc)? I know the range of integers each of the types can take, but is there some memory efficiency that can be achieved by using an appropriate type?

For example, in Golang, it "seems" more efficient to store someone's age as an uint8 rather than unit (which is equivalent to uint32 or uint64 according to its specification https://golang.org/ref/spec#Numeric_types)

Femi Sotonwa
  • 103
  • 1
  • 4
  • Only arrays / slices benefit from small types. And please: Do not store age in an unsigned. Unsigneds are bitpatterns, not numbers. – Volker Aug 29 '18 at 11:53
  • And structs. And maps. And channels. And anything being sent over the wire or written to disk in binary format. Or mapped to a database table. – Adrian Aug 29 '18 at 13:23
  • @Volker Where can I find out more about why not to use unsigned ints? – Michael Hampton Sep 03 '18 at 22:27
  • @MichaelHampton Just try some simple math with unsigned numbers and experience lots of over/underflows around 0 for innocent looking code. Not sure what you are looking for. Uints are fine and you should use them but not to do arithmetic with what people commonly think of as "natural number". – Volker Sep 04 '18 at 03:44
  • @Volker I was looking for whatever motivated your comment: "Do not store age in an unsigned. Unsigneds are bitpatterns, not numbers." – Michael Hampton Sep 04 '18 at 12:07
  • @MichaelHampton. Well, unsigned ints _are_ bitpatterns and signed ints _are_ numbers. Bit-operations work natural on unsigned and arithmetic works natural on signed ints while the converse is not true. My motivation was to sensibilize the OP to _not_ store age in an unsigned because age is not a bit pattern. – Volker Sep 04 '18 at 12:56

2 Answers2

4

Fixed size integers

Fixed size integers require exact amount of memory. Using a smaller integer type "here and there" for single variables, you will only gain a tiny amount of memory, if any. Also when used as types of struct fields, you again might not gain anything due to implicit paddings.

The memory gain may be noticeable and considerable when you use fixed size integers as the element type of (big) slices or arrays.

Another (maybe more important) reason to use fixed size integers may be to communicate what you store in them. You could just as well use int32 or int64 type to store bytes, but being an obvious waste, they don't communicate the valid range of the data stored in them.

Another point is efficiency. You could always use int64 in place of other signed integer types, but on certain architectures performing operations on int64 might require multiple register operations and thus being considerably slower. Also the rune type (alias for int32) clearly communicates that you intend to use it for unicode codepoints.

Another point is consistency. If you use int32 to model something in one place, you should stick to it and use the same type everywhere. This is more important in Go than in other languages, because Go's type system is strict (stricter than most other language's), meaning if you have a value of type int32, you can't assign it to a variable of int64 type and vice versa without explicit conversion.

int vs fixed size integers

The types int and uint are not fixed sizes, but according to Spec: Numeric types:

uint     either 32 or 64 bits
int      same size as uint

When you use int, the compiler may produce more optimized code when targeting different architectures. Usually int is 32-bit when targeting 32-bit architectures, and 64-bit when targeting 64-bit architectures. What this means is that the size of int will match the target architecture's register size, so integer operations can be efficiently carried out with single register operations. If you use int64 for example, that may require to perform multiple (register) operations to carry out a single integer operation on a 32-bit architecture.

I like to think of int being an integer type that is used to describe and communicate certain parts or components of Go's runtime data structures in the best way it sees fits. For example to index arrays or slices, or to describe their sizes, int is the "natural" type to use.

Spec: Length and capactiy:

The built-in functions len and cap take arguments of various types and return a result of type int. The implementation guarantees that the result always fits into an int. For example indexing slices or array, or to describe their length and capacity, int is the "natural" type recommended or enforced.

When using the for range statement with at least one iteration variable on arrays, slices or string values, the iteration variable (the "index") will be of type int.

Also note that a proposal has been presented by Rob Pike for Go 2 to change int to arbitrary precision. proposal: spec: change int to be arbitrary precision

icza
  • 389,944
  • 63
  • 907
  • 827
2

1) Fixed size integers can be used to reduce the memory used by your application. In a 3D app for example it can make more sense to use float32 rather than float64 because the graphics card wants float32s anyway and to use uint16 rather than uint32 for draw indices for example.

That said, for single variables it makes no difference, only if you have a large number of values and can trade precision for memory.

2) When writing to disk, e.g. using the encoding/binary package, you cannot use int or uint because their size changes between operating systems. You have to use values of known size to make the file format unambiguous.

3) When interfacing with the operating system's API it is often required to use fixed-size variables. For example, the Windows API is a 32 bit API which means that when you load a Windows DLL you often need to use 32 bit unsigned integers for flags etc.

gonutz
  • 5,087
  • 3
  • 22
  • 40