I don't want to go to Chel-C
applied-langua.ge
applied-langua.ge
My understanding of Jon Blow's argument is not that he is against certain classes of "safe" languages, or even formal verification. It is that software, self-evidently, does not work well -- or at least not as well as it should. And a big reason for that is indeed layers of unnecessary complexity that allow people to pretend they are being thoughtful, but serve no useful purpose in the end. The meta-reason being that there is a distinct lack of care in the industry -- that the kind of meticulousness one would associate with something like formal verification (or more visibly, UI design and performance) isn't present in most software. It is, in fact, this kind of care and dedication that he is arguing for.
His language is an attempt to express that. That said, I'm not so sure it will be successful at it. I have some reservations that are sort of similar to the authors of this piece -- but I do appreciate how it makes an attempt, and I think is successful in certain parts, that I hope others borrow from (and I think some already have).
John isn’t right about everything: he criticizes LSP in the cited talk, and I think the jury is in that we’re living in a golden age of rich language support (largely thanks to the huge success of VSCode). I think he was wrong on that.
But the guy takes his craft seriously, he demonstrably builds high-quality software that many, many people happily pay money for, and generally knows his stuff.
Even Rust gives up some developer affordances for performance, and while it’s quite fast used properly, there are still places where you want to go to a less-safe language because you’re counting every clock. Rust strikes a good balance, and some of my favorite software is written in it, but C++ isn’t obsolete.
I think Jai is looking like kind of what golang is advertised as: a modern C benefitting from decades of both experience and a new hardware landscape. I have no idea if it’s going to work out, but it bothers me when people dismiss ambitious projects from what sounds like a fairly uninformed perspective.
HN can’t make up its mind right now: is the hero the founder of the big YC-funded company that cuts some corners? Is it the lone contrarian self-funding ambitious software long after he didn’t need to work anymore?
He has made a few good games, but how has he done anything that would paint him as a competent language designer? Frankly, Blow has done very little (up to and including being a non-asshole) that would make me terribly interested in what he's up to.
The jury is out on Jai, but it’s clearly not a toy. John emphasizes important stuff: build times, SOA/AOS as a first-class primitive, cache-friendliness in both the L1i and L1d. And he makes pragmatic engineering trade offs informed by modern hardware: you can afford to over-parse a bit if your grammar isn’t insane, this helps a lot in practice on multi-core. The list goes on.
And “he made a few good games” is really dismissive. He doesn’t launch a new game every year, but his admittedly short list of projects is 100% wild commercially and critically successful. On budgets that a FAANG spends changing the color of some UI elements.
And that’s kind of the point right? Doing better work takes time, and there is in fact a lucrative market for high-quality stuff.
As for him being an asshole? He’s aspy and curt and convinced he’s right, which is a bad look on the rare occasions when he’s wrong.
But Bryan Armstrong is on the front page doubling-down on such bad treatment of his employees and shareholders that they are in public, written revolt. This may have changed since I looked, but no one is calling him an asshole.
A world in which a passionate craftsman misses on diplomacy while discussing serious technical subject matter is an asshole but a well-connected CEO revoking employment offers after people already quit their old job is “making the hard calls” is basically the opposite of everything the word “hacker” stands for.
Asshole.
How is that dismissive? He has indeed made a few good games, but making good games doesn't certify you as a language designer any more than it makes you a good plumber or equinologist. Hollow Knight is my favorite game of all time, immensely successful both critically and commercially, and yet if Team Cherry were to release a programming language I reserve the right not to be terribly excited about it.
> But Bryan Armstrong is on the front page
OK, Bryan Armstrong is an asshole. I can call two people an asshole. I can call more people than that assholes too, if it comes to that.
> Asshole
Because I'm dismissive of Jonathan Blow? Listen, if you want to fanboy/girl your brains out over the guy, be my guest. He just doesn't impress me all that much and I don't think "aspy and curt and convinced he's right" is anything remotely approaching an excuse for poor behavior. I've been told I'm on the autism spectrum, too, yet I manage not to act like an asshole. Though clearly you disagree.
In this instance, it allows you to blow past the few concrete examples amongst many that I cited where Jai is trying new things in the language space. It’s not hard work to learn a little about Jai. Jai may be an utter failure, but it’s not a toy or hobby, it’s being co-designed with an interesting game engine that looks pretty hot. It’s at least as expressive as C99, compiles way faster on modern gear, targets LLVM and x86, it’s at a minimum interesting.
Calling someone who does their homework a “fanboi” is A-ok, but someone else is looking for an excuse for poor behavior?
You can watch his Twitch streams and see what he does and how he uses the language.
He's developing at least two games using it (the development of one of them he also shows on stream) and so far it's been proven to be a very strong contender for a C-like language suitable for game development. Just the fact that his entire 3-D game builds in under a few seconds is definitely something to aspire to.
Jon and the authors of uxn commit a common fallacy in that they're chasing a brass ring of in-the-small performance metrics, getting it in the form of particular demonstrations, and then gradually accreting features to it until, most likely, they end up in a similar position to the old tech. Many software projects start off as the "light and simple alternative" and then develop into something not light and simple. This isn't necessarily an issue for any particular project, because if you know the goal of your tech, you don't need all the features and so can omit some things to claim a definite advantage for the application; but it's not in and of itself a solution to the general issue of making computing better, because it entails bespoken effort from expert practitioners, while the general trend in computing tech is the same as most industrial automation - it's quality-first. Quality comes first when you automate, because a superhuman level of quality can redefine what's possible, and it can compensate for the downsides of not being a bespoke, artisanal result.
The actual problem faced by language authors is that they face difficulty in defining quality while also generalizing the problem space. New languages are mostly "old concepts, new syntax and libraries" - still giving improvements in UX and therefore quality, but with most of the features carried over from previous languages.
The authors of this post note the same tendency with Gemini [1] and demonstrate that the clients are actually quite fat, much fatter than their rationale documents claim they should be.
If creating full games is an in-the-small performance for a particular demonstration, I can't even imagine what an in-the-big is.
> The actual problem faced by language authors is that they face difficulty in defining quality while also generalizing the problem space
As far as I can tell, jai is exactly that. It's already dropped a few features that looked fine in theory but didn't work for actual development.
I can watch coworkers blaze through Common Lisp in emacs, that doesn't mean it's the Next Big Thing in developer experience and performance.
The privacy of development has made Jai less than compelling, for a lot of us I think. I'd be personally more excited if I could use it and poke around at it, rather than see someone tinker on video streams. I get why he's doing things that way, but it's just hard to feel like it's going to be meaningful for anyone but him so long as it's kept hidden away.
With that said, it’s on record that an open source release is planned, and whether or not it works, it’s not insane to run something past 100 early adopters before putting it on GitHub.
This isn't a good argument for C++. If you can't get where you need to go in Rust because you are "counting every clock" you need to go down, which means writing assembler -- not sideways to C++. Once you're counting every clock, none of the high level languages can help you, because you're at the mercy of their compiler's internal representation of your program and their optimisers. If you care whether we use CPU instruction A or CPU instruction B, you need the assembler, which likewise cares, and not a high level language.
Both C++ and Rust provide inline assembler if that's what you resort to.
There are things to like about C++ but "counting every clock" isn't one of them.
The common thing in PL is to publish something written or code. So don’t be surprised when some people don’t feel like they have the time to go through an unconventional format.
It's also very hard, for me at least, to interpret the sum of his arguments in the talk as anything except "If you're not managing memory, you're not a real programmer."
I'm truly sympathetic. The simplicity of the microcomputer era has a certain romance to it, especially if you never lived through the reality of it. There's a sense of freedom to the model of computing where only your program is running and the entirety of the machine is your own little playground. So I get why people make stuff like PICO-8 and uxn.
I agree with the criticism of Jon Blow's rhetoric, even though the tone is harsher than strictly necessary. Blow's criticisms and proposed solutions seem overly opinionated to me, and he's throwing out the baby with the bath water. He describes things like compile time and runtime hygienic macros like they're a new invention that hasn't existed in Lisp since before he was born.
However, I think targeting uxn is unfair. Uxn would be viewed better as an experiment in minimalism and portability. I think of it more like an art project.
It's unfair because the author is comparing mainstream languages that benefit from countless users' input and innovations over the course of 60 years to a niche system with a small handful of developers that has existed for maybe 2 years or so. That's a strawman if I ever heard one.
Having actually experienced it, all the way back to writing business applications in mainframe assembler, I am not nostalgic for it. Today I write mostly in Rust.
[1]: https://mwcampbell.us/a11y-history/echo.mp3 This file has a real Echo followed by an emulator. Unfortunately, I forgot where I got it, so I can't provide proper attribution.
He explained to me what a “patch” actually means, or meant back then. He was talking about debugging and implementing loaders for new hardware and such, then he mentioned a “patching area”, I asked wtf that means and apparently the release cycles then where so slow, that a binary left some dedicated space for you to directly hack in a patch. He then would change the machine code directly to jump to the patched area so he could fix a bug or extend the behavior.
Contrast this to the arguably wasteful CI/CD setups we have now.
To clarify, are you arguing that modern build and release processes should patch binaries in-place, or something else?
I’m all for burning more cycles on tests and static analysis and formal verification etc. before the software goes on the user’s machine.
But we all live every day with “good enough” on our machines every day. I think there’s a general consensus that too much software spends my CPU cycles like a drunken sailor.
But most of them are burned on layers upon layers of abstraction that do not actually do anything useful safety- or correctness-wise; they're there solely because we've turned code reuse into a religion. Which wouldn't be bad by itself, if that religion had a firm commandment to not reuse bad solutions - yet that is exactly what we keep doing, again and again, patching it all with the software engineering equivalents of duck tape and glue to keep it all from falling apart. Why is C still at the bottom of virtually every software stack we run? Why do we keep writing desktop apps in HTML/JS? Does a simple app really need 20 dependencies of uncertain quality?
JavaScript is a good example. It's not a bad language because it's high-level - to the contrary, that's the best part of it! It's a bad language because, despite being high-level, it still gives any user ample opportunities to mess things up by accident. We need something just as (if not more) high level but better for general-purpose software development.
But let’s not get carried away with it. Eich had 9 days from unreasonable manager to shipping physical media. To do kind of a cool Scheme/Self thing from scratch in 9 days? I’ve been on some high-G burns, but that’s fucking nuts.
But since there’s no scientific way to quantify any of this, I’ll throw my anecdote on the scale in favor of my opinion and note that Brendan Eich was a hard-ass Irix hacker at SGI before he followed Jim Clark to Netscape.
But, regardless of how we got here and whose fault it is, we're here - and it's not a good place.
For example back then it was common to understand the whole machine code of a binary in total. We’re talking no abstraction, no runtimes. Portability and virtual memory were luxuries.
I definitely think CI/CD could be less wasteful, but I don’t necessarily think we should manually patch binaries in place.
For example, when I scroll a two-page document in Google Docs my CPU usage on an M1 Mac spikes to 20%. For an app with overall functionality that is probably less than that of a Word 95.
I suspect that this is where some of the inspiration comes from, because he mentioned being a fan of Scheme at a young age. At the same time he wants strong static typing, fine grained control and power (non restrictive).
These days, we call that little playground a 'sandbox'. But I think OP's point is that sandboxes can be a lot more efficient that what they see w/ uxn. It's not exactly a secret that the whole FORTH model does not easily scale to larger systems: that's why other languages exist!
People say this with a straight face, and I don't know if it's an elaborate joke of some kind or not.
We're building a tower of babel that requires supercomputers to barely run, and somehow end up defending it.
The comment you're replying to is not defending the explosion of complexity but pointing out that we resent it precisely because we find ourselves dependent on it. The article is pointing out that we tend to take bad or counterproductive paths when we try to free ourselves from that complexity though.
And at the end it's basically nostalgia, which is a really old trap, so old that the warnings are well posted for many centuries. If you're stepping into that trap, as Blow seemingly has, you have specifically ignored warnings telling you what's about to happen, and you should - I think - be judged accordingly.
Whether he has any real solutions to the decay of modern software is, of course, another question. It makes intuitive sense that, since previous generations were able to develop efficient and pleasant-to-use software for much more constrained computers than the ones we now have, we can gain something by looking back to the past. But those previous generations of software also lacked things that we're no longer willing to give up -- security, accessibility, internationalization, etc. That doesn't mean we have to settle for the excesses of Electron, React, etc. But it does mean that, at least for software that needs qualities like the ones I listed above, we can't just go back to the ways software used to be developed for older computers. So, I think you're right about the danger of nostalgia.
I think that's precisely the danger. It's the danger of using nostalgia to feed into a purity spiral. We can simultaneously acknowledge that there's problem where we create bad software that wastefully uses resources on a user's computer while understanding that part of modern development has made computing much safer and more accessible than it used to be. Instead of looking _backward_, we can look _forward_ to a future where we can continue to be safe and accessible while not being as wasteful with a user's resources.
My name is Devine, and I'm to blame for the uxn disaster.. I'm getting this link thrown at me from all sides right now, so I figured I might as well chip in.
I'm a bit more on the design-y side of things, and all these fancy words to talk about computers and retro computing, are a bit beyond me, and reference an era of computing which I didn't really had a chance to experience first hand.
But let's talk about "the uxn machine has quite the opposite effect, due to inefficient implementations and a poorly designed virtual machine, which does not lend itself to writing an efficient implementation easily."
This is meaningful to me and I'd love to have your opinion on this. Before setting on the journey to build uxn, I looked around at the options that were out there, that would solve our specific problems, and I'd like to know what you would recommend.
Obviously, I take it that the author is not advocating that we simply return to Electron, and I take it they understand that re-compiling C applications after each change is not viable with our setup, that Rust is manyfolds too slow for us to make any use of it, and that they understand that our using Plan 9, C is not a good candidate for writing cross-compatible(libdraw) applications anyway.
So, what should we have done differently?
I'm genuinely looking for suggestions, even if one suggestion might not be compatible with our specific position, many folks come to us asking for existing solutions in that space, and I would like to furnish our answers with things I might have not tried.
Here are some directions we tried prior to Uxn:
https://wiki.xxiivv.com/site/devlog.html
Ah, one last thing, this is how you fib the first 65k shorts in uxntal:
https://git.sr.ht/~rabbits/uxn/blob/main/projects/examples/e...
Having said that, IMO, if you're having fun with uxn and its retro 8-bit aesthetic, by all means keep going with that.
It's neat, but I don't remember seeing a graphical API for it, I'll have a look :)
The article suggests that Uxn programs can write to arbitrary locations on the filesystem. If that is the case, it seems like it would be really easy to change that in the interpreter. Then Uxn's security model would be essentially identical to how the article describes WebAssembly: the interpreter serves as a "sandbox" that prevents programs from touching anything outside their own virtual memory. This is a good security model and it likely makes a lot of sense for Uxn.
Otherwise, the article seems to be more bluster than substance. Uxn is probably not going to be the fastest way to compute the Fibonacci sequence, nor the most secure way to protect a telecommunications network from foreign cyber-attacks, but it doesn't need to be either of those things to be useful and valuable as a way to write the kind of UI-focused personal computer software you want to write.
Some of the emulator sandbox the file device, it is likely to be the way that all the emulators will work eventually.
Say you're trying to "translate" a Uxn program into x86 code. The easiest way to do this is by going through each of the instructions in the program one by one, then converting it to an equivalent sequence of x86 instructions. (There is a little complexity around handling jumps/branches, but it's not too bad.)
But if the Uxn program is allowed to change its own code at runtime, that kind of conversion won't work. The Uxn program can't change the x86 code because it doesn't know what x86 code looks like--it only knows about Uxn code. There are some ways around this, but either they're really slow (eg by switching back to an interpreter when the Uxn code has been modified) or much more complex (eg a JIT compiler) or don't work all the time (due to the halting problem).
Therefore what compilers will actually do is reorder program behavior towards optimal pipeline usage(where doing so doesn't break the spec). This has clear downsides for any programming style that relies on knowing instruction-level behavior. And it is so hard to keep up with the exactly optimal instructions across successive generations of CPU that in the majority of cases, humans just never get around to attempting hand optimization.
The benefit of defining a VM is that you can define whatever is optimal in terms of pragmatic convenience - if you want to write programs that have a certain approach to optimization, you can make some instructions, uses of memory or styles of coding relatively faster or slower, and this leads to an interesting play space for programmers who wish to puzzle through optimization problems. But unless it also happens to represent the actual hardware, it's not going to achieve any particular goal for real performance or energy usage - at least, not immediately. Widespread adoption motivates successively more optimal implementations. But that logic makes it hard to justify any "starting over" kind of effort, because then you end up at the conclusion that the market is actually succeeding at gaining efficiency through its fast-moving generational improvements, even if it does simultaneously result in an environment of obsolescence as the ecosystem-as-a-whole moves forward and leaves some parts behind.
An alternate path forward, one which can integrate with the market, is to define a much more narrow language for each application you have in mind, and be non-particular about the implementation, thus allowing the implementation to become as optimal as possible given a general specification. This task leads, in the large scale, towards something like the VPRI STEPS project, where layers of small languages build off of each other into a graphical desktop environment.
What setup is that? Or, where can I read more about it? I realize this is kind of irrelevant, since the original article criticizes C and similar languages. But I'm curious.
So, of course you can, I've written every application that now exist on Uxn, in C prior to porting them. There was a moment when I was quite convinced that C was a good candidate for what we wanted to do.
For example, equivalent programs:
C version: https://git.sr.ht/~rabbits/orca-toy/tree/main/item/etc/orca....
Uxn version: https://git.sr.ht/~rabbits/orca-toy/tree/main/item/src/orca....
Compiling Orca C(SDL on Pi), is about 10x~ slower, more battery hungry, (and also for some reason, very upsetting to ASAN), than building C(libdraw on Pi), which is itself about 50x slower and battery hungry than building the Uxn version.
I can compile little C cli tools on the Pi just fine, that's not the issue, building x11 or SDL applications with debug flags is another story. I much rather be assembling uxn roms in this case. I wrote a few cc65 compiled applications prior to building uxn as an alternative, but that was a non-starter on ARM.
If you can limit yourself within low resolution, small color pallete, direct use of simple graphics API, basicalyl target the computing experience of when computers had 50mhz CPU. Then its possible to make things blazing fast even on a Pi, using ANY language? I'm sure on a "well ackshually" level there is some difference in how the CPU executes things but practically its like milliseconds and milliamps not anything perceptable.
WIth C Im not sure if I know what im talking about here (i've compiled hello world with gcc myself, otherwise i know how to use Make even though i dont understand it but ive also never needed to understand it, but seems like every project uses makefiles or something like it...) but isn't compiling SDL or libdraw a 1 time thing the very first time you build the program, then each time you make a change to orca.c it compiles pretty quick (until 'make clean')? you dont include the time to re-compile uxn emulator when you say uxn is 50x faster? What is ASAN?
I haven't found that the C build systems necessarily make this faster or more pleasant, they often get in my way and make it hard to replicate my environment across devices.
It's that same idea that you just said, that "any language will do", that sent me down the path toward virtual machines, if the language doesn't matter, I might as well pick something that appeals to my aesthetics and maps well with what I'm trying to do.
If Orca was written in Lua for a framework like Love2d, for example, then I wouldn't have to recompile love2d itself, it would be more akin to how uxn works. That's usually why people use scripting languages, I think?
ASAN is an address sanitizer, if you do any c development on arm devices, you'll get pretty familiar to its countless ways of breaking in fun ways.
And "don't let the turkeys get you down". :)
The "Provably Correct" book presents the work of Dr. Margaret Hamilton (she of Apollo 11, who coined the term "software engineer"). It shows a simple elegant way to make easy-to-use safe programming systems.
I just gotta say, I envy you guys. :)
> For a time, I thought I ought to be building software for the NES to ensure their survival over the influx of disposable modern platforms — So, I did. . Sadly, most of the software that I care to write and use require slightly more than an 8-button controller.
Seems to me you could have saved a lot of effort by changing gears slightly to target other ubiquitous 6502 machines such as the apple 2 or c64.
I did a few C64 test applications both in plain 6502 and via cc65(which works very poorly on ARM btw), but that didn't really work out for us. I ran into issues porting VICE to Plan 9, and I had all sorts of issues with c64 sound emulation.
Setting the content aside, when an author starts off their with with this kind of tone I'm immediately turned off.
There's no need to be so antagonistic. Jonathan Blow "said", "claimed", "discussed", or any of the infinite other neutral and non-insulting ways to refer to another person's work.
There is no such thing as "safe language".
The author has clearly never seen what real safety critical code look like.
When safety/robustness really is critical, there are ways to achieve it with high confidence, and it can be done in any language as long as the team doing it is qualified and applying stringent rules.
Of course this is time consuming and costly but luckily we've known how to do it for decades.
The kind of rules I am talking about are more stringent than most people who never worked on those fields realize.
In the most extreme case I've seen (aerospace code) the rules were : no dynamic memory allocation, no loop, no compiler. Yeah, pure hand-rolled assembly. Not for speed, for safety and predictability.
I write slow, half-assed Python scripts every single day, because “good enough” is in fact good enough for some things.
But over-extrapolating the “good enough” mindset to everything is lazy and makes computers less fun.
that said this isn't an essay about safety, it's about the emotional appeal of a sort of false simplicity that some programmers are prone to falling for and pointing out the inherent inability of a couple projects (in synecdoche for a whole shit ton of other projects) to live up to promises of that mirage.
See https://cs.stackexchange.com/questions/93798/what-is-a-safe-... for a decent overview.
The article is likely referring to memory safety.
I would agree with Jonathon Blow here that it is very common to use abstractions without there being any understanding of or even an interest to discover the underlining implementation of that abstraction.
For example, why else would the question, “Do you use multithreading in NodeJS?” be a common interview question?
It is commonly known that NodeJS “runs code asynchronously” but how often would it be that an engineer could accurately explain how this is done?
While some may find the benefit in understanding the system in which they work in completion I believe a majority is content with living with assumptions.
You can write a pure-functional RPN calculator in a handful of lines of D, you can also write D's entire implementation in D including the "low-level" aspects.
I also think the distinction between low and high level code in languages that are not built around some theoretically abstract model of execution (e.g. the lambda calculus) to be rather pointless and mostly useful only for making poor arguments.
I'm also sceptical of simplicity as an unqualified idea. I have read "simple" code with no abstractions that makes it extremely hard to read, I have read "simple" code that can be considered as such because the abstractions are actually abstractions: "Abstraction is the removal of irrelevant detail".
> Simplicity needs to be pervasive through the system, and further in the context it resides in, for one to benefit from it
This should have been the opening text of the essay.
We all want less sloppy code and less sloppy abstractions, but it's hard to do in the real world with tens of millions of developers placed under different constraints.
"I was not given time to do this correctly, I'll just use a library that adds 200mb RES but basically works for now."
The Internet Architecture Board, W3 working groups, OWASP, Open telemetry, and hundreds of other groups are working hard to standardize things so we don't have to repeat the same mistakes in a problem area. Heck even community sites like leetcode help raise awareness about sub-optimal solutions to problem spaces.
Also, the example about dynamic dispatch isn't really as persuasive as the author might think. Even if everyone benefits from these abstractions, what's the point when that abstraction is fundamentally slow on hardware in the first place, no matter how much optimization you can do? I mean, the Apple engineers have done everything they can do to optimize obj_msgSend() down to the assembly level, but you're still discouraged to use Obj-C virtual method calls in a tight loop because of performance problems. And we know in both principle and practice that languages which heavily rely on dynamic polymorphism (like Smalltalk) tends to perform much worse than languages like C/(non-OOP)C++/Rust which (usually) doesn't rely heavily on dynamic polymorphism. In these languages, when performance matters devs often use the good ol' switch statement (with enums / tagged unions / ADTs) instead to specify different kinds of behavior, since they are easier to inline for the compiler and the hardware is made to run switch statements faster than virtual calls. (Or to go even further you can just put different types of objects in separate contiguous arrays, if you are frequently iterating and querying these objects...) The problem I think for most programmers is that they don't know they can actually make these design choices in the first place, since they've learned "use virtual polymorphism to model objects" in OOP classes as a dogma that they must always adhere to, whereas a switch statement could have been better in most cases (both in terms of performance and code readability/maintainability. Virtual calls may be a good abstraction in some cases, but in most cases there are multiple abstractions competing with it that are more performant (and arguably, can actually be simpler).
The point Jon is trying to make (although maybe not that clear enough from the talk), is that we simply need better abstractions for the hardware that we have. And C/C++ doesn't really cut it for him, so that's why he's creating his own abstractions from scratch by writing a new language. He has often said that he dislikes "big ideas programming", which believes that if every programmer believes in a core "idea" of programming then everything will magically get better. He instead opts towards a more pragmatic approach to writing software, which is writing for the hardware and the design constraints we have right now. Maybe he may seem a bit grumpy from the perspective of people outside of OS/compiler/game development (since he also lets out some personal developer grievances in the talk), but I think his sentiment make sense in a big picture, that we have continuously churned out heaps of abstractions that have gone too far from the actual inner workings of the hardware, up to the point that desktop software has generally become too slow compared to the features it provides to users (Looking at you, Electron...)
In particular:
> The most significant performance issue is that all uxn implementations we have found use naïve interpretation. A typical estimation is that an interpreter is between one and two magnitudes slower than a good compiler. We instead propose the use of dynamic translation to generate native code, which should eliminate the overhead associated with interpreting instructions.
Okay, go for it. Literally nothing is stopping you from implementing an optimizing compiler for uxn bytecode.
Meanwhile, zero mention in this "analysis" of program size, or memory consumption, or the fact that uxn implementations exist even for microcontrollers. Interpreters are slow, but they're also straightforward to implement and they can be pretty dang compact, and so can the interpreted bytecode be much smaller than its translated-to-native-machine-code equivalent.
(Interpreters also don't need to be all that slow; I guess this guy's never heard of Forth? Or SQLite?)
> Writing a decent big-integer implementation ourselves requires some design which we would rather not perform, if possible. Instead, we can use a library for simulated 32-bit arithmetic. […] The resulting program takes 1.95 seconds to run in the "official" uxn implementation, or 390 times slower than native code! This amount of overhead greatly restricts what sort of computations can be done at an acceptable speed on modern computers; and using older computers would be out of the question.
Well yeah, no shit, Sherlock. Doing 32-bit arithmetic on an 8-bit machine is gonna be slow. Go try that on some Z80 or 6502 or whatever and get back to us.
And no, using older computers ain't "out of the question". There are literally uxn ports to DOS, to the Raspberry Pi Pico, to the goddamn Gameboy Advance, to all sorts of tiny constrained systems. The author would know this if one had done even the slightest bit of investigation before deciding to shit all over uxn and the folks making it.
> The uxn system could also be a sandbox, and prevent damage outside of its memory, but a filesystem device is specified for the platform, and is often implemented, and so a uxn program can destroy information outside its virtual machine. Any isolation would have to be performed outside of the virtual machine; thus running a random uxn program is as insecure as running a random native executable.
Absolutely nothing in the uxn spec suggests that the "filesystem" in question should be the host's filesystem; it could very well be some loopback device or a sandbox or what have you. If security/isolation is desired, then that's pretty trivial to implement in a way that a tiny bytecode stack machine would have a very hard time escaping. Either the author is incapable of actually reading the documentation of the thing being analyzed, or one is being blatantly intellectually dishonest.
----
Like, I don't know what the author's beef is - maybe Rek and Devine ran over the author's dog with their sailboat, or maybe the Bytecode Interpreter Mafia smashed the author's kneecaps with hammers - but the article reads more like bone-pickery than some objective analysis.
Well, for one thing, once you get to subroutine-threaded code (which is often the most efficient way to implement it on modern architectures), it's arguable whether still counts as "interpreted".
But even then, FORTH is still several times slower than equivalent native code. Which is better than most naive bytecode interpreter, but it's also why industrial FORTH compilers do native code inlining and other optimizations to reach the desired degree of performance. At which point, what's the fundamental difference with C?
They do mention disregarding uxn's default choice to optimize for size and change it instead to optimize for speed (-OS vs -O2) to give a more level comparison (for speed specifically). But it helps to show that the comparison is a bit stretched.
Perhaps the greatest of all programmers produce redundancy while depending on very little of it in their own code. For example, Richard Hipp created SQLite, the ubiquitous and amazingly high-quality embedded database, in C. Thinking about that makes me feel like I ought to be using C in my own, much more modest attempt at a reusable infrastructure project [1]. Cue the cliches about younger generations (like mine) being soft compared to our predecessors.
[1] https://github.com/AccessKit/accesskit (it's too late now, I'm committed to doing it in Rust)
Before you do that, read https://www.sqlite.org/testing.html
SQLite has a crazy amount of verification and testing. There are something like 640x the code for tests as for the actual implementation.
If you are looking to SQLite as an inspiration to write in C, you should also consider the verification and testing that makes it work.
And that’s a self-own.
A term I like to use for this phenonemon is "Inner Platform Effect".
https://en.wikipedia.org/wiki/Inner-platform_effect
The prime example is that in the 90's, Java thought they were going to make Windows irrelevant (a pile of poorly debugged device drivers or something like that).
But now Java is just Windows/Unix process.
Same with all these "alternative computing stacks" -- in the end they will almost certainly be just Unix processes.
The only situation I can think of where they wouldn't be is a revolution in hardware like the IBM PC producing MS-DOS, etc. And even not then, because we already had the mobile revolution starting ~15 years ago, and both platforms are based on Unix (iOS/Android).
----
I do think people should carefully consider whether they want to create an "inner platform" or make the platforms we ACTUALLY USE better.
That is the purpose of https://www.oilshell.org/.
Evolving working systems is harder than creating clean slates. So clean slates are fun for that reason: you get to play God without much consequence.
Sometimes clean slates introduce new ideas, and that's the best case. But a common pattern is that they are better along certain dimensions (the "pet peeves" of their creator -- small size, etc.), but they are WORSE than their predecessors along all the other dimensions!
So that is the logic of Oil being compatible and painstakingly cleaning up bash -- to not be worse than the state of the art along any dimension! I've experimented writing a clean slate shell in the past, but there are surprising number of tradeoffs, and a surprising number of things that Unix shell got right.
-----
But Oil can ALSO be viewed as a clean slate, which is sometimes hard to understand. https://www.oilshell.org/release/latest/doc/oil-language-tou...
I just drafted this doc, and surprisingly little breaks even in the non compatible mode:
What Breaks When You Upgrade to Oil https://www.oilshell.org/preview/doc/upgrade-breakage.html
So I would like to see more systems take a DUAL view -- compatible, but also envision the ideal end state, and not just pile on hacks (e.g. Linux cgroups and Docker are a prime example of this.)
You will learn the wisdom of the system that way, and the work will be more impactful. For example, it forced me to put into words what Unix (and the web) got right: https://www.oilshell.org/blog/2022/03/backlog-arch.html
I'd like to ask the author, how does he think his computer works? The hardware is rather complex and it has to work near perfectly all the time. It should be impossible according to his premise, but it's clearning happening.
You might think of a modern CPU as a black-box that goes out and finds (the lack of) dependencies in the instruction stream to exploit them, but this all has to be condensed into a logical circuit that is bounded in memory (registers), can be pipelined, and verified.
And even then with hardware you are typically verifying things like "The pipeline never locks up entirely" or "The cache never gives back memory from the wrong physical address" basic things like that whereas these same kinds of invariants in software are rarely profitable to try and verify.
David Malcolm has done a really good job with the analyser but it can't catch everything by virtue of the C type system making it possible to write code that can't be guaranteed either by construction or by making opaque boundaries.
I've watched people live coding audio software. That's a performance, like jamming or rap battling where you make music spontaneously for an audience. It's a distinct skill from being able to polish stuff in a studio, just like playing a guitar or singing live is a distinct skill, it's even distinct from working with a loop sampler (like Marc Rebillet) although it's often related.
But for a compiler, what's "live"? Somebody writes some code and you... tokenize it in real time, transform it into some intermediate representation, optimise that and then spit out machine code? No? Then it's not "live coding", you're just talking about how he got paid to stream on Twitch or whatever. Loads of people do that. Ketroc streamed his last minute strategies for the recent SC2 AI tournament, he's not even a "professional" programmer, half his audience haven't seen Java before.
Add to this that John Blow is such an exemplar of the entrepreneurial spirit that this site has basically its foundational value.
The guy worked in the rat race for awhile, saved a modest amount to self-fund building Braid. Braid smashed every record both commercially and critically for what one guy in a garage could do in games.
He took all that money, hired a few people carefully, and built The Witness, not on fucking Unity or something, but from the shaders up so that it would have a unique look and not be a clone of something else. The Witness was also a huge commercial and critical success.
His most recent project is, uh, ambitious. I don’t know if it’s going to prove feasible. But I’m sure as hell rooting for success rather than failure.
Now mostly this is directed at the auth or the post, but you’ve kind of signed up for a little of this: what the fuck is your CV?
If you work in games then you know that John Blow is by many measures the most demonstrably successful game developer without a big studio behind him, others might not.
Talking about this stuff on the Internet is a sloppy, haphazard business: deep insight rarely fits in a tweet. I don’t mind that the blog author is not only saying ridiculous things but naming-and shaming earnest, serious pros into the bargain.
I mind that so many people on this site, which I do care about, are lining up behind that bullshit.
ex gamer here (player only, no idea about the game making industry), never heard of him or any games. Is he really the most successful? From the outside i would have guessed hte most successful indy game dev, based on how much they're talked about, would be something like: dwarf fortress, minecraft, flappy birds, wordle...
If Jonathan Blow truly does believe that there are "perfect" programmers who never, ever need runtimes that do bounds checking (and other useful things)[0], then that is a huge blind spot. Maybe these unicorns exist, but they are just that: incredibly, vanishingly rare. And Blow certainly isn't one of those people; I've played both Braid and The Witness, and I've seen them both crash (in game code, not in a linked platform library). They're amazing, beautiful games, but that doesn't make their author above criticism.
> ... but you’ve kind of signed up for a little of this: what the fuck is your CV?
Valid criticism/skepticism need not turn into a dick-measuring contest. Trying to invalidate someone's opinion by asking for their credentials is logically fallacious. Please don't do this sort of thing here.
Also not sure where all the anger is coming from. Why do you feel such a personal stake in Jonathan Blow's reputation as some sort of infallible coding god?
[0] Not saying that I know for a fact that he does believe this; I'm just going by OP's article, which could easily be wrong or at least exaggerated.