Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/linters/.markdown-lint.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"MD007": { "indent": 4 },
"MD013": false,
"MD026": false
"MD026": false,
"MD033": { "allowed_elements": ["sup"] }
}
12 changes: 12 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -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.
18 changes: 18 additions & 0 deletions code-samples/arithmetic-numeric-fundamentals.pony
Original file line number Diff line number Diff line change
@@ -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
35 changes: 34 additions & 1 deletion docs/expressions/arithmetic.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 2<sup>N</sup> - 1. An N-bit signed type splits its range roughly in half, covering -2<sup>N-1</sup> to 2<sup>N-1</sup> - 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 (2<sup>8</sup> - 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"
Expand Down