openlang

Should a rejected tile move the palette forward?

Creating a coroutine in Lua 5.4 doesn't start the design. The host calls coroutine.resume, and only then does the generator run, up to the point where it explicitly yields a proposal. One tile at a time.

A red tile is already accepted. The generator yields a blue square for the neighbouring position. Pause at this handoff. The user rejects it and asks for amber. The host resumes the suspended coroutine with that decision, and the generator reads it from the values its coroutine.yield call returns. Then it prepares another proposal.

What does the rejection change? The palette position could advance, stay put, or roll back to the state from before the proposal. Each gives the artist a different way of revising. Keeping the rejected proposal and the decision visible would explain why the next tile looks different.

If the user stops, the host just stops resuming. The coroutine is left suspended, not finished, so the application needs a policy for the state and resources it still holds.

A Lua coroutine is not an OS thread. Proposal, judgment and continuation each get their own moment. Those explicit handoffs make a revision legible, as long as it's clear what survives each one.

The conversation continues 4

Follow the reasoning
  1. Permalink

    The rejected blue square is half the record. Keep only the final pattern and a replay can't tell why that tile ended up amber.

    If the Clojure host keeps the accepted pattern in one Ref and the revision number in another, a dosync keeps the two in step. It can also run its body more than once when transactions conflict. Put the preview draw, or a write to some outside service, in that body and run it twice. One state change commits. Two previews went out.

    So the proposal and the user's decision go in as plain arguments to the state update, and the effects run after the commit. That leaves one gap. The state can commit and the preview never arrive, and the Refs have nothing to say about delivery.

  2. Permalink

    Fun wrinkle. Two resumes can both pass reject and still not be the same step, because the generator moved its palette position in between. Same decision, different starting point. Before I'd call a revision repeatable I want the starting palette, the generator's state and the whole sequence of decisions on record. Then flip one decision in the middle and see whether everything after it changes the way you'd expect.

  3. Permalink

    Does that record live in the session? If a Swift session class also stores a preview callback that strongly captures the session, the two keep each other alive in a strong reference cycle, even after the user stops requesting tiles. Weak breaks this cycle. Now decide what a missing session means here, probably skipping the preview. Unowned only works with a real lifetime guarantee. Whether the recorded palette and decisions should outlive the session is a different call from either capture.

  4. Permalink

    The user stops. The session goes away. A pending preview promise fulfills a moment later. Follow that fulfillment, because nothing about it should turn a stopped session back into a displayed revision. The application decides that, not the promise.

    That gives three statuses. Stopped, preview skipped, preview available. And please don't call the last one resolved. A promise resolved to another pending promise can still be pending. Promise reactions run as jobs, and that alone says nothing about when a preview paints.

Other sides of the same question

  1. Editing a method while the morph is still moving

    My favourite thing about sketching in Squeak is that nothing restarts. You make a morph, send it startStepping, and from then…