5 ms·
The imperative shell could be something like while not is_closed(state) { (mouse_activity, kbd_activity) := get_mouse_and_kbd() //blocking call
by mac01021 6y ago
The imperative shell could be something like
while not is_closed(state) {
(mouse_activity, kbd_activity) := get_mouse_and_kbd() //blocking call
(state, is_modified) := update(state, mouse_activity, kbd_activity)
if (is_modified) {
draw(state)
}
}
There is no reason that `update` and every function it calls cannot be pure. The state will have to include undo and redo histories, an indicator of the active mode, so that you might be in one mode while you're entering text, a different mode while you're dragging out a line or a shape, etc. It will include information about what drawing tool you have selected and what colors you've chosen for your ink and eraser. All that data will be used by the draw procedure to render the correct view of the state.
The one issue here is that once your state gets to a certain level of complexity, as it certainly does in ms paint, it's not going to be performant without immutable "persistent" data structures, which are either not available or not widely used in python/js/ruby/c.
If you're thinking i haven't achieved the goal here because the draw procedure is big and complicated and imperative, then maybe we need to replace
draw(state)
with
view := render(state)
draw(view)
where render is pure and does almost all the work. But I'll leave thinking about what render looks like as an exercise for the reader (or to be described by an HN user who knows more about graphics programming than I do)