Answer to the exact question
The runtime error
Error: Nil when slicing beyond list bounds in gleam/list.slice
occurs because gleam/list.slice/3 returns Nil when the requested range is outside the list’s bounds. The function internally performs a drop followed by a take; if either operation tries to skip or take more elements than the list contains, the result is Nil, which propagates to the caller.
list.slice(list, start, end) // returns Nil if start > length or end > length
Why it happens
- Gleam lists are singly‑linked and immutable; their length is not known in advance.
- When
drop consumes the entire list, it returns Nil, causing the subsequent take to also return Nil.
- Similarly, if
end exceeds the list length, take will return Nil once the end of the list is reached.
How to avoid the Nil error
- Compute the list length once with
list.length and guard against start indices that exceed it.
- Use
list.drop/2 and list.take/2 separately, checking the intermediate result for Nil before proceeding.
- For pagination, keep a running offset and only call
slice when the offset is known to be within bounds. If the offset may exceed the list, stop pagination gracefully.
Should the standard library expose a paginated list type?
Pagination with slice is O(n) per page because each call traverses the list from the head. For deep pages (e.g., page 1000 of size 10) this cost becomes noticeable. A dedicated PaginatedList wrapper could store the original list, a cursor offset, and a page size, providing next_page and prev_page operations that move the cursor in O(1) amortised time while still preserving the safety guarantees of List.
Key considerations for adding such a type:
- API surface: It adds a new type and associated functions, which may increase learning curve.
- Immutability and sharing: The wrapper must share the underlying list without retaining unused prefixes, to avoid memory leaks.
- Interoperability: Conversion helpers like
to_list and from_iterator would allow the paginated list to interoperate with existing list and iterator utilities.
- Use‑case fit: If most pagination scenarios involve static lists with known lengths, a paginated list is useful. For streaming or I/O‑bound data where the total size is unknown, the existing
gleam/iterator module (with explicit resource cleanup) may be preferable.
Therefore, a paginated list type could be valuable, but its inclusion depends on the frequency of deep‑page pagination against the cost of extending the API. A lightweight implementation that re‑uses the underlying list and exposes only essential operations would mitigate most concerns.
Missing diagnostic detail
To refine the recommendation, it would help to know whether the lists you paginate are static with a known length or are produced by an iterator where the total size may be unknown. This context determines whether a pure paginated list or an iterator‑based approach is more appropriate.