# Spans, buffers, and pooling

> Use views without copies, respect buffer leases, and return pooled arrays safely.

Canonical: https://alice-lang.org/documentation/advanced/buffers/

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

## A span is a view

`Span(T)` and `ReadOnlySpan(T)` describe a region of existing memory. Slicing a view can avoid copying the underlying elements. A view still has a lifetime and an owner; it does not make its backing storage immutable or exclusively yours.

```alice
text = "hello world"
view = text.AsSpan(6)
puts view.Length
puts view.ToString()
puts MemoryExtensions.IndexOf(text.AsSpan(), 'w')
```

Expected output:

```text
5
world
6
```

[Edit and run in the Alice playground](https://playground.alice-lang.org/#code=u.dGV4dCA9ICJoZWxsbyB3b3JsZCIKdmlldyA9IHRleHQuQXNTcGFuKDYpCnB1dHMgdmlldy5MZW5ndGgKcHV0cyB2aWV3LlRvU3RyaW5nKCkKcHV0cyBNZW1vcnlFeHRlbnNpb25zLkluZGV4T2YodGV4dC5Bc1NwYW4oKSwgJ3cnKQ)

`AsSpan(6)` views the last five characters. `ToString()` materializes a string, so avoiding a slice copy does not mean every later operation allocates nothing. Use the view directly with APIs that accept spans where practical.

## Span versus memory

| Use                                                        | Typical choice                                              |
| ---------------------------------------------------------- | ----------------------------------------------------------- |
| Synchronous work over a borrowed region                    | `Span(T)` / `ReadOnlySpan(T)`                               |
| A region that must be stored or retained across async work | `Memory(T)` / `ReadOnlyMemory(T)` with an appropriate owner |
| A fixed owned numeric dataset                              | `Array(T)`                                                  |
| Reusable temporary array storage                           | `ArrayPool(T)` with a clear lease                           |

A read-only view stops writes through that view; it does not guarantee another alias cannot mutate the storage. Follow [.NET's memory and span guidelines](https://learn.microsoft.com/en-us/dotnet/standard/memory-and-spans/memory-t-usage-guidelines), especially for async consumers.

## Rent and return an array

Pooling can reduce repeated allocation for temporary buffers. It also adds a lifetime contract that the Alice type checker does not prove for you.

```alice
using System.Buffers
pool = ArrayPool(Int32).Shared
buffer = pool.Rent(4)
begin
  for i in 0...4
    buffer[i] = i + 1
  end
  total = 0
  for i in 0...4
    total += buffer[i]
  end
  puts total
ensure
  pool.Return(buffer, true)
end
```

Expected output:

```text
10
```

[Edit and run in the Alice playground](https://playground.alice-lang.org/#code=u.dXNpbmcgU3lzdGVtLkJ1ZmZlcnMKcG9vbCA9IEFycmF5UG9vbChJbnQzMikuU2hhcmVkCmJ1ZmZlciA9IHBvb2wuUmVudCg0KQpiZWdpbgogIGZvciBpIGluIDAuLi40CiAgICBidWZmZXJbaV0gPSBpICsgMQogIGVuZAogIHRvdGFsID0gMAogIGZvciBpIGluIDAuLi40CiAgICB0b3RhbCArPSBidWZmZXJbaV0KICBlbmQKICBwdXRzIHRvdGFsCmVuc3VyZQogIHBvb2wuUmV0dXJuKGJ1ZmZlciwgdHJ1ZSkKZW5k)

The requested length is four, and the loops use exactly those four initialized elements. The rented array may be larger and may contain previous data. `Rent` promises at least the requested capacity, not an exact-size or cleared array. See the [Rent contract](https://learn.microsoft.com/en-us/dotnet/api/system.buffers.arraypool-1.rent?view=net-10.0).

`ensure` returns the lease even if processing fails. Return to the same pool exactly once, and stop using every alias after return. The example passes `true` to request clearing when the array is retained by the pool; that helps prevent a subsequent renter from observing the prior contents. See the [Return contract](https://learn.microsoft.com/en-us/dotnet/api/system.buffers.arraypool-1.return?view=net-10.0).

## Capacity is not initialized data

A parser or network operation should carry the number of valid elements separately from buffer capacity. Passing the entire rented array to serialization or output can expose unwritten trailing data. Initialize the region you read, validate lengths, and restrict APIs to the populated region.

Clearing on return is not a universal secret-erasure guarantee: copies, strings, logs, and storage the pool discards may remain. Use the security API appropriate to the secret and its representation.

## Async and concurrent borrowers

Do not return an array until every asynchronous operation using it has completed. Do not hand the same mutable region to concurrent writers unless their regions are actually disjoint and the API supports it. AL0202 does not model arbitrary external buffer leases.

## When pooling is appropriate

Measure first. Long-lived data usually needs a straightforward owner, not a perpetual pool lease. Pooling tiny infrequent buffers can add complexity without a meaningful benefit, while unbounded caching can increase retained memory. See [profiling](https://alice-lang.org/documentation/advanced/profiling.md) for distinguishing allocation rate from live memory.

## Continue reading

- Previous: [Resources and deterministic cleanup](https://alice-lang.org/documentation/advanced/resources.md)
- Next: [Measure allocation and retained memory](https://alice-lang.org/documentation/advanced/profiling.md)
