diff --git a/.github/linters/.markdown-lint.yml b/.github/linters/.markdown-lint.yml index 7e403081..63482d07 100644 --- a/.github/linters/.markdown-lint.yml +++ b/.github/linters/.markdown-lint.yml @@ -1,5 +1,6 @@ { "MD007": { "indent": 4 }, "MD013": false, - "MD026": false + "MD026": false, + "MD033": { "allowed_elements": ["sup"] } } diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..625f80a9 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,12 @@ +# Pony Tutorial + +MkDocs-based tutorial site for the Pony programming language. + +## Local Verification + +- **mkdocs**: Run via venv (`pip install -r requirements.txt`, then `mkdocs serve` or `mkdocs build`) +- **cspell**: Run using a Docker container (CI uses `streetsidesoftware/cspell-action`; locally, use `docker run -v $(pwd):/workdir ghcr.io/streetsidesoftware/cspell:latest "docs/**/*.md"`) + +## Code Samples + +Code samples live in `code-samples/` and are included in docs via `--8<--` snippets inside fenced code blocks. Sample files are bare expressions (no `actor Main`) unless they need to compile standalone. diff --git a/code-samples/arithmetic-numeric-fundamentals.pony b/code-samples/arithmetic-numeric-fundamentals.pony new file mode 100644 index 00000000..009b6d03 --- /dev/null +++ b/code-samples/arithmetic-numeric-fundamentals.pony @@ -0,0 +1,18 @@ +// Unsigned wrap-around: the value wraps from the maximum back to zero +U8(255) + 1 == 0 + +// Unsigned wrap-around: the value wraps from zero to the maximum +U8(0) - 1 == 255 + +// Unsigned integer literal wrap-around: negative literals get wrapped as well +U8(-1) == 255 + +// Signed integers: zero is in the middle of the range, not at the edge +// Compare with U8(0) - 1 above — for signed integers, this is just normal subtraction +I8(0) - 1 == -1 + +// Signed wrap-around: going past the maximum wraps to the minimum +I8(127) + 1 == -128 + +// Signed wrap-around: going past the minimum wraps to the maximum +I8(-128) - 1 == 127 diff --git a/docs/expressions/arithmetic.md b/docs/expressions/arithmetic.md index 1c3bf826..46745322 100644 --- a/docs/expressions/arithmetic.md +++ b/docs/expressions/arithmetic.md @@ -8,11 +8,44 @@ Pony focuses on two goals, performance and safety. From time to time, these two Pony provides different ways of doing arithmetic to give programmers the freedom to chose which operation suits best for them, the safe but slower operation or the fast one, because performance is crucial for the use case. +## Numeric Fundamentals + +Already familiar with integer widths, signed vs. unsigned, and overflow? [Skip ahead](#integers). + +### Integer Widths + +The number in a type name like `U8` or `I32` is the number of bits used to store the value. More bits means a wider range of representable values: + +| Type | Bits | Minimum | Maximum | +| ----- | ---- | ------- | ------- | +| `U8` | 8 | 0 | 255 | +| `I8` | 8 | -128 | 127 | +| `U32` | 32 | 0 | 4294967295 | +| `I32` | 32 | -2147483648 | 2147483647 | + +The pattern: an N-bit unsigned type can hold values from 0 to 2N - 1. An N-bit signed type splits its range roughly in half, covering -2N-1 to 2N-1 - 1. + +### Signed vs. Unsigned + +Unsigned integer types (`U8`, `U16`, `U32`, etc.) represent only non-negative values. All N bits contribute to the magnitude, so the maximum value for a `U8` is 255 (28 - 1). + +Signed integer types (`I8`, `I16`, `I32`, etc.) use two's complement representation, which gives them an asymmetric range. For example, `I8` covers -128 to 127, not -127 to 127. There is one more negative value than positive because zero takes up one of the non-negative slots. + +### Overflow and Underflow + +When an arithmetic operation produces a result outside the representable range, it overflows (too large) or underflows (too small). With fixed-width integers, wrap-around can occur: + +```pony +--8<-- "arithmetic-numeric-fundamentals.pony" +``` + +This wrap-around behaviour is a consequence of how fixed-width binary arithmetic works — the result is computed and then only the low N bits are kept. Different languages handle this differently: some leave it undefined, some throw an exception, and Pony wraps around by default. The next section covers Pony's specific approach in detail. + ## Integers ### Pony's default Integer Arithmetic -Doing arithmetic on integer types in Pony with the well known operators like `+`, `-`, `*`, `/` etc. tries to balance the needs for performance and correctness. All default arithmetic operations do not expose any undefined behaviour or error conditions. That means it handles both the cases for overflow/underflow and division by zero. Overflow/Underflow are handled with proper wrap around semantics, using one's complement on signed integers. In that respect we get behaviour like: +Doing arithmetic on integer types in Pony with the well known operators like `+`, `-`, `*`, `/` etc. tries to balance the needs for performance and correctness. All default arithmetic operations do not expose any undefined behaviour or error conditions. That means it handles both the cases for overflow/underflow and division by zero. Overflow and underflow are handled with wrap-around semantics, using two's complement representation for signed integers. In that respect we get behaviour like: ```pony --8<-- "arithmetic-default-integer-arithmetic.pony"