Programming Language

Nocter

A self-contained systems language built around simplicity, encapsulation, and foolproof design.

/development/docs/iteration.md

Explicit Iteration and Collection Access

This document owns the compiler and standard-library design for v0.3.0 Phase 2. Public semantics belong to Strings, Arrays, Views, and Pointers, and the completed gate belongs to the v0.3.0 Release Record.

Phase 2 completed on 2026-08-02. This document records the implemented boundary; it is no longer an active checklist.

Separate Concepts

ConceptMeaning
readonly view iterationan allocation-free cursor borrowing contiguous source storage
owned vector iterationa cursor that owns vector storage and moves elements out once
iterator result provenancethe source storage origin retained by a returned element borrow
initialized prefixcompleted vector elements currently owned by Vec<T>
remaining iterator rangeinitialized elements still owned by VecIntoIter<T>
transient shift holeone temporarily uninitialized slot during a non-fallible insert/remove shift

Iterator type names and method names have no compiler meaning. Resolution uses ordinary declaration identity, generic specialization, receiver capability, and callable provenance summaries.

Readonly Iteration

ViewIter<T> stores a readonly &[T] and the next index. Construction does not allocate. Its next() method advances the cursor only after establishing the returned element borrow.

pub struct ViewIter<T> {
    view: &[T]
    next: usize
}

impl<T> ViewIter<T> {
    pub method &+self.next(): &T? { ... }
}

The result origin is the stored view's origin, not the iterator object's stack location and not an untracked raw pointer. Returning the iterator from a helper maps that origin through the ordinary aggregate and callable-summary model. A raw pointer may be used by trusted lowering but cannot be the semantic source of provenance.

Distributed std provides a constructor from &[T], Vec<T>.iter(), and String.bytes_iter(). Until structural inherent methods on built-in view types have their own reviewed language design, &[T] uses the named constructor rather than compiler or resolver special casing.

Owned Iteration

VecIntoIter<T> owns the original raw storage and a remaining half-open range. Converting from Vec<T> transfers storage and every initialized element obligation into the iterator, then leaves the consumed vector with no live element or storage obligation.

next() removes the lowest remaining element, advances the range, and returns ownership as T?. The iterator destructor drops the still-owned range in reverse index order. RawBuffer then performs the one final storage release through its ordinary backend identity.

No byte copy may leave two live semantic owners. Extracted elements are removed with the same trusted take operation used by Vec.pop().

Access and Mutation

Vec.get(index) and Vec.get_mut(index) return optional borrows and retain the vector storage origin. They do not copy generic elements.

try_insert completes all fallible capacity work before shifting elements. After capacity succeeds, the shift contains no fallible call or early control edge. It maintains one transient hole, moves the hole toward the insertion index, fills it with the new value, and publishes len last.

remove takes the selected element, moves later elements left through one transient hole, decrements len, and returns the removed owner. Bounds absence returns none before creating a hole. This is not a sparse vector model: no reachable function boundary or cleanup edge can observe the temporary hole.

Compiler Boundaries

ResponsibilityOwner
element-place type and borrow checkstypecheck/arrays and ownership place analysis
aggregate/view provenance projectiontypecheck/provenance and callable summaries
optional borrowed/owned return loweringir/lower/optional_fallible and expression lowering
raw element borrow/take/store/drop operationsfocused ir/lower pointer operation modules
remaining-range cleanupordinary VecIntoIter<T> drop body plus recursive drop lowering
editor-facing specialization/provenanceanalysis facts; protocol conversion in driver/lsp

Buildability must reject an iterator body before IR if a required general operation is not promoted. IR and backend code do not inspect ViewIter, VecIntoIter, iter, next, get, or remove spellings.

LSP Boundary

Existing compiler-backed method queries must specialize T from the receiver. Hover and signature help show &T? or T? exactly. Completion respects &self versus &+self, so repeated next() requires a writable iterator binding. Provenance detail comes from callable semantic facts.

Incomplete .next( edits reuse ordinary member and call recovery. Phase 2 does not add an iterator-specific recovery parser.

Zero-argument calls and calls waiting for a first argument are syntactically ambiguous while open. Generic signature recovery therefore tries both a closed empty call and a typed placeholder overlay, then accepts the first compiler analysis that resolves a callable. This also improves ordinary non-iterator calls.

Implemented Foundations

  • borrowed local and call ABI values preserve concrete slice-element addresses and callable provenance
  • optional and fallible control-flow wrappers preserve every possible returned borrow source
  • generic take_value_at_ptr bindings specialize at the IR binding boundary and reuse ordinary scalar or aggregate drop tracking
  • optional aggregate failure branches mark uninitialized destinations inactive before lowering break, return, and other fallback control flow
  • distributed std/iter, std/vec_into_iter, std/vec, and std/string contain the public API; compiler and backend code contain no iterator-name dispatch