I'd like to post a purely positive, encouraging comment here :-)<p>Thanks for the article, and good job implementing an entire editor from scratch in C! That's impressive.<p>Also, as a very accomplished programmer who happens not to have done much recent UI programming, who has read quite a bit about React/Redux/Rewhatever, Elm, The Haskell School of Expression, etc., I find articles like this extremely helpful: you took a simple example, and clearly and straightforwardly demonstrated the underlying goals and principles of "Unidirectional UI". While I mostly "get it" already from reading articles on React-based architectures, clear reiterations of the idea are a huge aid in getting the concepts solid.
Very interesting work! It seems that educational text editors are becoming a trend after Antirez published his :-)<p>Excuse me the shameless plug, I'd like to show mine too: <a href="https://github.com/arximboldi/ewig" rel="nofollow">https://github.com/arximboldi/ewig</a><p>It is written in C++, but using a style that is unlike what most C++ developers use: it is composed mostly of pure functions. The architecture is very much like that of Elm programs, and there is even a `store` class like in Redux.<p>Like the project from OP, it is about 2K lines of code. But it also supports asynchronous loading/saving, copy-paste (you can copy-paste a 1GB file instantly), very robust undo, dirty markers, UTF-8 (not perfect), etc.<p>The magic? Immutable vectors based on RRB-Trees. This is like the vectors in Clojure/Scala, but also supports log(n) slicing, concatenations, insertions---these operations are fundamental for a text editor, and I'd say, to most interactive software supporting big data models [1].<p>The code has been written in a style as simple as I could. I'd like to think that even non-C++ developers might be able to understand it. It might be specially interesting for web developers invested in Clojure, Elm or Redux and the single-atom architecture.<p>Probably one day I should go ahead and just write a blog post about it or a tutorial or something. But so far I don't have a blog I am not really a social media person. The code is still moving also...<p>PS. And thanks a lot to @kostspielig her help writing and reviewieng the code! <3<p>[1] The data-structure can be found here: <a href="https://github.com/arximboldi/immer" rel="nofollow">https://github.com/arximboldi/immer</a>
> In other words, UI programming is about mapping incoming events to a series of effects.<p>Sort of like programming with <i>Monads</i>.<p>This is one of the reasons why programming with Monads is so powerful: the programmer can explicitly compose and control effects.<p>Good on the author for digging in and learning new things. I'd recommend following up with reading the source to vi and doing some research on programming patterns of the day. One of the things we're pretty bad at preserving is context; it'd be neat to read about what the author discovers (ie: why was vi written the way it was? What did the original authors discover? etc).
It's worrying how sometimes the most basic programming concepts can appear revolutionary to web developers. So much so, they've recently stumbled across the concept of a read input-update-render loop, and are now trying, with frameworks like React, to contort the DOM tree, just to get back to how UI was programmed since decades.<p>There's a fairly old concept called "immediate mode UI", which even gets rid of the tree structure, and keeps the whole state on the user side, giving you full control over when elements are updated and where they are placed. These days it's used mostly in video games, since they already rely on a 60 FPS loop, and the UI complexity tends to be low.<p>If not for the necessity to use standard platform form elements due to their various quirks and interactions with the system, I'd be doing UI programming only in immediate mode with custom controls, simply because how convenient, and simple it is.
Storing every character in a doubly linked list seems like an extremely inefficient use of memory. Depending on your architecture, that could use 24 bytes per ASCII character (if the char in the struct is padded with 64-bit pointers). I imagine that vi wouldn't have gotten very far if it had been that memory constrained.
Is the (pseudo?) code there for state mutation representative of a widely used pattern?
It looks like using a pattern from a functional programming book, but applied to mutable data. What I mean is this snippet:<p><pre><code> function handleAddTodo(state) {
if (!newTodoField) {
state.error = 'Empty field!'
}
state.todos.push(state.newTodoField)
state.newTodoField = nil
return state;
}
</code></pre>
This looks like a function newState = fun(oldState) but there is one huge problem: the new state is the <i>same</i> data as the old state? In a Rust-like type system this might be OK because you couldn't accidentally keep using the original state after sending it to this method, and in an immutable scenario there would be no problem because you created a new state instead of mutating. But this looks exactly like mutating the argument sent to a function.
So out of curiosity, do any modern UI frameworks in JS (this looks like that type of code) do this, or was it just an unfortunate example?
Once you move to making mobile or desktop front end you appreciate how easy front end web dev really is.<p>Contrary to popular opinion I think the DOM, HTML, and CSS, are an awesome way of defining and styling a scene graph. When I did some C++ front end I missed them every day.
For anyone interested in building a text editor, I really enjoyed working over this tutorial:<p><a href="http://viewsourcecode.org/snaptoken/kilo/" rel="nofollow">http://viewsourcecode.org/snaptoken/kilo/</a><p>The author builds a terminal-based text editor in C from scratch. It's very well written and the incremental diff-style format makes it easy to follow along.
not C, but probably very C useful <a href="http://scienceblogs.com/goodmath/2009/01/26/ropes-twining-together-strings/" rel="nofollow">http://scienceblogs.com/goodmath/2009/01/26/ropes-twining-to...</a>
I am a novice in this area, so forgive me if I am missing something, but I have some questions regarding the two approaches in the article, specifically if there is a performance trade-off being made between them.<p>To my untrained eye, the initial version seems to be doing a minimal set of updates based on the input it receives, whereas the latter version will call the monolithic render procedure no matter how small a change is made to the state.<p>Does each of the sub-procedures in renderTodo! check internally if the state actually changed (by keeping a copy of the previous state?), or do they just unconditionally re-render the entire UI? If the latter is true, then doesn't this supposedly better way of structuring code come with a large performance penalty? Or is it simply the case that this penalty is outweighed by the added test-ability and improved consistency of the state?<p>I believe that React and similar frameworks run a diffing procedure to find out which parts of the UI actually need to be updated (so a more minimal set of updates is actually applied). In the first version, however, it seems like the same diff occurred naturally as part of the code's structure - only a subset of the render* functions are called - and therefore the diff does not need to be computed at run-time.<p>Is this something worth being concerned about, or is letting the framework compute the diff on every state change not that big of a deal?
What is the difference between Event Sourcing and the Command Pattern here? For decades the Undo/Redo functionality has been implemented by the Command Pattern it seems.
And looking at what Event Sourcing is, it looks a lot like the Command Pattern which purpose is to encapsulate into an object a side-effect performed on some data structure. That object can then be executed at a later time, reverted, logged, etc...
Another C tty oriented text editor is the classic MicroEmacs:<p><a href="https://github.com/DigitalMars/me" rel="nofollow">https://github.com/DigitalMars/me</a><p>I learned a lot about programming from reading the source code to it. It's a gem of clarity and design (and you could reasonably argue that many of my changes to it messed it up).
All i can say is "watch this kid!". He is showing the motivation, perspectives, insight and intelligence to be able to do important work in the future. Great article and the C code worth reading to learn from. Thanks for sharing and looking forward to reading future blogs and seeing what you create.
> In other words, UI programming is about mapping incoming events to a series of effects.<p>So I guess the word `event-driving programming` is lost in time.<p>And I don't think the Unidirectional pattern described is suits for C programming. When I see people use C, I think performance, and unless the compiler optimized it away the state mutating function is gonna cost a lot of unnecessary memory copy. And worst offender is that unless you have React-like UI diff-ing library, it's gonna be a costly entire screen redraw event for the most simple update.
A cursory look into the linked github pull request changes made me spot this, and I must admit that never in a million years would I've thought to erase the possible endline character of a string returned by getline with this:<p><pre><code> line[strcspn(line, "\n")] = 0;
</code></pre>
I don't think I'm going to start, either, even if it is a nifty oneliner. Anyway, I've always found this kind of little projects a good sport.
Nice article, good summary of the purpose of unidirectional UI approach like Redux's, although it doesn't get as much into persistent data structures as maybe it could have.<p>What's the point of the exclamation mark after certain function names? Is that a pseudocode thing? Is that supposed to be shorthand for an impure function? (if so, not sure why `handleKeyboardEvent` doesn't have an exclamation mark.
The more I read, the more I felt that the author was long-windedly discovering FSM's, only describing them using the language de-jour - i.e. JavaScript-ecosystem-ism's.<p>Is this the state of things today - that kids start off as highfalutin' "developers", whereby 95% of their apps are written by others (because: "npm -i <all the things>"), and then .. eventually, from the top-down, trickle through the stack learning "the things", giving it all a new fancy name, and blogging about it? Because to me, this seems more like devolution at work in the computer science industries, not some kind of radically derived insight.<p>I'm not trying to be overly critical, but for a lot of us, "discovering that C-based apps are, weirdly, similar to what us React-ites are doing" sure seems like a step backwards from real stack competency.
If you plan on allowing future employers to look at your Github profile, you might want to change the way you write your commit messages.<p>> REFACTOR: :hocho: future queue (I was retarded)<p>Not exactly an appealing commit message.
It is not surprising that C gets that much of a bad reputation when devoloper show such poor capacity at managing errors; malloc(3) return values are never checked and everything is expected to always succeed, throughout the source tree.