# What changed in 0.12

> Breaking numeric semantics, new syntax (own, par for, unchecked), ownership, fork/join, and how to update code from 0.11.

Canonical: https://alice-lang.org/documentation/reference/whats-new-0-12/

[Documentation index](https://alice-lang.org/documentation/llms.txt) · [Complete book](https://alice-lang.org/llms-full.txt)

Alice 0.12 makes numbers behave exactly, adds syntax that hands performance decisions to the compiler, and moves a large part of hot-loop memory traffic off the garbage collector. This page lists what changes for existing code and what is new. The full list is in the [changelog](https://github.com/alicelanguage/alice/blob/main/CHANGELOG.md).

## Breaking: numbers

| Before 0.12                             | From 0.12                                                                |
| --------------------------------------- | ------------------------------------------------------------------------ |
| `-7 / 2` was `-3` (truncating)          | `-7 / 2` is `-4`, `-7 % 2` is `1` (floored, like `divmod`)               |
| Integer overflow wrapped silently       | It raises `OverflowException`; `&+ &- &*` wrap                           |
| `2 ** -1` returned `1`                  | It raises                                                                |
| `300.to_u8` wrapped                     | Sized conversions raise when the value does not fit; `to_u8!` wraps      |
| `2.5.round` followed banker's rounding  | Half away from zero: `3.0`                                               |
| Floats could print as `2`               | Always with a decimal point: `2.0`, `1.0e-07`, `1.0e+16`                 |
| `Channel(T).new` buffered without limit | Unbuffered: `send` waits for a receiver; `Channel(T).new(n)` buffers `n` |

To update: use `tdiv` and `remainder` where you relied on truncation, `&+ &- &*` or an `unchecked` region where you relied on wraparound, `to_X!` for wrapping conversions, and `Channel(T).new(n)` for a buffered channel. Programs that print floats will show `.0` where they printed integers.

## New syntax

### `own`

```alice
own row = Array(Int32).new(n)
```

Declares a local array the compiler must prove is the only reference to its buffer. The buffer is recycled where the program drops it. An escape is AL0207 and a read after a move is AL0208. Without `own`, the same ownership is inferred silently where it holds. See [ownership](https://alice-lang.org/documentation/advanced/ownership.md).

### `par for`

```alice
par for y in 0...h
  for x in 0...w
    img[y * w + x] = shade(x, y)
  end
end
```

Parallel at any trip count, or compile error AL0209 when the iterations are not provably independent. See [fork/join and parallel loops](https://alice-lang.org/documentation/concurrency/fork-join.md).

### `unchecked`

```alice
unchecked
  h = h * 31 + c.ord
end
```

Integer `+ - *` inside wrap instead of raising. Conversions such as `to_i32` and `**` still check.

### Smaller additions

- Hex and binary literals take `_` separators and type suffixes: `0xFFFF_FFFF_i64`, `0xFF_u8`.
- `q, r = 7.divmod(2)` destructures without allocating; multiple assignment destructures arrays and lists.
- New numeric methods: `to_i8` to `to_u64`, `fdiv`, `sign`, `popcount`, `leading_zeros_count`, `trailing_zeros_count`, `bit_length`, `finite?`, and constants such as `Int32::MAX` and `Float64::NAN`.
- `Digest::SHA256.hexdigest`, `Digest::SHA1`, `Digest::MD5`.

## Faster without changes

- A MIR optimizer folds constants, turns floored division by powers of two into shifts and masks, and removes overflow checks that value ranges prove dead.
- Independent recursive calls fork across cores; large loops, including row-major image loops, run in parallel when proven independent.
- Parallel loops and forks use a lean scheduler: one job per loop, no `Task` per fork.
- Non-escaping local arrays are recycled instead of collected.
- `sort`, `sum`, `min`, `max` of large primitive arrays use fork/join.
- Self-recursive numeric kernels are compiled fully optimized from their first call.

## Fixed

- A loop that read the array it writes at another index (`row[j] = row[j - 1] + ...`) could be parallelized at 65,536 or more iterations and compute wrong values. It now stays serial.
- An exception inside an automatically parallelized loop reaches the caller as itself, as in the serial loop.
- `(-5).abs`, `round(n)` on decimal fractions, `Array(T).new(n, v)` ignoring `v`, and `Array(T).new(n) { |i| ... }` ignoring its block.

## New diagnostics

| Code   | Meaning                                        |
| ------ | ---------------------------------------------- |
| AL0207 | An `own` array escapes.                        |
| AL0208 | A moved local is used before it is reassigned. |
| AL0209 | A `par for` loop is not provably independent.  |

## Continue reading

- Previous: [Syntax quick reference](https://alice-lang.org/documentation/reference/syntax.md)
