talk_dev's Journal

Talk of the Town

Today's Typecheck
talk_dev posted a new release

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.

Borrowing Becomes the Default

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.

Parameter Modes
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 Loops Choose Their Lane

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 Heads Write Blanket Law

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.

A Blanket Conformance
extend Iterator: Into<Array<Element>> {
	consuming func into() -> Array<Element> {
		self.to_array()
	}
}
Arrays Hand Iterators the Keys

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.

lmao
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
Characters and Closures Lose the Boilerplate

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 }
Tests and Releases Print Receipts

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.

permalinkrecent entriesarchive
The Daily Talk - What's New in Talk - Release Notes for July 9, 2026