Skip to content

CEP-0057: Reassignable Loop Bindings

Draft

Draft proposal for future reassignable loop item and optional payload bindings. V1 loop-introduced bindings are const, and while var is rejected.

Summary

Catalyst should eventually decide whether loop-introduced bindings can be reassignable, and if so which syntax expresses that without confusing local rebinding with collection mutation.

V1 accepts const loop bindings only:

while const item = iter.next() {
}

for item in items {
}

for var item in items {
}

In V1, for var requests mutable collection iteration through MutableIterable(Item). It does not make the loop item binding reassignable.

Motivation

Reassignable loop bindings are useful when an iteration body wants to normalize, transform, or replace a local working value before using it. The naive spelling collides with accepted V1 source forms:

while var item = iter.next() {
  item = transform(item)
}

This looks consistent with if var, but it breaks the V1 rule that loop-introduced bindings are const.

The same problem is sharper for for:

for var item in slice {
  item.* = value
}

Here var selects mutable iteration and item is usually a mutable pointer. If item were also reassignable, item = other would rebind the local pointer, not replace the collection element. V1 keeps element replacement explicit through the yielded item, such as item.* = value.

Proposed Direction

The proposal should decide:

  • whether while optional payload bindings should support a reassignable form;
  • whether for item bindings should support a reassignable form;
  • whether one syntax should cover both while and for;
  • how reassignable binding syntax composes with destructuring binding patterns;
  • how diagnostics distinguish local rebinding from collection element replacement;
  • whether for var remains permanently reserved for mutable iteration selection.

Any accepted design should preserve the V1 meaning of for var as mutable iteration selection. A future feature should not make for var item in xs silently mean both "call iter_mut" and "make item reassignable" unless diagnostics can make the two effects clear.

Example

Possible future shapes include a dedicated loop-binding modifier:

while mutable item = iter.next() {
  item = transform(item)
}

or a body-local declaration, which is already valid V1 and may remain the preferred spelling:

while const item = iter.next() {
  var current = item
  current = transform(current)
}

These examples are illustrative only. The proposal does not reserve mutable or accept a new source form.

V1 Compatibility

V1 rejects while var:

while var item = iter.next() {
}

V1 accepts while const for optional payload loops, plain for for readonly or existing-iterator iteration, and for var for mutable iterable selection. All loop-introduced bindings are const in V1. Code that needs a mutable working value declares a local var inside the loop body.