v0.2.0-next

v0.2.0-next

Prerelease

This release is still in development and has not been tagged yet.

A Zirric program still runs one thing at a time. What it can now do is wait on more than one of them: a key and a timer, a slow job and a user who presses q, several files handled as they become ready.

Implemented Proposals

  • ZE-025 Routines and Channels — the co module: routines, the scopes that own them, and channels between them. No new syntax, no new keyword, no new operator.

Notable Changes

  • One routine runs at a time, and only gives way at a switch point — co.send, co.receive, co.select, co.wait, co.sleep, iterating a channel, the end of a co.scope body, and every stdlib call that waits on the outside world. Between two switch points, code runs as if it were alone, so a shared var or array needs no lock.
  • New io.read(reader, length) and io.write(writer, buf), wrapping the @Reader and @Writer attributes the way len wraps @Countable. io.read(stdin, 1) replaces io.Reader(stdin).read(stdin, 1), which is shorter whether or not a program has routines.
  • The functions of fs, io.read, io.write and therefore fmt.fprint* are switch points, whatever reader, writer or filesystem they are given. A fake that answers instantly interleaves exactly where the host’s own would, and cannot run a whole loop while the other routines never start. With the host’s own filesystem or streams, the run lock is released for the length of the call, so a routine blocked on standard input does not stop the rest of the program. With fs.memory() nothing really waits, but the calling routine still goes to the back of the queue, so a test sees the same places to interleave as production does.
  • A Channel carries @Iterable, so for value <- channel receives until the channel is closed and drained, and co.produce turns a function into a generator with nothing new.
  • os.timer() hands out the timer that really waits. co.immediateTimer() and co.neverTimer() are the two a test uses instead, which is how a timeout is checked in both directions without waiting for either.
  • A program where every routine is waiting stops with a deadlock message naming each blocked routine and what it was waiting on, rather than hanging.
  • cancel returns at once even when the routine it stops is waiting for standard input, and loses none of that input: a host stream owns its reads, so bytes that arrive for a routine which is no longer waiting stay there for whoever reads next. A write already handed to the host still completes — see Cancelling for what cancellation does and does not take back.

Bug Fixes

  • A closure written inside a for expression body can reach a variable of the enclosing function. The loop body has a symbol table of its own while running in the same frame, so such a reference was resolved against the frame’s own captures — reporting an internal error, or silently reading an unrelated captured value when the indices happened to line up.