Borrowing Becomes the House Style
Talk flips ordinary parameters to shared borrows, gives for loops typed access lanes, turns protocol-head extensions into blanket conformances, and sweetens calls, characters, tests, and iterators.
Today's Talk issue is about putting the program's intent on the surface. Parameters now say when a callee may read, mutate, or consume a value. For loops keep their source shape long enough for the checker to choose the right iterator. Protocol extensions can describe real blanket conformances. Arrays, characters, closures, and the test command all pick up smaller conveniences that make the new rules easier to use.
An unadorned function parameter is now a shared borrow. The old owned-parameter
meaning
moves to consume x: T, exclusive write-back is spelled mut x: T, and
borrow x: T gives initializers a way to opt out of their still-consuming default.
Call sites get matching markers. f(consume value) forces a move,
f(copy value) asks
for the cheap clone, and f(borrow value) or f(mut value) asserts the mode the
callee
promised. The checker now rejects temporaries passed to mut and rejects extra write-back
parameters instead of pretending those mutations can land somewhere.
func read(x: Foo) -> Void { () } func update(mut x: Foo) -> Void { () } func store(consume x: Foo) -> Void { () } read(value) update(mut value) store(consume value)
for is no longer thrown away before name resolution. The parser keeps a
real
StmtKind::For, the checker resolves the implicit iter, iter_mut,
or
into_iter call, and typed-program building elaborates the checked plan into ordinary calls
for
flow and lowering.
The source marker now matters. A plain loop borrows through iter(), a mutable loop borrows
through iter_mut() and stores the binder back with _store_current, and a
consuming
loop moves through into_iter(). Unsupported mut sources and consumed sources used after the
loop
are diagnosed in the ownership pass.
for item in items { inspect(item) } for item in mut items { item = item + 1 } for item in consume items { take(item) }
Protocol-head extensions now act like conformance axiom schemes. An extension of
Iterator to Into<Array<Element>> means every concrete iterator can
satisfy that Into target when its premises hold, not that there is a nominal type literally
named
Iterator in the conformance table.
The solver matches those non-nominal conformances, substitutes protocol Self, protocol
inputs,
and associated projections, and carries the selected evidence through member lookup into typed output.
Overlaps become overlap diagnostics, recursive applications report recursive conformance, and a hard
solver
step limit keeps bad graphs from turning into overflow.
extend Iterator: Into<Array<Element>> { consuming func into() -> Array<Element> { self.to_array() } }
Core iteration was reshaped around those rules. Iterator exposes
consuming
map, skip, to_array, and a default into_iter.
Array now publishes borrowed, mutable, and consuming iterator paths, with
ArrayIntoIterator taking ownership of storage and dropping any unconsumed elements from its
current position.
let a = [1, 2, 3, 4] assert( a.map { $0.show() }.to_array() == [ "1", "2", "3", "4" ] ) assert( a.skip(2).to_array() == [3, 4] )
Trying desperately to never have to type &.
- For better or worse
Single-quoted character literals now have their own token and expression form. The
lexer
distinguishes 'a', '\n', and '\'' from effect names, validates
escapes,
and carries characters through formatting, highlighting, type checking, and lowering as
Character
values.
Calls picked up a matching set of small conveniences. A call can omit parentheses when its first
argument is
a string literal, a parenthesized final block can become the trailing block, and closures can synthesize
positional parameters from $0, $1, and friends.
let newline: Character = '\n' say "hello" say "hello" { 123 } let doubled = numbers.map { $0 * 2 }
The command line gained talk test [paths...], which discovers and runs
.test.tlk files. The stdlib now has a small testing prelude and postlude, core has array
and
iterable tests, and a failed assertion makes the runner exit nonzero after printing the captured
summary.
The release side also got sturdier. VM end-to-end benchmarks landed, the TalkSwift XCFramework workflow was updated for tag and release events, and the releasor2000 workflow can now carry the package through the release track without hand-copying each artifact.