count on it
Talk 0.1.70 puts sizes in types, shortcuts failure with ?, opens brackets and ranges to real protocols, and sends tests into the editor. Also there’s a podcast.
The last issue rebuilt the machinery under Talk. This one spends the result on the language users actually type. Static values now shape generic APIs and inline storage; question mark, subscripts, bitwise operators, and ranges remove familiar detours; protocols can construct concrete values; unsafe authority has a visible boundary; and the editor and a new podcast carry the story beyond the command line.
Talk now accepts mixed type and static value parameters. A declaration such as
Grid<static Rows: Int> can carry a size through its API, infer that value from an
argument, use it as an ordinary value inside the generic body, and specialize the body for each concrete
application. Static parameters may be nonnegative Int values, Bool values, or
cases of fieldless enums; defaults are allowed when they use only earlier parameters.
The index language stays intentionally smaller than ordinary Talk. It supports literals, parameters,
parentheses, addition, subtraction, and multiplication by an integer literal. The checker canonicalizes
affine forms, so N + 1 and 1 + N identify the same type, and
where clauses can state ==, <, and <=
obligations. If a call leaves a value undetermined, the diagnostic asks for explicit generic arguments;
if arithmetic cannot establish a bound, it asks for a stronger static predicate instead of guessing.
func width<static N: Int>(values: [Int; N]) -> Int { N } let pixels: [Int; 3] = [10, 20, 30] width(pixels)
That mechanism immediately has a concrete collection: [Element; Count] spells
InlineArray<Element, Count>. Elements live directly in the value, the count is part
of the type rather than stored at runtime, and get checks an ordinary runtime index and
returns an optional shared view. Literals must have exactly the count promised by their expected type,
nested inline arrays retain their exact shape, and owned elements are dropped normally.
Postfix ? now performs early propagation for any enum with exactly two
variants. The first variant unwraps and continues; the second is rebuilt and returned from the enclosing
function. That covers Optional, Result, and user-defined two-case enums
without tying the syntax to one core type.
func source(ok: Bool) -> Result<Int, String> { if ok { Result.ok(21) } else { Result.error("no value") } } func doubled(ok: Bool) -> Result<Int, String> { let value = source(ok)? Result.ok(value * 2) } doubled(true)
The checker keeps the shortcut honest. The operand and function result must use the same enum, there
must be an enclosing return boundary, and enums with any number of variants other than two are rejected
with a Cannot use '?' here diagnostic.
Subscript syntax is now protocol-backed. value[index] resolves through
SubscriptRead, while assignment through the same spelling resolves through
SubscriptWrite. Arrays provide both paths, and user types can implement either protocol
independently.
Int and Byte also gain &, |, ^,
~, <<, and >>. Their precedence follows Rust's
ordering, shift counts are masked to the operand width, and nested generic closers such as
Array<Array<Int>> still parse despite the new right-shift token.
let values = [1, 2, 3] values[1] = 6 & 3 print(values[1]) let powers = 4.times { i in values[1] << i } print(powers[3])
Ranges complete the everyday loop. 1..<5 is half-open, 1..5 is inclusive,
both expose contains, and integer ranges are iterable. Inclusive iteration now terminates
correctly even when its upper bound is the largest Int. The new
n.times { ... } convenience maps the indices from zero through n - 1 into an
array, including closures that mutate captured values.
A protocol may now require an initializer. A conforming type can satisfy it with an explicit initializer or its synthesized memberwise initializer, and an expected concrete result type chooses the conformance whose initializer should construct the value.
protocol FromPair<T> { init(lower: T, upper: T) } struct Pair<T> { let lower: T let upper: T } extend<T> Pair<T>: FromPair<T> {} let pair: Pair<Int> = FromPair( lower: 1, upper: 5 ) pair.lower + pair.upper
Extensions became more exact at the same time. Generic binders now appear explicitly before the head,
as in extend<T> Pair<T>, while concrete heads such as
extend Box<Int> mean that exact application. Disjoint Box<Int> and
Box<Bool> extensions can therefore publish different implementations with the same
member name; another Box application does not see either one. Rows that can apply to the
same concrete type still report an overlap rather than receiving declaration-order priority.
Raw-pointer expressions and @_ir outside core now carry the
compiler-known 'unsafe effect. The lexical @unsafe { ... } form discharges
that effect for one visible region and installs no runtime handler.
@unsafe { let pointer = _alloc<Int>(1) _free(pointer) }
The old file-wide // unsafe comment no longer grants authority. Unmarked code receives
No handler for 'unsafe, while backend diagnostics point to @unsafe or an
enclosing function that explicitly carries the effect. The chat examples and filesystem implementation
have moved to the scoped spelling.
The TalkTalk VS Code extension now discovers *.test.tlk files in the
native Test Explorer. It can run a whole file or one named test through talk test --json,
then attach captured output and assertion failures to the corresponding result. Discovery ignores
repository and build directories such as .git, node_modules, and
target.
A new TalkTalk: Reinstall Extension command also locates the Talk checkout and launches
its existing reinstall script, shortening the edit-build-reinstall loop for extension development.
The release notes have an audio companion. The talktalkcast feed currently carries 17 episodes, moving from types, constraints, records, and members through pattern matching, effects, ownership, borrows, specialization, diagnostics, comparisons, and a first program.
Subscribe directly with the talktalkcast RSS feed. For a release this crowded with language features, the compiler desk finally has enough material to fill the commute.