Integers

Eight sized integer types with fixed ranges on every platform, an unannotated literal is always Int64, and overflow is a compile error when it is written and a panic when it happens at runtime.

Diese Seite gibt es noch nicht auf Deutsch, deshalb steht sie hier auf Englisch. Zur englischen Seite

An integer type always carries its width: Int8 through Int64 signed, UInt8 through UInt64 unsigned. There is no platform-dependent "the native integer size" - the same program overflows at the same value on every platform.

Example#

const count: Int = 5
const byte: UInt8 = 200
const smallest: Int8 = Int8.minimum
const largest: Int8 = Int8.maximum

print "{count} {byte} {smallest} {largest}"

Syntax#

Int8 Int16 Int32 Int64                   signed, in increasing width
UInt8 UInt16 UInt32 UInt64                unsigned, in increasing width
Int UInt                                  aliases for the 64-bit width
Type.minimum  Type.maximum                the smallest and largest value of a type

Rules#

  1. Int is an alias for Int64, and UInt is an alias for UInt64. Write Int for "a number" and the sized name when the width itself is the point - a binary format, FFI, memory layout.

  2. An integer literal without an expected type is Int64. This is fixed and does not follow the Int alias, so a file that shadows Int still has Int64 literals. See Literals.

  3. Every integer type carries minimum and maximum as its own constants, so a bound is named instead of repeated: Int8.minimum is -128, Int8.maximum is 127, UInt64.maximum is 18446744073709551615.

  4. A literal that does not fit its target type is a compile error at the literal, not at some later use. It is read in its target type and never as an Int64 first, so a UInt64 takes every literal up to 18446744073709551615, the upper half an Int64 does not have included.

    Kompiliert nicht
    const small: Int8 = 300
    // error: `300` does not fit into `Int8`
    const basis: UInt64 = 14695981039346656037
    print basis
  5. Overflow at runtime panics; overflow written directly in the source is caught where it is written. Rule 4 is the compile-time half of this rule; the runtime half is the same panic every other bug produces (see what a panic does).

  6. Integer division truncates toward zero, and the remainder takes the sign of the dividend. -7 / 2 is -3, -7 % 2 is -1, so a is always (a / b) * b + a % b. Dividing by zero panics, and so does dividing the smallest value of a signed type by -1 - an overflow like any other.

  7. There are no implicit numeric conversions. Converting between two integer types, or between an integer and a Float, always goes through From, TryFrom or .into().

    Kompiliert nicht
    const whole: Int64 = 5
    const asFloat: Float = whole
    // error: Expected `Float64`, found `Int64`
    const whole: Int64 = 5
    const asFloat = Float.from whole
    print asFloat
  8. A widening conversion is From and never fails; a narrowing one is TryFrom and returns a Result. Every signed type widens into a larger signed type, and every unsigned type up to UInt32 widens into Int64. Narrowing (Int64 into Int8, Int64 into Int32, Float64 into Int64) is TryFrom<..., NumberRangeError>.

    const big: Int64 = 300
    const narrowed = Int8.tryFrom big
    match narrowed {
      Ok(value) => print value
      Fail(problem) => print problem
    }
  9. &, |, ^, ~, << and >> are the bit operators of every integer type, and the members of Bits. & binds like *, | and ^ like +, a shift between * and **, so flags & 1 == 0 is (flags & 1) == 0. A shift of a signed type is arithmetic and one of an unsigned type logical, the bits that leave the width are dropped, and a shift by a negative amount or by the width of the type or more panics.

    const flags: UInt8 = 0xFF
    const masked = flags & 0x0F
    const shifted = flags << 2
    print "{masked} {shifted} {~masked}"
    // prints 15 252 240
  10. Every operator that can panic has a checked twin that answers an Option. addedChecked, subtractedChecked, multipliedChecked, dividedChecked and remainderChecked belong to every integer type, through the trait Integer, and answer None exactly where +, -, *, / and % panic - an overflow, a zero divisor, the smallest value of a signed type divided by -1. The operator says "this fits"; the twin is for a value that comes from outside and may not.

    const stock: Int8 = 100
    print stock.addedChecked(27)
    print stock.addedChecked(28)
    print 7.dividedChecked(0)
    // prints Some(127)
    // prints None
    // prints None
  11. UInt64 alone has addedWrapping and multipliedWrapping, the only arithmetic that does not panic on overflow. They exist for hash functions, which need the wrap; every other numeric type panics on overflow the way + always does.

What this is not#

There is no C trap. In C, x & 1 == 0 is x & (1 == 0); here & binds like *, so it is the test it looks like.

const flags = 0b1010
print(flags & 1 == 0)
// prints true

^ is exclusive or, not a power. A power is **, and a float, which has no bits to combine, says so:

Kompiliert nicht
const wrong = 2.0 ^ 2.0
print wrong
// error: `Float64` has no `^`: it is the exclusive or of two integers
Esc