For example, my first programmable calculator was a Radio Shack rebadge of the Sinclair programmable calculator. (That's right, before Sinclair introduced the ZX-80, at one-tenth the price of any other microcomputer on the market, he introduced a programmable calculator at one-tenth the price of any programmable calculator on the market.)
\n\n\n\nSinclair's calculator cut a lot corners. It claimed to have 36 programming steps, but its \"steps\" were very weird. E.g. if you wanted to multiply a number by 3.5 then you needed to enter \"number\" \"3\" \".\" \"5\" as steps — so the numerical constant 3.5 cost you four programming steps.
\n\n\n\nYou could cut steps by using a memory, but — guess what — it only had one memory. (Back then, the mark of a good calculator was having a bunch of memories.) It also didn't have a stack so, unlike HP (which explicitly used a stack along with \"reverse-polish notation\" to handle \"order of operations\") or TI (which explicitly supported \"order of operations\" by having a stack behind the scenes and allowed you to explicitly invoke it using parens) 3+4x5 was 35.
\n\n\n\nSo, in essence, you had X, Y, and M registers.
\n\n\n\nAnyway, the calculator came with a book of sample programs, one of which was an implementation of \"lunar lander\" — a game I had played on the HP-65 and which was the Grand Theft Auto V of its day. But owing to the paucity of memory on the Sinclair you had to write down your altitude, fuel and velocity and enter them each round, which kind of ruined the experience.
\n\n\n\nAnyway, another of the example programs, I forget which, did a really amazing trick, which was to use two different entry points for a single code sequence to use that same code for two different purposes.
\n\n\n\nThus, via a combination saving program steps by rounding lunar gravity to 2m/s (saving two precious program steps), reusing a multiply-add code sequence in two different ways, I was able to duplicate the UI of the HP-65 version (which just required you to enter your burn each turn).
\n\n\n\nIt's all about the UI, right?
\n\n\n\nJust as the skills that haven't been named, codified, aren't yet taught in courses, that operate between the well-defined commoditized skill sets tend to be the most valuable skills, it's the connections between UI components that are the most valuable things in user interfaces.
\n\n\n\nDialog boxes — modal or preferably otherwise — are something you inevitably need in almost any user interface. One thing that really makes UI development a bit easier is the ability to quickly generate a simple dialog box in a pinch — Hypercard's ask and answer were the first time I saw a really slick option for doing this, and it's one of the first things I look for in a new framework.
\n\n\n\nThe key thing that happens in a user interface when a modal dialog is employed is that it creates a new UI context (typically outside of and separate from the current context) shares information with it, and allows it to send commands back to the original context.
\n\n\n\nHow dialog boxes work is a microcosm of everything that's right — or wrong — about a UI framework. Very few frameworks do it really well — it's usually a pain point and it's just a question of how nasty it is.
\n\n\n\nConsider React. In React, if you want to have a button that creates a modal dialog box, the obvious way to do it is to wrap the modal in the button, and when the button is clicked its state changes and the button now renders the modal that's hidden inside. In essence, React \"solves\" the \"dialog needs to create a new context and communicate with it\" problem by requiring the dialog to be inside the original context after all.
\n\n\n\nIf you want the same dialog box to be launched by two different buttons then it needs to live inside both buttons. If the dialog needs something from its context, such as a callback, then typically that callback needs to be passed down the hierarchy through both parents. It's perfectly possible for the dialog to work correctly when invoked by one button but not the other because of a plumbing snafu.
\n\n\n\n(React doesn't just have a fragile base class problem, it has a fragile instance problem and a fragile composition problem. This is why I've started to think of React as an employment security program for mediocre programmers.)
\n\n\n\nYeah, you can work around these issues, but now you're fighting React's philosophy. And the current trend of requiring front-end code to be rolled up into a single minified file and delivered immediately (as exemplified by Webpack) makes this worse, because the \"correct\" way to deliver a web application it to deliver all of it, at once, whether you'll ever need it or not.
\n\n\n\nSo, this issue was on my mind when I designed the component system in b8r, and I didn't have an ideal solution in mind when I did it, I just knew that it would need a solution, and so I provided too many solutions.
\n\n\n\nSo, if you're doing things the React way in b8r, then a child component inherits a shallow clone of its parent's properties. All of them. This was a bad decision because it's very easy to use, and it's a loaded shotgun pointed at your foot. At first blush, it's great, but oh the corner cases. (To be fair, the problems don't tend to result from using the feature for dialogs so much as composition.)
\n\n\n\nNext, you can explicitly set the data-path of a component which will give it a copy of whatever is at that data path. This is neither as convenient as the above, nor especially robust (since, again, you get a shallow clone).
\n\n\n\nNext, it's pretty easy to find components and talk directly to them. This is usually a last resort since the two methods above are almost always easier and more-or-less automatic.
\n\n\n\nFinally, because b8r treats the DOM as the single source of truth about bindings (not data!) you can directly write bindings and then they will work. In existing b8r code this is mainly used to by a component to bind itself algorithmically to something based on the data it has received. E.g. a detailed view might figure out that it needs to bind itself to a specific list instances based on the value of an id stored at a specific path. (This specific use-case has recently been afforded another solution, which is nested path resolution, so you can do something like: data-path=\"app.things[id=${app.selected_thing_id}]\".)
\n\n\n\nIt seems clear in retrospect that that paths are the key. Instead of setting data-path to decide what data to copy and pass to a component, data-path should just become the component's base bath for relative data references. This idea can be generalized to list instances (a list instance's data-path is exactly the same, a list instance is, in essence, a lightweight component instance). Within a component, _component_.foo would therefore point at the _component_ instance's foo(which is a controller object with (in React parlance) state but no props, while _data_.foo would point to the components ${dataset.path}.foo.
\n","$updatedAt":"2024-06-05T09:10:30.386+00:00",path:"b8r-lessons",_created:"2024-07-09T20:28:53.400Z",id:"6634",_modified:"2024-07-09T20:28:53.400Z","$id":"6634",_path:"post/path=b8r-lessons"},"page/path=blog":{path:"blog",css:"",imageUrl:"",prefetch:[{regexp:"^\\/(([\\w\\d]+\\/)*)([\\w-]+)\\/?$",path:"post/path=[3]"}],tags:["public"],source:"