The duplicate state fallacy

Suppose you just started coding against a rich user interface framework. It keeps all sorts of state to itself, and notifies about changes by whatever mechanism. As the simplest example, it does have to know what to render in a menu when the user scrolls it down, so it keep the whole list to itself. Or perhaps it contracts your code to refresh the screen whenever something interesting happens.

Be as it may, it's always about who owns the state. It's always about either the shortcomings of the graphics framework, or about the shortcomings of your code. In particular it's never fast enough because it's just too damn hard to coordinate two separate processes handling common state unless they've been designed as one from the beginning.

And, hence, even the monolithic, gargantuan, Linux kernel. What state management problems you had with the screen are amplified roughly three decades by working with an all-knowing OS kernel, coded by performance minded nerds. In C.

In actual fact the trouble could be avoided. What fucks you up here is the shared state between processes, and the fact that it can be assigned to in a non-atomic, autonomous way. If there was proper state management and a shared atomic semantics, either process could assign whatever it wanted to the state without wreaking havoc. And if it was necessary to notify somebody else upon an assignment, well they'd be notified automatically, they'd be structured to handle the lightweight message, and they'd just be happy without much further effort. For instance, you could just say that part of the menu text changed and then the next time the UI framework needed to paint that region over, it'd just render your shared text from where you put it.

You can actually do this in languages like Common LISP, and their frameworks. That's because the program semantics do not assign into any state per se, but relegate that sort of thing to a carefully controlled, low level, optimization layer, with its own separate operations and their interaction semantics. The overall, surface level, mostly-used semantics of the language just encode your state evolution, and that of your abstract interfaces. With any decently coded UI framework they externalize the low level, performance tweaking to a shallow abstraction layer.

Not only because they should, but because they also can: the nastiest problem with commonly used procedural languages is that they indeed cannot, because their semantics do not really force the coder to enunciate, precisely, what the state evolution rules ought to be in the first place. They simply do not force the programmer to give enough data to the compiler, so that it can do its job properly.

I'm not saying the functional programming paradigm is the be all and end all of programming, especially as it now stands. Far from it; I for instance hate lists and trees as the only data structures out there in the functional universe. But you do gotta give the framework even this highly practical benefit of a doubt: it does force you code in a style which lets the compiler/interpreter know how your state is supposed to evolve. Even your shared states. As such, it can give you no hassles, zero-copy, UI framework integration. C, Ruby, whathaveyou, can't, because in them you're lured into not telling the interfaces or even your own compiler what they most need to know.

If you can't evolve the state of a shared element directly, there is something wrong with your language. And since there's something wrong with just about any procedural language by that token, well, I for one am once again looking pretty seriously into functional programming and its current, attendant frameworks.

No comments:

Post a Comment