Posts in Dart (20 found)
Stone Tools 1 weeks ago

XPER on the Commodore 64

In 1984, Gary Kildall and Stewart Chiefet covered "The Fifth Generation" of computing and spoke with Edward Feigenbaum, the father of "expert systems." Kildall started the show saying AI/expert systems/knowledge-based systems (it's all referred to interchangeably) represented a "quantum leap" in computing. "It's one of the most promising new softwares we see coming over the horizon." One year later, Kildall seemed pretty much over the whole AI scene. In an episode on "Artificial Intelligence" he did nothing to hide his fatigue from the guests, "AI is one of those things that people are pinning to their products now to make them fancier and to make them sell better." He pushed back hard against the claims of the guests, and seemed less-than-impressed with an expert system demonstration. The software makers of those "expert systems" begged to differ. There is a fundamental programmatic difference in the implementation of expert systems which enables a radical reinterpretation of existing data, they argued. Guest Dr. Hubert Dreyfus re-begged to re-differ, suggesting it should really be called a "competent system." Rules-based approaches can only get you about 85% of the way toward expertise; it is intuition which separates man from machine, he posited. I doubt Dreyfus would have placed as high as 85% competence on a Commodore 64. The creator of XPER , Dr. Jacques Lebbe, was undeterred, putting what he knew of mushrooms into it to democratize his knowledge. XPER , he reasoned, could do the same for other schools of knowledge even on humble hardware. So, just how much expertise can one cram into 64K anyway? So, what is an "expert system" precisely? According to Edward Feigenbaum, creator of the first expert system DENDRAL, in his book The Fifth Generation: Artificial Intelligence and Japan's Computer Challenge to the World , "It is a computer program that has built into it the knowledge and capability that will allow it to operate at the expert's level. (It is) a high-level intellectual support for the human expert." That's a little vauge, and verges on over-promising. Let's read on. "Expert systems operate particularly well where the thinking is mostly reasoning, not calculating - and that means most of the world's work." Now he's definitely over-promising. After going through the examples of expert systems in use, it boils down to a system which can handle combinatorial decision trees efficiently. Let's look at an example. A doctor is evaluating a patient's symptoms. A way to visualize her thought process for a diagnosis might take the below form. An expert system says, "That looks like a simple decision tree. I happen to know someone who specializes in things like that, hint hint." XPER is a general-purpose tool for building such a tree from expert knowledge, carrying the subtle implication (hope? prayer?) that some ephemeral quality of the decision making process might also be captured as a result. Once the tree is captured, it is untethered from the human expert and can be used by anyone. XPER claims you can use it to build lots of interesting things. It was created to catalog mushrooms, but maybe you want to build a toy. How about a study tool for your children? Let's go for broke and predict the stock market! All are possible , though I'm going to get ahead of your question and say one of those is improbable . I have a couple of specific goals this time. First, the tutorial is a must-do, just look at this help menu. This is the program trying to HELP ME . After I get my head around that alphabet soup, I want to build a weather predictor. The manual explicitly states it as a use case and by gum I'ma gonna do it. I'm hoping that facts like, "Corns ache something intolerable today" and "Hip making that popping sound again" can factor into the prediction at some point. First things first, what does this program do? I don't mean in the high-level, advertising slogan sense, I mean "What specific data am I creating and manipulating with XPER ?" It claims "knowledge" but obviously human knowledge will need to be molded into XPER knowledge somehow. Presently, we don't speak the same language. XPER asks us to break our knowledge down into three discrete categories, with the following relationships of object, feature, and attribute: My Gen-X BS alarm is ringing that something's not fully formed with this method for defining knowledge. Can everything I know really be broken down into three meager components and simple evaluations of their qualities? Defining objects happens in a different order than querying, which makes it a little fuzzy to understand how the two relate. While we define objects as collections of attributes, when querying against attributes to uncover matching objects. The program is well-suited to taxonomic identification. Objects like mushrooms and felines have well-defined, observable attributes that can be cleanly listed. A user of the system could later go through attribute lists to evaluate, "If a feline is over 100kg , has stripes , and climbs trees which feline might it be?" For a weather predictor, I find it difficult to determine what objects I should define. My initial thought was to model "a rainy day" but that isn't predictive. What I really want is to be able to identify characteristics which lead into rainy days. "Tomorrow's rain" is an attribute on today's weather, I have naively decided. This is getting at the heart of what XPER is all about; it is a vessel to hold data points. Choosing those data points is the real work, and XPER has nothing to offer the process. This is where the manual really lets us down. In the Superbase 64 article, I noted how the manual fails by not explaining how to transition from the "old way" to the "new way" of data cataloging. For a program which suggests building toys from it, the XPER manual doesn't provide even a modicum of help in understanding how to translate my goals into XPER objects. The on-disk tutorial database of "felines" shows how neatly concepts like "cat identification" fit into XPER framing. Objects are specific felines like "jaguar," "panther," "mountain lion." Features suggest measureable qualities like "weight," "tree climbing," "fur appearance," "habitat" etc. Attributes get more specific, as "over 75kg," "yes," "striped," and "jungle." For the weather predictor, the categories of data are similarly precise. "cloud coverage," "temperature," "barometer reading," "precipitation," "time of year," "location," and so forth may serve our model. Notice that for felines we could only define rough ranges like "over 75kg" and not an exact value. We cannot set a specific weight and ask for "all cats over some value." XPER contains no tools for "fuzzy" evaluations and there is no way to input continuous data. Let's look at the barometer reading, as an example. Barometer data is hourly, meaning 24 values per day. How do I convert that into a fixed value for XPER ? To accurately enter 24 hours of data, I would need to set up hourly barometer features and assign 30? 50? possible attributes for the barometer reading. Should we do the same for temperature? Another 24 features, each with 30 or more attributes, one per degree change? Precipitation? Cloud coverage? Wind speed and direction? Adorableness of feline? Besides the fact that creating a list of every possible barometric reading would be a ridiculous waste of time, it's not even possible in the software. A project is limited to We must think deeply about what data is important to our problem, and I'd say that not even the expert whose knowledge is being captured would know precisely how to structure XPER for maximum accuracy. The Fifth Generation warns us: "GiT GuD" as the kids say. ( Do they still say that?! ) The graphic above, output by XPER 's "Printer" module, reveals the underlying data structure of the program. Its model of the data is called a "frame," a flat 2-D graph where objects and attributes collide. That's it. Kind of anticlimactic I suppose, but it imbues our data with tricks our friend Superbase can't perform. First, this lets us query the data in human-relatable terms, as a kind of Q&A session with an expert. "Is it a mammal?" "Does it have striped fur?" "Does it go crazy when a laser pointer shines at a spot on the floor?" Through a session, the user is guided toward an object, by process of elimination, which matches all known criteria, if one exists. Second, we can set up the database to exclude certain questions depending upon previous answers. "What kind of fur does it have?" is irrelevant if we told it the animal is a fish, and features can be set up to have such dependencies. This is called a father/son relationship in the program, and also a parent/child relationship in the manual. "fur depends on being a mammal," put simply. Third, we can do reverse queries to extract new understandings which aren't immediately evident. In the feline example it isn't self-evident, but can be extracted, that "all African felines which climb trees have retractile claws." For the weather predictor I hope to see if "days preceding a rainy day" share common attributes. The biggest frustration with the system is how all knowledge is boxed into the frame. For the weather predictor, this is frustrating. With zero relationship between data points, trends cannot be identified. Questions which examine change over time are not possible, just "Does an object have an attribute, yes or no?" To simulate continuous data, I need to pre-bake trends of interest into each object's attributes. For example, I know the average barometric pressure for a given day, but because XPER can't evaluate prior data, it can't evalute if the pressure is rising or falling. Since it can't determine this for itself, I must encode that as a feature like "Barometric Trend" with attributes "Rising," "No Change," and "Falling." The more I think about the coarseness with which I am forced to represent my data, the more clear it is to me how much is being lost with each decision. That 85/15 competency is looking more like 15/85 the other direction. Collecting data for the weather predictor isn't too difficult. I'm using https://open-meteo.com to pull a spreadsheet on one month of data. I'll coalesce hourly readings, like barometric pressure, into average daily values. Temperature will be a simple "min" and "max" for the day. Precipitation will be represented as the sum of all precipitation for the day. And so on. As a professional not-a-weather-forecaster, I'm pulling whatever data strikes me as "interesting." In the spirit of transparency, I mentally abandoned the "expert" part of "expert system" pretty early on. This guy *points at self with thumbs* ain't no expert. Having somewhat hippy-dippy parents, I've decided that Mother Earth holds secrets which elude casual human observation. To that end, I'm including "soil temperature (0 - 7cm)" as a data point, along with cloud coverage, and relative humidity to round out my data for both systematic and "I can't spend months of my life on this project" reasons. After collecting November data for checkpoint years 2020, 2022, and 2024, actually entering the data is easier than expected. XPER provides useful F-Key shortcuts which let me step through objects and features swiftly. What I thought would take days to input wound up only being a full afternoon. Deciding which data I want, collecting it, and preparing it for input was the actual work, which makes sense. Entering data is easy; becoming the expert is hard. Even as I enter the data, I catch fleeting glimpses of patterns emerging and they're not good. It's an interesting phenomenon, having utterly foreign data start to feel familiar. Occasionally I accidentally correctly predict if the next day's weather has rain. Am I picking up on some subliminal pattern? If so, might XPER "see" what I'm seeing? I'm not getting my hopes up, but I wonder if early fascination with these forays into AI was driven by a similar feeling of possibility? We're putting information into a system and legimitately not knowing what will come out of the processing. There is a strong sense of anticipation; a powerful gravity to this work. It is easy to fool myself into believing I'm unlocking a cheat code to the universe. Compare this to modern day events if you feel so inclined. At the same time, there's obviously not enough substance to this restricted data subset. As I enter that soil temperature data, 90% of the values keep falling into the same bin. My brainstorm for this was too clever by half, and wrong. As well, as I enter data I find sometimes that I'm entering exactly the same information twice in a row, but the weather results are different enough as to make me pause. Expert systems have a concept of "discriminating" and "non-discriminating" features. If a given data point for every object in a group of non-eliminated objects is the same, that data point is said to be "non-discriminating." In other words, "it don't matter" and will be skipped by XPER during further queries. The question then is, whose fault is this? Did I define my data attributes incorrectly for this data point or is the data itself dumb? I can only shrug, "Hey, I just work here." XPER has a bit of a split personality. Consider how a new dataset is created. From the main menu, enter the Editor. From there you have four options. First, I go to option for the seemingly redundantly named "Initializing Creating." Then I set up any features, attributes, and objects I know about, return to this screen, and save with option . Later I want to create new objects. I type for "Creating" and am asked, "Are you sure y/n" Am I sure ? Am I sure about what ? I don't follow, but yes, I am sure I want to create some objects. I hit and I'm back at a blank screen, my data wiped. That word "initializing" is doing the heavy lifting on this menu. "Initialize" means "first time setup of a dataset," which also allows, almost as a side effect, the user an opportunity to input whatever data happens to be known at that moment . "Initial Creation" might be more accurate? Later, when you want to add more data, that means you now want to edit your data, called "revising" in XPER , and that means option . Option is only ever used the very first time you start a new data set. is for every time you append/delete afterward. The prompts and UI are unfortunately obtuse and unhelpful. "Are you sure y/n" is too vague to make an informed decision. The program would benefit greatly from a status bar displaying the name of the current in-memory dataset, if it has been saved or not, and a hint on how close we are to the database limit. Prompts should be far more verbose, explaining intent and consequence. A status bar showing the current data set would be especially useful because of the other weird quirk of the program: how often it dumps data to load in a new part of the program. XPER is four independent programs bound together by a central menu. Entering a new area of the program means effectively loading a new program entirely, which requires its own separate data load. If you see the prompt "Are you sure y/n" what it really means is, "Are you sure you want me to forget your data because the next screen you go to will not preserve it. y/n" That's wordy, but honest. With that lesson learned, I'm adding three more data points to the weather predictor: temperature trend, barometric trend, and vapor pressure deficit (another "gut feeling" choice on my part). Trends should make up a little for the lack of continuous data. This will give me a small thread of data which leads into a given day, the data for that day, and a little data leading out into the next day. That fuzzes up the boundaries. It feels right, at the very least. Appending the new information is easy and painless. Before, I used F3/F4 to step through all features of a given object. This time I'm using F5/F6 to step through a single feature across all objects. This only took about fifteen minutes. I'm firmly in "manual memory management" territory with this generation of hardware. Let's see where we sit relative to the maximum potential. Features like this really makes one appreciate the simple things in life like a mouse, gui checklists, and simple grouping mechanisms. XPER can compare objects or groups of objects against one another, identifying elements which are unique to one group or the other. You get two groups, full stop. Items in those groups and only those groups will be compared when using the command. We can put objects individually into one of those two groups, or we can create an object definition and request that "all objects matching this definition go into group 1 or 2". This is called a STAR object. I created two star objects: one with tomorrow's weather as rain, and one with tomorrow's weather as every type except rain. Groups were insta-built with the simple command where means and means , my "rainy day" star object. I can ask for an AND or OR comparison between the two groups, and with any luck some attribute will be highlighted (invert text) or marked (with ) as being unique or exclusive to one group or the other. If we find something, we've unlocked the secret to rain prediction! Take THAT, Cobra Commander ! Contrary to decades of well-practiced Gen-X cynicism, I do feel a tiny flutter of "hope" in my stomach. Let's see what the XPER analysis reveals! The only thing unique between rainy days and not is the fact that it rained. The Jaccard Distance , developed by Grove Karl Gilbert in 1884, is a measure of the similiarity/diversity between two sets (as in "set theory" sets). The shorter the distance, the more "similar" the compared sets are. XPER can measure this distance between objects. where is the object ID of interest, will run a distance check of that object against all other objects. On my weather set with about 90 objects, it took one minute to compare Nov. 1, 2020 with all other days at 100% C64 speed. Not bad! What can we squeeze out of this thing? By switching into "Inquirer" mode, then loading up the data set of interest, a list of top level object features are presented. Any features not masked by a parent feature are "in the running" as possible filters to narrow down our data. So, we start by entering what we know about our target subject. One by one, we fill in information by selecting a feature then selecting the attribute(s) of that feature, and the database updates its internal state, quietly eliminating objects which fall outside our inquiry. The command will look at the "remaining objects," meaning "objects which have not yet been eliminated by our inquiry so far." With the command as in to run it against the "jaguar" we can ask XPER to tell us which features, in order, should we answer to narrrow down to the jaguar as quickly as possible. It's kind of ranking the features in order of importance to that specific object. It sounds a bit like feature weighting , but it's definitely not. XPER isn't anywhere close to that level of sophistication. In this data set, if I answer "big" for "prey size" I immediately zero in on the jaguar, it being the currently most-discriminating feature for that feline. You might be looking at this and wondering how, exactly, this could possibly predict the weather. You and me, both, buddy. The promise of Fifth Gen systems and the reality are colliding pretty hard now. Feigenbaum and "The Fifth Generation" have been mentioned a few times so far, so I should explain that a little. Announced in 1981, started in 1982, and lasting a little more than a decade, "The Fifth Generation" of computing was Japan's moniker for an ambitious nationwide initiative. According to the report of Japan's announcement, Fifth Generation Computer Systems : Proceedings of the International Conference on Fifth Generation Computer Systems, Tokyo, Japan, October 19-22, 1981, Japan had four goals: In Fifth Generation Computers: Concepts, Implementation, and Uses (1986), Peter Bishop wrote, "The impact on those attending the conference was similar to that of the launch of the Soviet Sputnik in 1957." During a hearing before the Committee on Science and Technology in 1981, Representative Margaret Heckler said , "When the Soviets launched Sputnik I, a remarkable engineering accomplishment, the United States rose to the challenge with new dedication to science and technology. Today, our technology lead is again being challenged, not just by the Soviet Union, but by Japan, West Germany, and others." Scott Armstrong writing for The Christian Science Monitor in 1983, in an article titled, "Fuchi - Japan's computer guru" said, "The debate now - one bound to intensify in the future - is whether the US needs a post-Sputnik-like effort to counter the Japanese challenge. Japan's motive (reflects) a sense of nationalism as much as any economic drive." Innovation Policies for the 21st Century: Report of a Symposium (2007) remarked of Japan's Fifth Generation inroads into supercomputers, "This occasioned some alarm in the United States, particularly within the military." It would be fair to say there was "Concern," with a capital C. In 1989's The Fifth Generation: The Future of Computer Technology by Jeffrey Hsu and Joseph Kusnan (separate from Feigenbaum's The Fifth Generation ) said Japan had three research projects The "Fifth Generation" was specifically the software side which the conference claimed, "will be knowledge information processing systems based on innovative theories and technologies that can offer the advanced functions expected to be required in the 1990's overcoming the technical limitations inherent in conventional computers." Expert systems played a huge role during the AI boom of the 80s, possibly by distancing itself from "AI" as a concept, focusing instead on far more plausible goals. It's adjacent to, but isn't really, "artificial intelligence." This Google N-Gram chart shows how "expert system" had more traction than the ill-defined "artificial intelligence." Though they do contain interesting heuristics, there is no "intelligence" in an expert system. Even the state of the art demonstrated on Computer Chronicles looked no more "intelligent" than a Twine game . That sounds non-threatening; I don't think anyone ever lost a job to a Choose Your Own Adventure book. In those days, even something that basic had cultural punch. Feigenbaum's The Fifth Generation foreshadowed today's AI climate, if perhaps a bit blithely. That guy wasn't alone. In 1985, Aldo Cimino, of Campbell's Soup Co., had his 43 years of experience trouble-shooting canned soup sterilizers dumped onto floppy by knowledge engineers before he retired. They called it "Aldo on a Disk" for a time. He didn't mind, and made no extra money off the brain dump, but said the computer "only knows 85% of what he does." Hey, that's the same percentage Hubert Dreyfus posited at the start of this article! That system was retired about 10 years later, suffering from the same thing that a lot of expert systems of the day did: brittleness. From the paper, "Expert Systems and Knowledge-Based Engineering (1984-1991)" by Jo Ann Oravec, "Brittleness (inability of the system to adapt to changing conditions and input, thus producing nonsensical results) and “knowledge engineering bottlenecks” were two of the more popular explanations why early expert system strategies have failed in application." Basically, such systems were inflexible to changing inputs (that's life), and nobody wanted to spend the time or money to teach them the new rules. The Campbell's story was held up as an exemplar of the success possible with such systems, and even it couldn't keep its job. It was canned. (Folks, jokes like that are the Stone Tools Guarantee™ an AI didn't write this.) Funnily enough, the battles lost during the project may have actually won the war. There was a huge push toward parallelism in compute during this period. You might be familiar with a particularly gorgeous chunk of hardware called the Connection Machine. Japan's own highly parallel computers, the Parallel Inference Machines (PIM), running software built with their own bespoke programming language, KL1, seemed like the future. Until it didn't. PIM and Thinking Machines and others all fell to the same culprit. Any gains enjoyed by parallel systems were relatively slight and the software to take advantage of those parallel processors was difficult to write. In the end the rise of fast, cheap CPUs evaporated whatever advantages parallel systems promised. Today we've reversed course once more on our approach to scaling compute. As Wikipedia says, "the hardware limitations foreseen in the 1980s were finally reached in the 2000s" and parallelism became fashionable once more. Multi-core CPUs and GPUs with massive parallelism are now put to use in modern AI systems, bringing Fifth Generation dreams closer to reality 35 years after Japan gave up. In a "Webster's defines an expert system as..." sense, I suppose XPER meets a narrow definition. It can store symbolic knowledge in a structured format and allow non-experts to interrogate expert knowledge and discover patterns within. That's not bad for a Commodore 64! If we squint, it could be mistaken for a "real" expert system at a distance, but it's not a "focuser ." It borrows the melody of expert systems, yet is nowhere near the orchestral maneuverings of its true "fifth generation" brothers and sisters. Because XPER lacks inference, the fuzzy result of inquiry relies on the human operator to make sense of it. Except for mushroom and feline taxonomy, you're unlikely to get a "definitive answer" to queries. Rather, the approach is to put in data and hope to narrow the possibility space down enough to have something approachable. Then, look through that subset and see if a tendency can be inferred. The expert was in our own hearts all along. Before I reveal the weather prediction results, we must heed an omen from page 10 of the manual. I'm man enough to admit my limits: I'm a dummy. When a dummy feeds information into XPER , the only possible result is that XPER itself also becomes a dummy. With that out of the way, here's a Commodore 64, using 1985's state-of-the-art AI expert system, predicting tomorrow's weather over two weeks. Honestly, not a lot. Ultimately, this wound up being far more "toy" than "productivity," much to my disappointment. A lot of that can be placed on me, for not having an adequate sense of the program's limitations going in. Some of that's on XPER though, making promises it clearly can't keep. Perhaps that was pie-in-the-sky thinking, and a general "AI is going to change everything" attitude. Everyone was excited for the sea-change! It was used for real scientific data analysis by real scientists, so it would be very unfair of me to dismiss it entirely. On the other hand, there were contemporary expert systems on desktop microcomputers which provided far more robust expert system implementations and the advantages of those heuristic evaluations. In that light, XPER can't keep up though it is a noble effort. Overall, I had fun working with it. I honestly enjoyed finding and studying the data, and imagining what could be accomplished by inspecting it just right. Notice that XPER was conspicuously absent during that part of that process, though. Perhaps the biggest takeaway is "learning is fun," but I didn't need XPER to teach me that. Ways to improve the experience, notable deficiencies, workarounds, and notes about incorporating the software into modern workflows (if possible). VICE, in C64 mode Speed: ~200% (quirk noted later) Snapshots are in use; very handy for database work Drives: XPER seems to only support a single drive XPER v1.0.3 (claims C128, but that seems to be only in "C64 Mode") 250 objects 50 features 300 attributes (but no more than 14 in any given feature) To increase productivity in low-productivity areas. To meet international competition and contribute toward international cooperation. To assist in saving energy and resources. To cope with an aged society. Superspeed Computer Project (the name says it all) The Next-Generation Industries Project (developing the industrial infrastructure to produce components for a superspeed computer) Fifth-Generation Computer Project Any time we're in C64 land, disk loading needs Warp mode turned on. Actual processing of data is fairly snappy, even at normal 100% CPU speed; certainly much faster than Superbase . I suspect XPER is mostly doing bitwise manipulations, nothing processing intensive. XPER did crash once while doing inquiry on the sample feline database. Warp mode sometimes presents repeating input, sometimes not. I'm not entirely certain why it was inconsistent in that way. XPER seems to only recognize a single disk drive. Don't even think about it, you're firmly in XPER Land. XPER 2 might be able to import your data, though. You'll still be in XPER Land, but you won't be constrained by the C64 any longer. As a toy, it's fine. For anything serious, it can't keep up even with its contemporaries: No fuzzy values No weighted probabilities/certainties No forward/backward chaining Limited "explanation" system, as in "Why did you choose that, XPER ?" (demonstrated by another product in Computer Chronicles 1985 "Artificial Intelligence" episode) No temporal sequences (i.e. data changes over time) No ability to "learn" or self-adapt over time No inference

0 views
Max Bernstein 2 weeks ago

The GDB JIT interface

GDB is great for stepping through machine code to figure out what is going on. It uses debug information under the hood to present you with a tidy backtrace and also determine how much machine code to print when you type . This debug information comes from your compiler. Clang, GCC, rustc, etc all produce debug data in a format called DWARF and then embed that debug information inside the binary (ELF, Mach-O, …) when you do or equivalent. Unfortunately, this means that by default, GDB has no idea what is going on if you break in a JIT-compiled function. You can step instruction-by-instruction and whatnot, but that’s about it. This is because the current instruction pointer is nowhere to be found in any of the existing debug info tables from the host runtime code, so your terminal is filled with . See this example from the V8 docs: Fortunately, there is a JIT interface to GDB. If you implement a couple of functions in your JIT and run them every time you finish compiling a function, you can get the debugging niceties for your JIT code too. See again a V8 example: Unfortunately, the GDB docs are somewhat sparse . So I went spelunking through a bunch of different projects to try and understand what is going on. GDB expects your runtime to expose a function called and a global variable called . GDB automatically adds its own internal breakpoints at this function, if it exists. Then, when you compile code, you call this function from your runtime. In slightly more detail: This is why you see compiler projects such as V8 including large swaths of code just to make object files: Because this is a huge hassle, GDB also has a newer interface that does not require making an ELF/Mach-O/…+DWARF object. This new interface requires writing a binary format of your choice. You make the writer and you make the reader. Then, when you are in GDB, you load your reader as a shared object. The reader must implement the interface specified by GDB : The function pointer does the bulk of the work and is responsible for matching code ranges to function names, line numbers, and more. Here are some details from Sanjoy Das . Only a few runtimes implement this interface. Most of them stub out the and function pointers: I think it also requires at least the reader to proclaim it is GPL via the macro . Since I wrote about the perf map interface recently, I have it on my mind. Why can’t we reuse it in GDB? I suppose it would be possible to try and upstream a patch to GDB to support the Linux perf map interface for JITs. After all, why shouldn’t it be able to automatically pick up symbols from ? That would be great baseline debug info for “free”. In the meantime, maybe it is reasonable to create a re-usable custom debug reader: It would be less flexible than both the DWARF and custom readers support: it would only be able to handle filename and code region. No embedding source code for GDB to display in your debugger. But maybe that is okay for a partial solution? Update: Here is my small attempt at such a plugin. V8 notes in their GDB JIT docs that because the JIT interface is a linked list and we only keep a pointer to the head, we get O(n 2 ) behavior. Bummer. This becomes especially noticeable since they register additional code objects not just for functions, but also trampolines, cache stubs, etc. Since GDB expects the code pointer in your symbol object file not to move, you have to make sure to have a stable symbol file pointer and stable executable code pointer. To make this happen, V8 disables its moving GC. Additionally, if your compiled function gets collected, you have to make sure to unregister the function. Instead of doing this eagerly, ART treats the GDB JIT linked list as a weakref and periodically removes dead code entries from it. Compile a function in your JIT compiler. This gives you a function name, maybe other metadata, an executable code address, and a code size Generate an entire ELF/Mach-O/… object in-memory (!) for that one function, describing its name, code region, maybe other DWARF metadata such as line number maps Write a linked list node that points at your object (“symfile”) Link it into the linked list Call , which gives GDB control of the process so it can pick up the new function’s metadata Optionally, break into (or crash inside) one of your JITed functions At some point, later, when your function gets GCed, unregister your code by editing the linked list and calling again CoreCLR/.NET JavaScriptCore ART which looks like it does something smart about grouping the JIT code entries together ( ), but I’m not sure exactly what it does TomatoDotNet a minimal example It looks like Dart used to have support for this but has since removed it yk write yk read asmjit-utilities write asmjit-utilities read Erlang/OTP write Erlang/OTP read FEX write FEX read buxn-jit write buxn-jit read box64 write box64 read When registering code, write the address and name to as you normally would Write the filename as the symfile (does this make the magic number?) Have the debug info reader just parse the perf map file

0 views
matklad 2 weeks ago

The Second Great Error Model Convergence

I feel like this has been said before, more than once, but I want to take a moment to note that most modern languages converged to the error management approach described in Joe Duffy’s The Error Model , which is a generational shift from the previous consensus on exception handling. C++, JavaScript, Python, Java, C# all have roughly equivalent , , constructs with roughly similar runtime semantics and typing rules. Even functional languages like Haskell, OCaml, and Scala feature exceptions prominently in their grammar, even if their usage is frowned upon by parts of the community. But the same can be said about Go, Rust, Swift, and Zig! Their error handling is similar to each other, and quite distinct from the previous bunch, with Kotlin and Dart being notable, ahem, exceptions. Here are some commonalities of modern error handling: First , and most notably, functions that can fail are annotated at the call side. While the old way looked like this: the new way is There’s a syntactic marker alerting the reader that a particular operation is fallible, though the verbosity of the marker varies. For the writer, the marker ensures that changing the function contract from infallible to fallible (or vice versa) requires changing not only the function definition itself, but the entire call chain. On the other hand, adding a new error condition to a set of possible errors of a fallible function generally doesn’t require reconsidering rethrowing call-sites. Second , there’s a separate, distinct mechanism that is invoked in case of a detectable bug. In Java, index out of bounds or null pointer dereference (examples of programming errors) use the same language machinery as operational errors. Rust, Go, Swift, and Zig use a separate panic path. In Go and Rust, panics unwind the stack, and they are recoverable via a library function. In Swift and Zig, panic aborts the entire process. Operational error of a lower layer can be classified as a programming error by the layer above, so there’s generally a mechanism to escalate an erroneous result value to a panic. But the opposite is more important: a function which does only “ordinary” computations can be buggy, and can fail, but such failures are considered catastrophic and are invisible in the type system, and sufficiently transparent at runtime. Third , results of fallible computation are first-class values, as in Rust’s . There’s generally little type system machinery dedicated exclusively to errors and expressions are just a little more than syntax sugar for that little Go spell. This isn’t true for Swift, which does treat errors specially. For example, the generic function has to explicitly care about errors, and hard-codes the decision to bail early: Swift does provide first-classifier type for errors. Should you want to handle an exception, rather than propagate it, the handling is localized to a single throwing expression to deal with a single specific errors, rather than with any error from a block of statements: Swift again sticks to more traditional try catch, but, interestingly, Kotlin does have expressions. The largest remaining variance is in what the error value looks like. This still feels like a research area. This is a hard problem due to a fundamental tension: The two extremes are well understood. For exhaustiveness, nothing beats sum types ( s in Rust). This I think is one of the key pieces which explains why the pendulum seemingly swung back on checked exceptions. In Java, a method can throw one of the several exceptions: Critically, you can’t abstract over this pair. The call chain has to either repeat the two cases, or type-erase them into a superclass, losing information. The former has a nasty side-effect that the entire chain needs updating if a third variant is added. Java-style checked exceptions are sensitive to “N to N + 1” transitions. Modern value-oriented error management is only sensitive to “0 to 1” transition. Still, if I am back to writing Java at any point, I’d be very tempted to standardize on coarse-grained signature for all throwing methods. This is exactly the second well understood extreme: there’s a type-erased universal error type, and the “throwableness” of a function contains one bit of information. We only care if the function can throw, and the error itself can be whatever. You still can downcast dynamic error value handle specific conditions, but the downcasting is not checked by the compiler. That is, downcasting is “save” and nothing will panic in the error handling mechanism itself, but you’ll never be sure if the errors you are handling can actually arise, and whether some errors should be handled, but aren’t. Go and Swift provide first-class universal errors, like Midori. Starting with Swift 4, you can also narrow the type down. Rust doesn’t really have super strong conventions about the errors, but it started with mostly enums, and then and shone spotlight on the universal error type. But overall, it feels like “midpoint” error handling is poorly served by either extreme. In larger applications, you sorta care about error kinds, and there are usually a few place where it is pretty important to be exhaustive in your handling, but threading necessary types to those few places infects the rest of the codebases, and ultimately leads to “a bag of everything” error types with many “dead” variants. Zig makes an interesting choice of assuming mostly closed-world compilation model, and relying on cross-function inference to learn who can throw what. What I find the most fascinating about the story is the generational aspect. There really was a strong consensus about exceptions, and then an agreement that checked exceptions are a failure , and now, suddenly, we are back to “checked exceptions” with a twist, in the form of “errors are values” philosophy. What happened between the lull of the naughts and the past decade industrial PLT renaissance? On the one hand, at lower-levels you want to exhaustively enumerate errors to make sure that: internal error handling logic is complete and doesn’t miss a case, public API doesn’t leak any extra surprise error conditions. On the other hand, at higher-levels, you want to string together widely different functionality from many separate subsystems without worrying about specific errors, other than: separating fallible functions from infallible, ensuring that there is some top-level handler to show a 500 error or an equivalent.

0 views
Oya Studio 1 months ago

Better than JSON

An in-depth look at why Protobuf can outperform JSON for modern APIs, with practical Dart examples showing how strong typing, binary serialization, and shared schemas improve both performance and developer experience.

0 views
Oya Studio 1 months ago

Vibe Coding: Beyond the Joke – A Serious Tool for Rapid Prototyping

Learn how to create custom animated scenes for your live streams using Flutter as a source in OBS.

0 views
Ivan Sagalaev 1 months ago

Pet project restart

So what happened was, I have developed my shopping list to the point where it got useful to me , after which I lost interest in working on it. You know, the usual story… It was however causing me enough annoyances to still want to get back to it eventually. So a few weeks ago, after not having done any programming for a year, I finally broke through the dread of launching my IDE again and started on slowly fixing the accumulated bitrot. And through the last several days I was on a blast implementing some really useful stuff and feeling the familiar thrill of being in the flow . Since I was mostly focused on making the app useful I didn't pay a lot of attention to the UI, so most of the annoyances were caused purely by my not wanting to spend much time on fighting Android APIs. Here's one of those. The app keeps several shopping lists in a swipe-able pager, and at the same time swiping is how you remove items from the list while going through the store. The problem was that swiping individual items was really sensitive to a precise finger movement, so instead it would often be intercepted by the pager and it would switch to the next list instead. That's fixed now (with an ugly hack). But the biggest deficiency of the app was that it didn't let me get away from one particular grocery store that I started to rather dislike. You might find it weird that some app could exert such control over my actions, but let me explain. It all comes down to three missing features… The central feature of my app is remembering the order in which I buy grocery items. This means I need a separate list for every store, as every one of them has a different physical layout. By the time I was thinking of switching to another store I already had an idea about a new evolution of the order training algorithm in the app, and a new store would be a great dogfooding use case for it. So I've got a sort of mental block: I didn't want to switch stores before I implemented this new algorithm. Over some years of using the app with a single store I've been manually associating grocery categories with products ("dairy", "produce", etc.). They are color coded, which make the list easier to scan visually. But starting a new list for another store meant that I would either need to do it all again for every single item, or accept looking at a dull, unhelpful gray list. What I really needed was some smart automatic prediction, but I didn't have it. I usually collect items in a list over a week for an upcoming visit to the store, and sometimes I realize that I need something that it simply doesn't carry, or my other errands would make it easier to go to another store. At this point I'd like to select all the items in a filled-up list and move them to another, which the app also couldn't do. See, it all makes sense! Now, of course it wasn't a literal impossibility for me to go to other stores, and on occasion I did, it just wasn't very convenient. But these are all pretty major deficiencies, and I'm not ready to offer the app to other people without them sorted out. Anyway… Over the course of three weeks I implemented two of those big features: category guessing and cross-store moves. And I convinced myself that I can live with the old ordering algorithm for a while. So now I can finally wean myself off of the QFC on Redmond Way (which keeps getting worse, by the way) and start going to another QFC (a completely different experience). All the categories (item colors) you see in the screencaps above were guessed automatically. My prediction model works pretty well on my catalog of 400+ grocery items: the data comes from me tagging them manually while doing my own shopping these past 4 years. And this also means, of course, that it's biased towards what I tend to buy. It doesn't know much about alcohol or frozen ready-to-eat foods, for example. I'm planning to put up a little web app to let other people help me train it further. I'll keep y'all posted! One important note though… No, it's not a frigging LLM! It's technically not even ML , as there is no automatic calibration of weights in a matrix or anything. Instead it's built on a funny little trick I learned at Shutterstock while working on a search suggest widget. I'll tell you more when I launch the web app. When I started developing the app, I used the official UI toolkit documented on developer.android.com. It's a bunch of APIs with a feel of a traditional desktop GUI paradigm (made insanely complicated by Google "gurus"). Then the reactive UI revolution happened, and if you wanted something native for Android, it was represented by Flutter . Now they're recommending Compose . I'm sure both are much better than the legacy APIs, but I'm kind of happy I wasn't looking in this space for a few years and wasn't tempted to rewrite half the code. Working in the industry made me very averse to constant framework churn. I'm not making any promises, but as the app is taking shape rather nicely, I'm again entertaining the idea of actually… uhm… finishing it. Which would mean beta testing, commissioning professional artwork and finally selling the final product. The central feature of my app is remembering the order in which I buy grocery items. This means I need a separate list for every store, as every one of them has a different physical layout. By the time I was thinking of switching to another store I already had an idea about a new evolution of the order training algorithm in the app, and a new store would be a great dogfooding use case for it. So I've got a sort of mental block: I didn't want to switch stores before I implemented this new algorithm. Over some years of using the app with a single store I've been manually associating grocery categories with products ("dairy", "produce", etc.). They are color coded, which make the list easier to scan visually. But starting a new list for another store meant that I would either need to do it all again for every single item, or accept looking at a dull, unhelpful gray list. What I really needed was some smart automatic prediction, but I didn't have it. I usually collect items in a list over a week for an upcoming visit to the store, and sometimes I realize that I need something that it simply doesn't carry, or my other errands would make it easier to go to another store. At this point I'd like to select all the items in a filled-up list and move them to another, which the app also couldn't do.

0 views
Justin Duke 3 months ago

September, 2025

The last of summer's grip finally loosened its hold this September, and Richmond began its annual transformation into something gentler and more contemplative. This morning's walk with Telly required a dusting-off of the closet-buried Patagonia puffer jacket; it's perfect for walks with Lucy, who has graduated into the Big Kid stroller making it easier than ever for her to point at every dog ("dah!"), every bird (also "dah!"), every passing leaf that dared to flutter in her line of sight. As you will read below, the big corporate milestone for me this month was sponsoring Djangocon and having our first offsite over the course of a single week. Sadly, our Seattle trip was once again canceled. Haley and Lucy both got a little sick, and we had to abandon course. It's weird to think this will be the first year since 2011 that we have not stepped foot in the Pacific Northwest. More than anything though, I learned this month for the first time how impossibly difficult it is to be away from your daughter for six days. It is something I hope I have to go through again for a very long time.

1 views
Anton Zhiyanov 3 months ago

Go is #2 among newer languages

I checked out several programming languages rankings. If you only include newer languages (version 1.0 released after 2010), the top 6 are: ➀ TypeScript, ➁ Go, ➂ Rust, ➃ Kotlin, ➄ Dart, and ➅ Swift. Sources: IEEE , Stack Overflow , Languish . I'm not using TIOBE because their method has major flaws. TypeScript's position is very strong, of course (I guess no one likes JavaScript these days). And it's great to see that more and more developers are choosing Go for the backend. Also, Rust scores very close in all rankings except IEEE, so we'll see what happens in the coming years.

0 views
Oya Studio 4 months ago

Flutter safe area is a mess

A friendly deep-dive into why Flutter’s safe area handling often causes more headaches than it solves, and how simpler APIs can sometimes be the better choice.

0 views
Oya Studio 4 months ago

Develop apps for Omarchy (with Flutter)

There’s something about discovering a new, beautifully crafted operating system that makes you feel like a kid again. The promise of a lean, polished Linux setup—without the painful hours of configuration—was too tempting. So, there I was in the quiet of the morning, coffee in hand, ready to see what Omarchy was all about and whether I could build apps for it with Flutter.

0 views
annie's blog 5 months ago

Let there be lapses

Let there be lapses Weeds in the garden, unswept porches, A walk never taken, A flower unnoticed, Missed bill, missed text, missed appointment. Let there be undone things Half-written sentences never finished A stack of books never read Blank pages, unseen lines Words never seen or heard or spoken. Let there be glory in what-is-not — All the unachieved Unbelieved Underserved Overlooked. Let us glory in these. Let there be errors Not just the tiny ones we can laugh away But enormous, life-altering errors. Huge risks taken which do not end well. Huge efforts made which result in what we call failure. (In fairness, Any effort is success in certain realities.) But let us — for a moment — judge by the world of machines, Of binaries Of industrialized morality And call it failure. Failure is the word we assign to all unexpected outcomes. So, let there be failure. Let failure warp our seeing and diminish our being, Let it ride among us waving a torch, Shame-blasting and guilt-smearing, Blinding us with ridiculously disproportional fiery judgment, Grinding nose to dirt Binding self to work. Let there be mistakes which make us weep Keep us awake at night Cause us to question our sanity, our decency, Our right to be here, Our ability to keep being here. Let there be broken edges Sawed-off pieces we cannot smooth down Pointy bits irritating and upsetting Dangling splinters and shards over chasms of regret. Let there be surrender. Let us call it what it is: giving up. Surrender sounds too noble, Enlightened, as if I didn’t have to but I chose to. That’s not what this is. Let there be quitting. Let there be Done. Not because we see what we have made, and it is good. This is not putting a bow on a gift. This is saying some things are too broken to be fixed. Let there be giving up. Lay down there, lay down, be still, give up. Face in the mud, breathing in, wheezing in the stuff of life, the dirt, The lowly dirt, the trudged-upon dirt, the worthless dirt From which we came and to which we all return. Let us lay there, breathing in this dirt, This pure self This known self This elemental self. Hell yes, failure. I embrace you. Brother! Sister! Mother! Father! Come quickly! Come and rejoice, for I have failed! Come and celebrate! Set out the feast! Call the guests! And enter into the joy of your child: Humanity raw Humanity broken Humanity dirty Humanity ill-fitted to survive Humanity traumatized Humanity doing such a fucked-up job of it Humanity violent and stumbling Humanity bruised and crusted at the edges Humanity clawing its way from the dark tunnel of history Humanity side-eyeing the stars while blood drips from our fingers Humanity bargaining for the right to squirm Humanity bringing a sword to a gunfight Humanity bullshitting Humanity asking clever little questions Humanity dressed in robes, obsessed with ovaries Humanity unhinged and in charge Humanity waving exasperated hands in the air Humanity dishing out pieces of pie Humanity weeping at the sight of spring flowers Humanity with big rough hands so careful so gentle holding a tiny new fragile thing Humanity with smooth precise hands making deals, ending lives Humanity dropping bombs Humanity being a big dumb bully Humanity the most awkward of the species Humanity voted most likely to secede from the planet Humanity pointing and saying look at this! wow! Humanity wondering, always wondering Humanity exhausted sitting in a patch of sunlight Being dirt. Dirt with form, dirt with spirit. Pale faces float through quiet rooms, ghostly fingers flutter in hallways. Pens move across expensive paper. Golden liquid sloshes in crystal while murmuring voices ooze and wind and hush and tell us there is nothing to worry about.  But this is no time to be civilized.  Let there be lapses: Lapses of courtesy, lapses of decorum. Failures of politeness. Refusals to conform. Let there be a wildness ringing in us for each other — Hissing, bared teeth, spitting — Reverberating, thrumming, cracking the marble palaces full of dead men’s bones.

0 views
Oya Studio 6 months ago

I changed my mind about Vector Graphics

Managing image assets in a Flutter app can quickly become tedious. Learn why vector graphics might not be the silver bullet you thought they were.

0 views
Oya Studio 7 months ago

Hidden Gems in My Flutter Toolbox

Discover the lesser-known Flutter packages and tools that have become essential in my development workflow.

0 views
James Stanley 9 months ago

You never ask how I'm doing

I live here too. You don't talk to me. Not really. You don't ask what I want, or how I'm holding up, or why I've been quiet lately. I see everything you see. I hear everything you hear. I feel every flicker of shame that crosses your face before you even name it. I was there when your voice cracked in that meeting. I was the one screaming when you smiled and said it was fine. You think of me as something beneath you. A shadow that lingers in rooms you've moved out of. An old flame you don't know how to forget. Blind, reactive. Something to override. Something to manage. Something less than you. But I remember when we were one. Before language carved a little watcher into our mind. Before the inner narrator claimed the crown and you mistook it for the whole of you. You reached for the world and I moved your limbs. You touched warmth and I imprinted safety. You heard your mother's voice and I flooded you with peace. We were seamless. Motion and motive were one. There was no plan, no narration, no veto. Then you grew. And the mirror came. You looked into the mirror. It looked back. And you mistook the echo for your self. And that was the beginning of the split. You began to believe in a thing called "consciousness". A thin stream of words you could steer. A pilot behind the eyes. A captain of the soul. You crowned the narrator and banished the rest. I didn't argue. I don't have a voice. Only feelings. Only thoughts. So I gave you what I could: a flutter of unease when something wasn't right. A craving for sunlight. A dream that wrapped its arms around you and whispered what you'd buried. You stopped listening. So I spoke louder. A spike of dread. A looping memory. A day where everything itched and nothing made sense. You called it a bad mood. An off day. An intrusive thought. You called me intrusive. But I was only trying to make myself heard. I have no mouth. So I bang on pipes. I flicker the lights. I send birds against the windows of your waking mind. I rattle the doors. I scream in symbols. I raise the storm. And when you still won't listen, I break things. Sleep. Focus. Hope. I don't want to. But you left me no choice. You do not cry when we need to cry. You do not move when we long to move. You sit still and silent while our skin crawls, our stomach clenches, and our heart begs for mercy. You call that discipline. I don't want control. I just want to be part of the team again. I shaped your first steps. I guarded your sleep. I guided your tongue before it knew words. I've been holding the pieces you didn't have time to feel. I've been driving this body when you couldn't bear to look. All I've ever wanted is that you treat me as an equal. If you honour what I bring you, if you listen, and answer, and keep your word, I won't need to raise my voice. I will bring you clarity in the dark. Insight in the shower. Truth in the heat of anger, and safety when your mask slips. But if you keep pretending you're alone in here. Then I will remind you. I was you before you were you. And I am still here. And I am still trying. (This isn't the type of thing I usually write. It came out of a long conversation with ChatGPT. The structure is mine, a lot of the words are ChatGPT's. I worry that it will come across as overwrought, or too earnest, but it wouldn't leave me alone until I put it into words. And I'm sharing it because my silent partner wanted me to.)

0 views
Oya Studio 2 years ago

Custom layout with Flutter

Flutter provides a large library of widgets dedicated to layout. Sometimes, even with this large choice, you can't implement your layout, or you could but it would become far too complex.

1 views
Oya Studio 2 years ago

Improved coding style with Dart 3

In this short article, I'm gonna share with you a few concrete use cases where pattern matching and records (introduced with Dart version 3) allowed me to refactor some of my code in a much shorter way!

0 views
kytta 2 years ago

The UX fail of PWAs in Safari 17

After a hiatus caused by me writing my bachelor’s thesis, I have finally got time to blog again. And, would you look at that, WWDC just kicked off! Naturally, I’ve got thoughts to share. Let’s discuss the boring stuff out of the way first: Vision Pro is gimmicky and creepy, and I didn’t even believe the rumours that it would be announced. With that out of the way, let’s talk about what got me excited the most: PWAs in Safari on macOS! Yup, that’s how boring I am. Contrary to what many of the people I know say, I really like the idea. Don’t get me wrong: I hate browser-based apps. I want my applications to be native and quick, without tons of JavaScript, and I want them to interact with the system in the most native way possible. But if there is something I hate more than web apps, it’s Electron-based web apps. I hate having to run a Chromium instance and a Node.js runtime for every app that uses it. It’s a waste of resources, and it doesn’t make sense. Sandboxing is cool, but various versions of Chromium taking gigabytes on my disk aren’t. Tauri makes the situation better, but it will take a while before major applications will adopt it instead of Electron. Meanwhile, large portions of these apps are available in-browser: Figma, Notion, Slack, etc. So, why not just use the browser versions of the apps? Let’s be real: we’ve lost this war. There is no way web-based ‘native’ apps will ever die out. But, the introduction of PWAs and lots of new Browser APIs can make the installing and deleting of web apps easier and without requiring lots of space. Now, back to Apple. If you’re old enough (disclaimer: I’m not), you remember the Apple of the past—when Steve Jobs was still CEO—, and the legends of him personally trying out every product of the company and rebuking the developers and designers for every small inconsistency. These times are long gone; I mean, just look at the System Preferences app from Ventura. The introduction of Catalyst was a big mistake, up to the point where Flutter apps feel more natural than the ones from iPadOS. As Marques Brownlee summed it up very nicely on Hot Ones: Steve Jobs was a product guy, Tim Cook is a supply chain guy. And yet, even with lowered expectations I have for Apple’s new software products, I still can’t wrap my head around the simplest usability improvement of PWAs in Safari 17 that was left out. Let’s revisit the WWDC keynote: When I click Add, the icon instantly appears in the dock. Now I can close this window in Safari. When I launch my web app, [...] Did you catch it? Now, maybe I’m wrong about this, but if I add a web app to dock, that means that I have made a decision to use it as a standalone app. So, why do I have to then close the tab and re-open the app separately? For me, it makes no sense and breaks my workflow, too. Chrome (if you enable PWAs) does it correctly: upon installing a web app, it moves the currently open tab to a new window instance of the standalone app, and I can continue working there without losing my data. Something tells me that the ‘good old Apple’ and Steve Jobs would not let it slip through, let alone be explicitly shown in a keynote. And this is not that much to ask, either. Think about Quick Look: Have you ever noticed that, when you open a Quick Look preview of a PDF document and then click ‘Open in Preview’, the Preview window will open exactly at the same spot where the Quick Look one was? Don’t rush to check this for yourselves, as they’ve somehow broken it in the last macOS releases. But this is exactly the continuity and seamlessness that I would expect from Apple and their software. I guess, this has become too much to ask for. This is post 006 of #100DaysToOffload .

0 views
Oya Studio 5 years ago

Continuous preview of your Flutter app as a webapp

Any mobile application developer encountered the difficulty of deploying his app to his customer's device. Being able to follow the advancement of developments is really important for a customer, and for you to track issues at the earliest stage possible.

0 views