Personally though, I think the distinctive choices are a boon. You are never confused about what language you are writing because Lua code is so obviously Lua. There is value in this. Once you have written enough Lua, your mind easily switches in and out of Lua mode. Javascript, on the other hand, is filled with poor semantic decisions which for me, cancel out any benefits from syntactic familiarity.
More importantly, Lua has a crucial feature that Javascript lacks: tail call optimization. There are programs that I can easily write in Lua, in spite of its syntactic verbosity, that I cannot write in Javascript because of this limitation. Perhaps this particular JS implementation has tco, but I doubt it reading the release notes.
I have learned as much from Lua as I have Forth (SmallTalk doesn't interest me) and my programming skill has increased significantly since I switched to it as my primary language. Lua is the only lightweight language that I am aware of with TCO. In my programs, I have banned the use of loops. This is a liberation that is not possible in JS or even c, where TCO cannot be relied upon.
In particular, Lua is an exceptional language for writing compilers. Compilers are inherently recursive and thus languages lacking TCO are a poor fit (even if people have been valiantly forcing that square peg through a round hole for all this time).
Having said all that, perhaps as a scripting language for Redis, JS is a better fit. For me though Lua is clearly better than JS on many different dimensions and I don't appreciate the needless denigration of Lua, especially from someone as influential as you.
Is it needless? It's useful specifically because he is someone influential, and someone might say "Lua was antirez's choice when making redis, and I trust and respect his engineering, so I'm going to keep Lua as a top contender for use in my project because of that" and him being clear on his choices and reasoning is useful in that respect. In any case where you think he has a responsibility to be careful what he says because of that influence, that can also be used in this case as a reason he should definitely explain his thoughts on it then and now.
Scheme is pretty lightweight.
And what does lightweight mean? Does it mean low memory footprint or does it mean few-lines-of-code-to-introduce or does it mean zero-dependencies?
Also look at Hedgehog Lisp. The bytecode compiler (runs on a PC) is separate from the interpreter, i.e. there is no REPL. But it means that the interpreter is only about 20KB of code. It's quite practical. It's not Scheme but rather is a functional Lisp (immutable data including AVL trees as the main lookup structure) and it is tail recursive. https://github.com/sbp/hedgehog
https://www.gnu.org/software/guile/manual/html_node/while-do...
I was asking which scheme if the 20-50 of them was "lightweight" and embeddable.
This. And not just Lua , but having different kind of syntax for scripting languages or very high level languages signal it is something entirely different, and not C as in system programming language.
The syntax is also easier for people who dont intend to make programming as their profession, but simply want something done. It used to be the case in the old days people would design simple PL for new beginners, ActionScript / Flash era and even Hypercard before that. Unfortunately the industry is no longer interested in it, and if anything intend to make every as complicated as possible.
I'm not familiar with Lua, but I expect tco to be a feature of the compiler, not of the language. Am I wrong?
> A Scheme implementation is properly tail-recursive if it supports an unbounded number of active tail calls.
The issue here is that, in every language that has a detailed enough specification, there is some provision saying that a program that makes an unbounded number of nested calls at runtime is not legal. Support for proper tail calls means that tail calls (a well-defined subgrammar of the language) do not ever count as nested, which expands the set of legal programs. That’s a language feature, not (merely) a compiler feature.
[1] https://standards.scheme.org/corrected-r5rs/r5rs-Z-H-6.html#...
I still think that the language property (or requirement, or behavior as seen by within the language itself) that we're talking about in this case is "unbounded nested calls" and that the language specs doesn't (shouldn't) assume that such property will be satisfied in a specific way, e.g. switching the call to a branch, as TCO usually means.
Otherwise yes. For instance, Scheme implementations that translate the Scheme program into portable C code (not just into bytecode interpreted by C code) cannot assume that the C compiler will translate C-level tail calls into jumps and thus take special measures to make them work correctly, from trampolines to the very confusingly named “Cheney on the M.T.A.”[1], and people will, colloquially, say those implementations do TCO too. Whether that’s correct usage... I don’t think really matters here, other than to demonstrate why the term “TCO” as encountered in the wild is a confusing one.
[1] https://www.plover.com/misc/hbaker-archive/CheneyMTA.html
I know it's not universal: some languages in their infancy lack a formalization and are defined by their reference implentation. But a more theoretical approach has allowed languages like C to strive for years.
If I have a program that based on the input given to it runs some number of recursions of a function and two compilers of the language, can I compile the program using both of them if compiler A has PTC and compiler B does not no matter what the actual program is? As in, is the only difference that you won’t get a runtime error if you exceed the max stack size?
(The usual caveats about TCO randomly not working are due to constraints imposed by preexisting ABIs or VMs; if you don’t need to care about those, then the whole thing is quite straightforward.)
A more useful way to understand the situation is that a language's major implementations are more important than the language itself. If the spec of the language says something, but nobody implements it, you can't write code against the spec. And on the flip side, if the major implementations of a language implement a feature that's not in the spec, you can write code that uses that feature.
A minor historical example of this was Python dictionaries. Maybe a decade ago, the Python spec didn't specify that dictionary keys would be retrieved in insertion order, so in theory, implementations of the Python language could do something like:
>>> abc = {}
>>> abc['a'] = 1
>>> abc['b'] = 2
>>> abc['c'] = 3
>>> abc.keys()
dict_keys(['c', 'a', 'b'])
But the CPython implementation did return all the keys in insertion order, and very few people were using anything other than the CPython implementation, so some codebases started depending on the keys being returned in insertion order without even knowing that they were depending on it. You could say that they weren't writing Python, but that seems a bit pedantic to me.In any case, Python later standardized that as a feature, so now the ambiguity is solved.
It's all very tricky though, because for example, I wrote some code a decade that used GCC's compare-and-swap extensions, and at least at that time, it didn't compile on Clang. I think you'd have a stronger argument there that I wasn't writing C--not because what I wrote wasn't standard C, but because the code I wrote didn't compile on the most commonly used C compiler. The better approach to communication in this case, I think, is to simply use phrases that communicate what you're doing: instead of saying "C", say "ANSI C", "GCC C", "Portable C", etc.--phrases that communicate what implementations of the language you're supporting. Saying you're writing "C" isn't wrong, it's just not communicating a very important detail: what implementations of the compiler can compile your code. I'm much more interested in effectively communicating what compilers can compile a piece of code than pedantically gatekeeping what's C and what's not.
After the 3.6 changed, they were returned in order. And people started relying on that - so at a later stage, this became part of the spec.
You could not reliably depend on that implementation detail until much later, when optimizations were implemented in CPython that just so happened to preserve dictionary key insertion order. Once that was realized, it was PEP'd and made part of the spec.
I'm saying it isn't very useful argue about whether a feature is a feature of the language or a feature of the implementation, because the language is pretty useless independent of its implementation(s).
C's "register" variables used to have the same issue, and even "inline" has been downgraded to a mere hint for the compiler (which can ignore it and still be a C compiler).
I'd love to hear more how it is, the state of the library ecosystem, language evolution (wasn't there a new major version recently?), pros/cons, reasons to use it compared to other languages.
About tail-calls, in other languages I've found sometimes a conversion of recursive algorithm to a flat iterative loop with stack/queue to be effective. But it can be a pain, less elegant or intuitive than TCO.
It's definitely smaller than many languages, and this is something to consider before selecting Lua for a project. But, on the positive side: With some 'other' languages I might find 5 or 10 libraries all doing more or less the same thing, many of them bloated and over-engineered. But with Lua I would often find just one library available, and it would be small and clean enough that I could easily read through its source code and know exactly how it worked.
Another nice thing about Lua when run on LuaJIT: extremely high CPU performance for a scripting language.
In summary: A better choice than it might appear at first, but with trade-offs which need serious consideration.
Also worth noting that some features in JS may rely on application/environment support and may raise errors that you cannot catch in JS code. This is often fun to discover and painful to try to work around.
Does the language give any guarantee that TCO was applied? In other words can it give you an error that the recursion is not of tail call form? Because I imagine a probability of writing a recursion and relying on it being TCO-optimized, where it's not. I would prefer if a language had some form of explicit TCO modifier for a function. Is there any language that has this?
return 1 + f()
?
https://github.com/ablevm/able-forth/blob/current/forth.scr
I do prefer this as it keeps the language more regular (fewer surprises)
v8 had PTC, but removed it because they insisted it MUST have a new tail call keyword. When they were shot down, they threw a childish fit and removed the PTC from their JIT.
> [...] In my programs, I have banned the use of loops. This is a liberation that is not possible in JS or even c, where TCO cannot be relied upon.
This is not a great language feature, IMO. There are two ways to go here:
1. You can go the Python way, and have no TCO, not ever. Guido van Rossum's reasoning on this is outlined here[1] and here[2], but the high level summary is that TCO makes it impossible to provide acceptably-clear tracebacks.
2. You can go the Chicken Scheme way, and do TCO, and ALSO do CPS conversion, which makes EVERY call into a tail call, without language user having to restructure their code to make sure their recursion happens at the tail.
Either of these approaches has its upsides and downsides, but TCO WITHOUT CPS conversion gives you the worst of both worlds. The only upside is that you can write most of your loops as recursion, but as van Rossum points out, most cases that can be handled with tail recursion, can AND SHOULD be handled with higher-order functions. This is just a much cleaner way to do it in most cases.
And the downsides to TCO without CPS conversion are:
1. Poor tracebacks.
2. Having to restructure your code awkwardly to make recursive calls into tail calls.
3. Easy to make a tail call into not a tail call, resulting in stack overflows.
I'll also add that the main reason recursion is preferable to looping is that it enables all sorts of formal verification. There's some tooling around formal verification for Scheme, but the benefits to eliminating loops are felt most in static, strongly typed languages like Haskell or OCaml. As far as I know Lua has no mature tooling whatsoever that benefits from preferring recursion over looping. It may be that the author of the post I am responding to finds recursion more intuitive than looping, but my experience contains no evidence that recursion is inherently more intuitive than looping: which is more intuitive appears to me to be entirely a function of the programmer's past experience.
In short, treating TCO without CPS conversion as a killer feature seems to me to be a fetishization of functional programming without understanding why functional programming is effective, embracing the madness with none of the method.
EDIT: To point out a weakness to my own argument: there are a bunch of functional programming language implementations that implement TCO without CPS conversion. I'd counter by saying that this is a function of when they were implemented/standardized. Requiring CPS conversion in the Scheme standard would pretty clearly make Scheme an easier to use language, but it would be unreasonable in 2025 to require CPS conversion because so many Scheme implementations don't have it and don't have the resources to implement it.
EDIT 2: I didn't mean for this post to come across as negative on Lua: I love Lua, and in my hobby language interpreter I've been writing, I have spent countless hours implementing ideas I got from Lua. Lua has many strengths--TCO just isn't one of them. When I'm writing Scheme and can't use a higher-order function, I use TCO. When I'm writing Lua and can't use a higher order function, I use loops. And in both languages I'd prefer to use a higher order function.
[1] https://neopythonic.blogspot.com/2009/04/tail-recursion-elim...
[2] https://neopythonic.blogspot.com/2009/04/final-words-on-tail...
I don't know why Lua implemented TCO, but if I had to guess, it's not because it enables you to replace loops with recursion, it's because it... optimizes tail calls. It causes tail calls to use less memory, and this is particularly effective in Lua's implementation because it reuses the stack memory that was just used by the parent call, meaning it uses memory which is already in the processor's cache.
The thing is, a loop is still going to be slightly faster than TCOed recursion, because you don't need to move the arguments to the tail call function into the previous stack frame. In a loop your counters and whatnot are just always using the same memory location, no copying needed.
Where TCO really shines is in all the tail calls that aren't replacements for loops: an optimized tail call is faster than a non-optimized tail call. And in real world applications, a lot of your calls are tail calls!
I don't necessarily love the feature, for the reasons that I detailed in the previous post. But it's not a terrible problem, and I think it at makes sense as an optimization within the context of Lua's design goals of being lightweight and fast.
Rather, you no longer see what they're doing clearly.
Some highly recursive programming styles are really just using the call stack as a data structure... which is valid but can be restrictive.
I scrolled most of this sub thread and gp seem to not be replying to any of the replies they got.
I'm fairly certain antirez is the author of redis
Do you really need to write compilers with limitless nesting? Or is nesting, say, 100.000 deep enough, perhaps?
Also, you'll usually want to allocate some data structure to create an AST for each level. So that means you'll have some finite limit anyway. And that limit is a lot easier to hit in the real world, as it applies not just to nesting depth, but to the entire size of your compilation unit.
Lua was first released in 1993. I think that it's pretty conventional for the time, though yeah it did not follow Algol syntax but Pascal's and Ada's (which were more popular in Brazil at the time than C, which is why that is the case)!
Ruby, which appeared just 2 years later, departs a lot more, arguably without good reasons either? Perl, which is 5 years older and was very popular at the time, is much more "different" than Lua from what we now consider mainstream.
Perl, Python, OCaml, Lua and Rust were all fine (Rust wasn't around in 2010 of course).
But since syck uses the ruby hashtable internally, I got stuck in the gem for a while. It fell out of their stdlib, and is not really maintained neither. PHP had the latest updates for it. And perl (me) extended it to be more recursion safe, and added more policies (what to do on duplicate keys: skip or overwrite).
So the ruby bindings are troublesome because of its GC, which with threading requires now7 a global vm instance. And using the ruby alloc/free pairs.
PHP, perl, python, Lua, IO, cocoa, all no problem. Just ruby, because of its too tight coupling. Looks I have to decouple it finally from ruby.
I doubt we ever would have heard about Ruby without it's syntax decisions. From my understanding it's entire raison d'être was readability.
def ruby(is)
it = is
a = "bad"
example()
begin
it["had"] = pascal(:like)
rescue
flow
end
endNow quite sure what you mean by that; all of Lua, Pascal, and Ada follow Algol's syntax much more closely than C does.
People go through all this effort to separate parsing and lexing, but never exploit the ability to just plug in a different lexer that allows for e.g. "{" and "}" tokens instead of "then" and "end", or vice versa.
1. <https://hn.algolia.com/?type=comment&prefix=true&query=cxr%2...>
2. <https://old.reddit.com/r/Oberon/comments/1pcmw8n/is_this_sac...>
The problem with "skins" is that they create variety where people strive for uniformity to lower the cognitive load. OTOH transparent switching between skins (about as easy as changing the tab sizes) would alleviate that.
That's one of my hopes for the future of the industry: people will be able to just choose the code style and even syntax family (which you're calling skin) they prefer when editing code, and it will be saved in whatever is the "default" for the language (or even something like the Unison Language: store the AST directly which allows cool stuff like de-duplicating definitions and content-addressable code - an idea I first found out on the amazing talk by Joe Armstrong, "The mess we're in" [1]).
Rust, in particular, would perhaps benefit a lot given how a lot of people hate its syntax... but also Lua for people who just can't stand the Pascal-like syntax and really need their C-like braces to be happy.
Some languages have tools for more or less straightforward skinning.
Clojure to Tamil: https://github.com/echeran/clj-thamil/blob/master/src/clj_th...
C++ to distorted Russian: https://sizeof.livejournal.com/23169.html
One of my pet "not today but some day" project ideas. In my case, I wanted to give Python/Gdscript syntax to any & all the curly languages (a potential boon to all users of non-Anglo keyboard layouts), one by one, via VSCode extension that implements a virtual filesystem over the real one which translates back & forth the syntaxes during the load/edit/save cycle. Then the whole live LSP background running for the underlying real source files and resurfacing that in the same extension with line-number matchings etc.
Anyone, please steal this idea and run with it, I'm too short on time for it for now =)
Neo makes it really easy to type those
The idea of "skins" is apparently to push that even further by abstracting the concrete syntax.
This has limits.
Files produced with tab=2 and others with tab=8, might have quite different result regarding nesting.
(pain is still on the menu)
More than that, in the general case for common C like languages things should almost never be nested more than a few levels deep. That's usually a sign of poorly designed and difficult to maintain code.
Lisps are a notable exception here, but due to limitations (arguably poor design) with how the most common editors handle lines that contain a mix of tabs and spaces you're pretty much forced to use only spaces when writing in that family of languages. If anything that language family serves as case in point - code written with an indentation width that isn't to one's preference becomes much more tedious to adapt due to alternating levels of alignment and indentation all being encoded as spaces (ie loss of information which automated tools could otherwise use).
All that being said, I've very much a "as long as everyone working on the code does it the same, I'll be fine" sort of person. We use spaces for everything, with defined indent levels, where I am, and it works just fine.
Unfortunately the discussion tends to be somewhat complicated by the occasional (usually automated) code formatting convention that (imo mistakenly) attempts to change the level of indentation in scenarios where you might reasonably want to align an element with the preceding line. For example, IDEs for C like languages that will add an additional tab when splitting function arguments across multiple lines. Fortunately such cases are easily resolved but their mere existence lends itself to objections.
I see this argument a lot with Lua. People simply don't like its syntax because we live in a world where C style syntax is more common, and the departure from that seem unnecessary. So going "well actually, in 1992 when Lua was made, C style syntax was more unfamiliar" won't help, because in the current year, C syntax is more familiar.
The first language I learned was Lua, and because of that it seems to have a special place in my heart or something. The reason for this is because in around 2006, the sandbox game "Garry's Mod" was extended with scripting support and chose Lua for seemingly the same reasons as Redis.
The game's author famously didn't like Lua, its unfamiliarity, its syntax, etc. He even modified it to add C style comments and operators. His new sandbox game "s&box" is based on C#, which is the language closest to his heart I think.
The point I'm trying to make is just that Lua is familiar to me and not to you for seemingly no objective reason. Had Garry chosen a different language, I would likely have a different favorite language, and Lua would feel unfamiliar and strange to me.
I haven't read antirez'/redis' opinions about Lua, so I'm just going off of his post.
In contrast I do know more about what Garry's opinion on Lua is as I've read his thoughts on it over many years. It ultimately boils down to what antirez said. He just doesn't like it, it's too unfamiliar for seemingly no intentional reason.
But Lua is very much an intentionally designed language, driven in cathedral-style development by a bunch of professors who seem to obsess about language design. Some people like it, some people don't, but over 15 years of talking about Lua to other developers, "I don't like the syntax" is ultimately the fundamental reason I hear from developers.
So my main point is that it just feels arbitrary. I'm confident the main reason I like Lua is because garry's mod chose to implement it. Had it been "MicroQuickJS", Lua would likely feel unfamiliar to me as well.
I’m not sure it’s still the case but he modified Lua to be zero indexed and some other tweaks because they annoyed him so much, so it’s possible if you learned GMod Lua you learned Garry’s Lua.
Of course his heart has been with C# for many years now.
For example Premake[1] uses Lua as it is - without custom syntax parser but with set of domain specific functions.
This is pure Lua:
workspace "MyWorkspace"
configurations { "Debug", "Release" }
project "MyProject"
kind "ConsoleApp"
language "C++"
files { "**.h", "**.cpp" }
filter { "configurations:Debug" }
defines { "DEBUG" }
symbols "On"
filter { "configurations:Release" }
defines { "NDEBUG" }
optimize "On"
In that sense Premake looks significantly better than CMake with its esoteric constructs.
Having regular and robust PL to implement those 10% of configuration cases that cannot be defined with "standard" declarations is the way to go, IMO.Come to think of it I don't think I can name a single mainstream language other than Lua that wasn't invented in the G7.
So, even if an implementation like MicroQuickJS existed in 2010, it's unlikely that too many people would have chosen JS over Lua, given all the shortcomings that JavaScript had at the time.
Lately, yes, Julia and R.
Lots of systems I grew up with were 1-indexed and there's nothing wrong with it. In the context of history, C is the anomaly.
I learned the Wirth languages first (and then later did a lot of programming in MOO, a prototype OO 1-indexed scripting language). Because of that early experience I still slip up and make off by 1 errors occasionally w/ 0 indexed languages.
(Actually both Modula-2 and Ada aren't strictly 1 indexed since you can redefine the indexing range.)
It's funny how orthodoxies grow.
There are only a few languages that are purely for beginners (LOGO and BASIC?) so it's a high cost to annoy experienced programmers for something that probably isn't a big deal anyway.
Thus, 1 probably wasn't "easier", it just adhered to an existing orthodoxy that "beginners" came from at the time.
The problem is that Lua is effectively an embedded language for C.
If Lua never interacted with C, 1-based indexing would merely be a weird quirk. Because you are constantly shifting across the C/Lua barrier, 1-based indices becomes a disaster.
If anything, the only significant change is that the community is becoming more and more convinced that offset array support is a bit of a footgun and makes it easy for bugs to sneak into generic code.
[Documents]$ cat test.js
let testArray = [];
testArray[0] = "foo";
testArray["0"] = "bar";
console.log(testArray[0]);
console.log(testArray["0"]);
[Documents]$ jsc test.js
bar bar
[Documents]$ function f1() end
function f2() end
local m1 = {}
local m2 = {}
local obj = {
[f1] = 1,
[f2] = 2,
[m1] = 3,
[m2] = 4,
}
print(obj[f1], obj[f2], obj[m1], obj[m2], obj[{}])
Functions as keys is handy when implementing a quick pub/sub.[edit]
let testArray = [];
testArray[0] = "foo";
testArray["0"] = "bar";
testArray["00"] = "baz";
console.log(testArray[0]);
console.log(testArray["0"]);
console.log(testArray["00"]);- Every property access in JavaScript is semantically coerced to a string (or a symbol, as of ES6). All property keys are semantically either strings or symbols.
- Property names that are the ToString() of a 31-bit unsigned integer are considered indexes for the purposes of the following two behaviours:
- For arrays, indexes are the elements of the array. They’re the properties that can affect its `length` and are acted on by array methods.
- Indexes are ordered in numeric order before other properties. Other properties are in creation order. (In some even nicher cases, property order is implementation-defined.)
{ let a = {}; a['1'] = 5; a['0'] = 6; Object.keys(a) }
// ['0', '1']
{ let a = {}; a['1'] = 5; a['00'] = 6; Object.keys(a) }
// ['1', '00']What you say is true for languages that don't have collections, real arrays, or vectors, only memory ranges. This is the case of C, but not Fortran, Pascal, or Ada. So yeah, if all you have is a hammer, you'd better use 0-based nails; hopefully, though, we'll allow for non-hammer tools in popular toolboxes sometime this century.
For those not familiar with TCL, the C API is flavoured like main. Callbacks take a list of strings argv style and an argc count. TCL is stringly typed which sounds bad, but the data comes from strings in the HTML and script blocks, and the page HTML is also text, so it fits nicely and the C callbacks are easy to write.
[1] Mosaic Netscape 0.9 was released the week before
The Redis test suite is still written in Tcl: https://news.ycombinator.com/item?id=9963162 (although more recently antirez said somewhere he wished he'd written it in C for speed)
This would have been a catastrophic loss. Lua is better than javascript in every single way except for ordinal indexing
Initially I agreed, just because so many other languages do it that way.
But if you ignore that and clean slate it, IMO, 1 based makes more sense. I feel like 0 based mainly gained foothold because of C's bastardization of arrays vs pointers and associated tricks. But most other languages don't even support that.
You can only see :len(x)-1 so many times before you realize how ridiculous it is.
Having written a game in it (via LÖVE), the 1-indexing was a continued source of problems. On the other hand, I rarely need to use len-1, especially since most languages expose more readable methods such as `last()`.
What does bug me is that Lua, the language, is 1-based, but its C api is not.
Thank god it wasn’t then.
I did once manage to compile Lua 5.4 on a Macintosh SE with 4MB of RAM, and THINK C 5.0 (circa 1991), which was a sick trick. Unfortunately, it took about 30 seconds for the VM to fully initialize, and it couldn't play well with the classic MacOS MMU-less handle-based memory management scheme.
it also helps that it has ridiculously high performance for a scripting language
Frankly, I welcome the fact that Redis doesn’t use JavaScript. It’s an abomination of a language. The fewer times I need to use it the better.
I was criticising a thing not a person.
Also your comment implies it was ok to be critical of a language 10 years ago but not ok today because a few more language designers might get offended. Which is a weird argument to make.
Let's talk specifics. As it seems you have strong opinions, in your opinion what is the single worst aspect of JavaScript that justifies the use of the word "ugly"?
https://www.reddit.com/r/learnjavascript/comments/qdmzio/dif...
or anything that touches array ops (concatenating, map, etc…). I mean, better and more knowledgeable people than me have written thousands of articles about those footguns and many more.
I am not a webdev, I don't want to remember those things, but more often than I would wish, I have to interop with JS, and then I'd rather use a better behaved language that compiles down to JS (there are many very good ones, nowadays) than deal with JS directly, and pray for the best.
OTOH I think JS has great ergonomics especially wrt closures which a number of popular languages get wrong. Arrow functions provide a syntactically pleasant way to write lambdas, let/const having per iteration binding in loops to avoid nasty surprises when capturing variables, and a good number of standard methods that exploit them (eg map/filter on arrays). I also think, though a lot of people would disagree because of function coloring, that built-in async is a great boon for a scripting languages, you can do long operations like IO without having to worry about threading or locking up a thread, so you get to work with a single threaded mental model with a good few sharp edges removed.
> I am not a webdev, I don't want to remember those things, (...)
Not only is JavaScript way more than a webdev thing, you are ignoring the fact that most of the mainstream programming languages also support things like automatic type conversion.
You seem so emotionally-involved that the whole point whooshed above your head. JS is a language that gives me no joy to use (there are many of those, I can put Fortran or SQL in there), and, remarkably, gives me no confidence that whatever I write with it does what I intend (down to basic branching with checking for nulliness/undefinedness, checking for edge-cases, etc). In that sense it's much worse than most of those languages that I just dislike.
> Not only is JavaScript way more than a webdev thing, you are ignoring the fact that most of the mainstream programming languages also support things like automatic type conversion.
Again, you are missing the point. JS simply has no alternative for webdev, but it's easy to argue that, for everything else, there are better, faster, more expressive, more robust, … languages out there. The only time I ever have to touch JS is consequently for webdev.
Lua is a pretty old language. In 1993 the world had not really settled on C style syntax. Compared to Perl or Tcl, Lua's syntax seems rather conventional.
Some design decisions might be a bit unusual, but overall the language feels very consistent and predictable. JS is a mess in comparison.
> because it departs from a more Algol-like syntax
Huh? Lua's syntax is actually very Algol-like since it uses keywords to delimit blocks (e.g. if ... then ... end)
But only after long time I tried to check what Algol actually looked like. To my surprise, Algol does not look anything like C to me.
I would be quite interested in the expanded version of “C has inherited syntax from Algol”
Edit: apparently the inheritance from Algol is a formula: lexical scoping + value returning functions (expression based) - parenthesitis. Only last item is about visual part of the syntax.
Algol alternatives were: cobol, fortan, lisp, apl.
Of course, C also inherited syntax from Algol, but so did most languages.
That's what matters to me, not how similar Lua is to other languages, but that the language is well-designed in its own system of rules and conventions. It makes sense, every part of it contributes to a harmonious whole. JavaScript on the other hand.
When speaking of Algol or C-style syntax, it makes me imagine a "Common C" syntax, like taking the best, or the least common denominator, of all C-like languages. A minimal subset that fits in your head, instead of what modern C is turning out to be, not to mention C++ or Rust.
They did add some optional sections like bounds checking that seem to have flopped, partly for being optional, partly for being half-baked. Having optional sections in general seems like a bad idea.
https://en.wikipedia.org/wiki/C99
C++ by comparison it's a behemoth. If C++ died and, for instance, the FLTK guys rebased their libraries into C (and Boost for instance) it would be a big loss at first but Chromium and the like rewritten in C would slim down a bit, the complexity would plummet down and similar projects would use far less CPU and RAM.
It's not just about the binary size; C++ today makes even the Common Lisp standard (even with UIOP and some de facto standard libraries from QuickLisp) pretty much human-manageable, and CL always has been a one-thousand pages thick standard with tons of bloat compared to Scheme or it's sibling Emacs Lisp. Go figure.
Also, the Limbo language it's basically pre-Go.
https://en.wikipedia.org/wiki/Alef_(programming_language)
https://en.wikipedia.org/wiki/Limbo_(programming_language)
https://en.wikipedia.org/wiki/Newsqueak
https://en.wikipedia.org/wiki/Communicating_sequential_proce...
https://doc.cat-v.org/bell_labs/new_c_compilers/new_c_compil...
It was amalgamated at Google.
Originally Go used the Ken C compilers for Plan9. It still uses CSP. The syntax it's from Limbo/Inferno, and probably the GC came from Limbo too.
If any, Golang was created for Google by reusing a big chunk of plan9 and Inferno's design, in some cases even straightly, as it shows with the concurrency model. Or the cross-compiling suite.
A bit like MacOS X under Apple. We all know it wasn't born in a vacuum. It borrowed Mach, the NeXTStep API and the FreeBSD userland and they put the Carbon API on top for compatibility.
Before that, the classic MacOS had nothing to do with Unix, C, Objective C, NeXT or the Mach kernel.
Mac OS X is to NeXT what Go is for Alef/Inferno/Plan9 C. As every MacOS user it's using something like NeXTStep with the Macintosh UI design for the 21th century, Go users are like using a similar, futuristic version of the Limbo/Alef programming languages with a bit of the Plan9 concurrency and automatic crosscompilation.
Go was created at Google, for Google, by Google employees. They looked at how Google was using C++ at that time, sat down, and created a new language that would suit that task more. Here's an article of what and how by Rob Pike https://commandcenter.blogspot.com/2012/06/less-is-exponenti...
It's as much of a Google project as anything can be. "C++ is a katamari ball of programming trends and half baked ideas. I get why google built golang, as they were already pretty strict about what parts of the c++ sediments you were allowed to use." is entirely correct regarding history.
https://lists.wikimedia.org/hyperkitty/list/wikitech-l@lists...
Good to see you alive and kicking. Happy holidays
[0] https://redbean.dev/ - the single-file distributable web server built with Cosmopolitan as an αcτµαlly pδrταblε εxεcµταblε
I had Claude Code for web figure out how to run this in a bunch of different ways this morning - I have working prototypes of calling it as a Python FFI library (via ctypes), as a Python compiled module and compiled to WebAssembly and called from Deno and Node.js and Pyodide and Wasmtime https://github.com/simonw/research/blob/main/mquickjs-sandbo...
PR and prompt I used here: https://github.com/simonw/research/pull/50 - using this pattern: https://simonwillison.net/2025/Nov/6/async-code-research/
No matter how much you hate LLM stuff I think it's useful to know that there's a working proof of concept of this library compiled to WASM and working as a Python library.
I didn't plan to share this on HN but then MicroQuickJS showed up on the homepage so I figured people might find it useful.
(If I hadn't disclosed I'd used Claude for this I imagine I wouldn't have had any down-votes here.)
Your github research/ links are an interesting case of this. On one hand, late AI adopters may appreciate your example prompts and outputs. But it feels like trivially reproducible noise to expert LLM users, especially if they are unaware of your reputation for substantive work.
The HN AI pushback then drowns out your true message in favor of squashing perceived AI fluff.
My simonw/research GitHub repo is deliberately separate from everything else I do because it's entirely AI-generated. I wrote about that here: https://simonwillison.net/2025/Nov/6/async-code-research/#th...
This particular case is a very solid use-case for that approach though. There are a ton of important questions to answer: can it run in WebAssembly? What's the difference to regular JavaScript? Is it safe to use as a sandbox against attacks like the regex thing?
Those questions can be answered by having Claude Code crunch along, produce and execute a couple of dozen files of code and report back on the results.
I think the knee-jerk reaction pushing back against this is understandable. I'd encourage people not to miss out on the substance.
If someone wants to read your blog, they will, they know it exists, and some people even submit your new articles here. There's no need to do what you're doing. Every day you're irritating more people with this behavior, and eventually the substance won't matter to them anymore, so you're acting against your own interests.
Unless you want people to develop the same kind of ad blindness mechanism, where they automatically skip anything that looks like self promotion. Some people will just see a comment by simonw and do the same.
A lot of people have told you this in many threads, but it seems you still don’t get it.
You're not pushing against an arbitrary taboo where people dislike self links in principle. People already accept self links on HN when they're occasional and clearly relevant. What people are reacting to is the pattern when "my answer is a link to my site" becomes your default state, it stops reading like helpful reference and starts reading like your distribution strategy.
And that's why "I'm determined to normalize it" probably won't work because you can't normalize your way out of other people's experience of friction. If your behavior reliably adds a speed bump to reading threads forcing people to context switch/click out and wonder if they're being marketed to then the community will develop a shortcut I mentioned in my previous comment which basically is : this is self promo so just ignore.
If your goal is genuinely to share useful ideas, you're better off meeting people where they are: put the relevant 2-6 sentences directly in the comment, and then add something like "I wrote more about it on my blog" or whatever and if anyone is interested they will scroll through your blog (you have it in your profile so anyone can find it with one click) or ask for a link.
Otherwise you're not "normalizing" anything, you're training readers to stop paying attention to you. And I assure you once that happens, it's hard to undo, because people won't relitigate your intent every time. They'll just scroll. It's a process that's already started, but you can still reverse it.
I'm actively pushing back against the "don't promote your site, don't link to it, restate your content in the comments instead" thing.
I am willing to take on risk to my personal reputation and credibility in support of my goal here.
If everyone starts dropping their "relevant content" in the comments, most of it won't be relevant, and a lot of it will be spam. People don't have time to sift through hundreds of links in the comments and tens of thousands of words when the whole point of HN is that discussion and curation work in the opposite direction.
If your content is good, someone else will submit it as a story. Your blog is probably already read by thousands of people from HN, if they think a particular post belongs in the discussion in some comment, they'll link it. That's why other popular HN users who blog don't constantly promote or link their own content here, unlike you. They know that you don't need to do it yourself, and doing it repeatedly sends the wrong signal (which is obvious and plenty of socially aware people have already pointed out to you in multiple threads).
Trying to normalize that kind of self promoting is like normalizing an annoying mosquito buzz, most people simply don't want it and no amount of "normalizing" will change that.
The difference between LinkedIn slop and good content is not the presence or absence of a link to one’s own writing, but the substance and quality of the writing.
If simonw followed these rules you want him to follow, he would be forced to make obscure references to a blog post that I would then need to Google or hope that his blog post surfaces on HN in the next few days. It seems terribly inefficient.
I agree with you that self-promotion is off-putting, and when people post their competing project on a Show HN post, I don’t click those links. But it’s not because they are linking to something they wrote. It’s because they are engaged in “self-promotion”, usually in an attempt to ride someone else’s coattails or directly compete.
If simonw plugged datasette every chance he got, I’d be rolling my eyes too, but linking to his related experiments and demos isn’t that.
I'd chalk up the -4 to generic LLM hate, but I find examples of where LLMs do well to be useful, so I appreciated your post. It displays curiosity, and is especially defensible given your site has no ads, loads blazingly fast, and is filled with HN-relevant content, and doesn't even attempt to sell anything.
You can safely assume so. Bellard is the creator of jslinux. The news here would be if it _didn't_.
> What's the difference to regular JavaScript?
It's in the project's README!
> Is it safe to use as a sandbox against attacks like the regex thing?
This is not a sandbox design. It's a resource-constrained design like cesanta/mjs.
---
If you vibe coded a microcontroller emulation demo, perhaps there would be less pushback.
In this particular case AI has nothing to do with Fabrice Bellard.
We can have something different on HN like what Fabrice Bellard is up to.
You can continue AI posting as normal in the coming days.
... and that it provides a useful sandbox in that you can robustly limit both the memory and time allowed, including limiting expensive regular expression evaluation?
I included the AI bit because it would have been dishonest not to disclose how I used AI to figure this all out.
Compiling this to wasm and calling it from python as a sandboxed runtime isn’t tangential. I wouldn’t have know from reading the project’s readme that this was possible, and it’s a really interesting use case. We might as well get mad at simonw for using an IDE while he explored the limits of a new library.
My issue is that the cost, in terms of time, for these experiments have really gone down with LLMs. Earlier, if someone played around with the posted project, we knew they spent a reasonable amount of time on it, and thus care about the subject. With LLMs, this is not the case.
Maybe we HN users have minds in sync :)
https://news.ycombinator.com/item?id=46359396#46359695
Have a nice day! Awesome stuff, would keep an eye on your blog, Does your blog/website use mataroa by any chance as there are some similarities even if they are both minimalist but overall nice!
Maybe someone finds it useful: https://paste.ubuntu.com/p/rD6Dz7hN2V/
Thanks a lot for checking out my blog/project. Have a great day!
I'm currently on a multi-year side-quest to find safe ways to execute untrusted user-provided code in my Python and web applications.
As such, I pay very close attention to any new language or library that looks like it might be able to provide a robust sandbox.
MicroQuickJS instantly struck me as a strong candidate for that, and initial protoyping has backed that up.
None of that was clear from my original comment.
https://github.com/libriscv/libriscv (I talked with the author of this project, amazing author fwsgonzo is amazing) and they told me that this has the least latency out of any sandbox at only minor consequence of performance that they know of
Btw for sandboxing, kvm itself feels good too and I had discussed it with them in their discord server when they had mentioned that they were working on a minimal kvm server which has since been open sourced (https://github.com/varnish/tinykvm)
Honestly Simon, Deno hosting/the way deno works is another good interesting tidbit for sandboxing. I wish something like deno's sandboxing capabilities came to python perhaps since python fans can appreciate it.
I will try to look more into your github repository too once I get more free.
Unfortunately it means those languages will be the permanent coding platforms.
not really,
I suspect training volume has a role in debugging a certain class of errors, so there is an advantage to python/ts/sql in those circumstances: if, as an old boss once told me, you code by the bug method :)
The real problems I've had that hint at training data vs logic have been with poorly documented old versions of current languages.
To me, the most amazing capability is not the code they generate but the facility for natural language analysis.
my experience is that agent tools enable polyglot systems because we can now use the right tool for the job, not just the most familiar.
I read this post of yours https://simonwillison.net/2025/Dec/18/code-proven-to-work/ and although there is a point that can be made that what you are doing isn't a job and I myself create prototypes of code using AI, long term (in my opinion) what really matters are the maintainance and claim (like your article says in a way, that I can pin point a person whose responsible for code to work)
If I find any bug right now, I wouldn't blame it on you but AI and I have varying amount of trust on it
My opinion on the matter is that for prototyping AI can be considered good use but long term it definitely isn't and I am sure that you share a similar viewpoint.
I think that AI is so contrasting that there stops existing any nuance. Read my recent comment (although warning, its long) (https://news.ycombinator.com/item?id=46359684)
Perhaps you can build a blog post about the nuance of AI? I imagine that a lot of people might share a similar aspect of AI policy where its okay to tinker with it. I am part of the new generation and trust be told I don't think that there becomes much incentives long term unless someone realizes things of not using AI because using AI just feels so lucrative for especially the youngsters.
I am 17 years old and I am going to go into a decent college with (might I add immense competition to begin with) when I have passion about such topics but only to get dissuaded because the benchmark of solving assignments etc. are done by AI and the signal ratio of universities themselves are reducing but they haven't reduced to the point that they are irrelevant but rather that you need to have a university to try to get a job but companies have either freezed hiring which some point out with LLM's
If you ask me, Long term to me it feels like more people might associate themselves with hobbyist computing and even using AI (to be honest sort of like pewdiepie) without being in the industry.
I am not sure what the future holds for me (or for any of us as a matter of fact) but I guess the point I am trying to state is that there is nuance to the discussion from both sides
Have a nice day!
I would guess people don't know how you expect them to evaluate this, so it comes off as spamming us with a bunch of AI slop.
(That C can be compiled to WASM or wrapped as a python library isn't really something that needs a proof-of-concept, so again it could be understood as an excuse to spam us with AI slop.)
If you care that much, write a blog post and post that, we don't need low effort LLM show and tell all day everyday.
A lot of HN people got cut by AI in one way or another, so they seem to have personal beefs with AI. I am talking about not only job shortages but also general humbling of the bloated egos.
I'm gonna give you the benefit for the doubt here. Most of us do not dislike genAI because we were fired or "humbled". Most of us dislike it because a) the terrible environmental impacts, b) the terrible economic impacts, and c) the general non-production-readiness of results once you get past common, well-solved problems
Your stated understanding comes off a little bit like "they just don't like it because they're jealous".
Especially so when it concerns AI theft of human music and visual art.
"Those pompous artists, who do they think they are? We'll rob them of their egos".
The problem is that these ego-accusations don't quite come from egoless entities.
AI brings clarity. This results in a lot of pain for those who tried to hijack the game in one way or another.
From the psychological point of view, AI is a mirror of one's personality. Depending on who you are, you see different reflections: someone sees a threat, others see the enlightenment.
Do you mean that kind of clarity when no audio/video evidence is a proof of anything anymore?
> This results in a lot of pain for those who tried to hijack the game in one way or another.
I'm not quite sure if any artists, designers, musicians and programmers whose work was used to train AI without their consent tried to manipulate anyone or hijack anything. Care to elaborate?
Programmers willingly put their projects to the open source, and it's their consent by default unless there is a prohibitive license that explicitly denies AI training.
Artists, designers, musicians - I agree here, but this is the point where inflated egos usually enter the room.
When was the last time you have heard a song without autotune? If it was a machine all along for the last 20 years, why we should care now? Why we should care if 99% of artists do not care about us by pushing subpar materials down to our throats to "make it" (for them, of course)?
AI rebalances those asymmetries by bringing them to ground 0. Some people consider it as destruction, but some see a breeding ground for the future.
Right now, 2025-12-25, 09:00 UTC, I'm listening to a song without autotune.
Everything But The Girl - Missing (Todd Terry remix)
And I can also find thousands of songs without autotune that were released on Spotify yesterday. Seek and thou shall find.
Also it's not clear how autotune is related to ego. No one pretends that autotune makes one a singer. It's but an effect, and quite artsy on its own when used properly. Does compressor relate to it too? Delay? Reverb?
"This song has too much ego, the reverb is 6dB louder than the dry signal"...
How does a sheer number of subpar artists caring only about money (which is of course a thing, but nowhere near a 99% thing, and maybe a problem for those who are too lazy to discern and search themselves) justify robbing truly sincere artists who share their soul with the listener?
Update - added that here: https://github.com/simonw/research/pull/53
(Keep posting please. Downvotes due to mentioning LLMs will be perceived as a quaint historic artifact in the not so distant future…)
Just having a WebAssembly engine available isn't enough for this - something has to take that user-provided string of JavaScript and execute it within a safe sandbox.
Generally that means you need a JavaScript interpreter that has itself been compiled to WebAssembly. I've experimented with QuickJS itself for that in the past - demo here: https://tools.simonwillison.net/quickjs - but MicroQuickJS may be interesting as a smaller alternative.
If there's a better option than that I'd love to hear about it!
One catch: the sandboxing feature isn't in the "community edition", so only available under the non-open-source (but still sometimes free, I think?) Oracle GraalVM.
The web is littered with libraries that half do that and then have a note in the README that says "do not rely on this as a secure sandbox".
It's a little less clear how you would do this from node, but the v8 embedding instructions should work https://v8.dev/docs/embed even if nodejs is already a copy of v8.
[0]: https://github.com/cloudflare/stpyv8 [1]: https://docs.pythonmonkey.io
I'd seen PyV8 and ruled it out as very unmaintained.
One of my requirements for a sandbox is that it needs to me maintained by a team of professionals who are running a multi-million dollar business on it. Cloudflare certainly count! I wonder what they use STPyV8 for themselves?
... on closer inspection it doesn't seem to have the feature I care most about: the ability to constrain memory usage (see comment here https://github.com/cloudflare/stpyv8/blob/57e881c7fbe178c598...) - and there's no built-in support for time limits either, you have to cancel tasks from a separate thread: https://github.com/cloudflare/stpyv8/issues/112
PythonMonkey looks promising too: the documentation says "MVP as of September 2024" so clearly it's intended to be stable for production use at this point.
1. The ability to restrict the amount of memory that the sandboxed code can use
2. The ability to set a reliable time limit on execution after which the code will be terminated
My third requirement is that a company with real money on the line and a professional security team is actively maintaining the library. I don't want to be the first person to find out about any exploits!
I will admit I don’t really understand why the library that wraps v8 requires a security team in your view, given that v8 itself definitely has one. I’m trying to understand what you see as the dangerous piece of such code likely to lead to exploits. I’m probably missing something, but I fail to see where the complexity lies.
I also need to limit filesystem access - don't want them stealing private files from elsewhere on the system, or filling the disk with garbage data (again causing a crash).
Network access restrictions are important too - I don't want my server becoming part of some DDoS attack, or an attacker using it to hit supposedly safe internal endpoints (SSRF).
In a browser environment it's much easier to sandbox Wasm successfully than to sandbox JS.
EDIT: found this from your other comment: https://www.figma.com/blog/an-update-on-plugin-security/ they do not address any alternatives considered.
I was looking for something like Pyodide but runnable from Python, but that doesn't seem to exist quite yet. I can get a Python interpreter to run in wasmtime, but that doesn't have the Pyodide goodies like Micropip etc. Sadly, Pyodide itself seems fully married to JS, as it compiles to Emscripten and not WASI.
I'm almost tempted to just go with a small binary embedding V8 and running Pyodide inside V8 isolates or something.
(I know I can do this via Firecracker / GVisor / whatever, that is not the solution I'm looking for.)
And +1000 on linking to your own (or any other well-written) blog.
But there are other ways, e.g. run the logic isolated within gvisor/firecracker/kata.
[1] github.com/microsoft/CCF under src/js/core
One example: given this database table run this JavaScript function against every value in this column to calculate a value to be stored in another column.
Or once a day fetch the JSON from this URL and transform it with this JavaScript and store it here.
You can’t restrict JS that way on the web because of compatibility. But I totally buy that restricting it this way for embedded systems will result in something that sparks joy
I bet MQJS will also be very popular. Quite impressive that bro is going to have two JS engines to brag about in addition to a lot of other very useful things!
Yes, quite! Monsieur Bellard is a legend of computer programming. It would be hard to think of another programmer whose body of public work is more impressive than FB.
Unfortunate that he doesn't seem to write publicly about how he thinks about software. I've never seen him as a guest on any podcast either.
I have long wondered who the "Charlie Gordon" who seems to collaborate with him on everything is. Googling the name brings up a young ballet dancer from England, but I doubt that's the person in question.
I am of the firm belief that "Monsieur Fabrice Bellard" is not one person but a group of programmers writing under this nom de plume like "Nicolas Bourbaki" was in Mathematics ;-)
I don't know of any other programmer who has similar breadth and depth in so many varied domains. Just look at his website - https://bellard.org/ and https://en.wikipedia.org/wiki/Fabrice_Bellard No self-aggrandizing stuff etc. but only tech. He is an ideal for all of us to strive for.
Watson's comment on how Sherlock Holmes made him feel can be rephrased in this context as;
"I trust that I am not more dense than my neighbours [i.e. fellow programmers], but I was [and am] always oppressed with a sense of my own stupidity in my dealings with [the works of Fabrice Bellard]."
PS: Fabrice Bellard: Portrait of a Super-Productive Programmer - https://web.archive.org/web/20210128085300/https://smartbear...
PPS: Fabrice Bellard: A Computer Science Pioneer - https://www.scribd.com/document/511765517/Fabrice-Bellard-In... (pretty good long article)
Not many, but these do come to mind: Linus Torvalds, Ken Thompson, Dennis Ritchie, Donald Knuth, Rob Pike. But yeah, it’s rarefied air up there.
Maybe Bellard identifies with the genius, but fears the loss of it.
Well, now we can run this thing in WASM and get, I imagine, sane runtime errors :)
It's a variant of my QuickJS playground here: https://tools.simonwillison.net/quickjs
The QuickJS page loads 2.28 MB (675 KB transferred). The MicroQuickJS one loads 303 KB (120 KB transferred).
emcc -O3
(and maybe even adding --closure 1 )
edit: actually the QuickJS playground looks already optimized - just the MicroQuickJS one could be improved.
https://github.com/simonw/research/pull/5
Thats now live on https://tools.simonwillison.net/microquickjs
https://bellard.org/jslinux/vm.html?cpu=riscv64&url=fedora33...
I am envious that I will never anywhere near his level of productivity.
I forgot about FFmpeg (thanks for the reminder), but my first thought was "yup that makes perfect sense".
AI will let 10,000 Bellards bloom - or more.
That said, judging by the license file this was based on QuickJS anyway, making it a moot comparison.
It's more a model of what a really talented person who applies themselves building things they enjoy building can do.
I prefer thinking of it this way: if Bellard can make a small JS engine from scratch by himself, what's really stoping you from knocking down this library you are thinking about.
Why do you say that specifically is his specialty? He also started QEMU and ffmpeg which are foundational pieces of software for several industries, and his day job is as founder of a company that makes software defined radio test equipment for cellular networks. There isn't one thing I could point at as a specialty.
Ffmpeg uses a ton of arcane C and assembly knowledge to make multimedia system manageable and efficient. QEMU uses dynamic binary translation for hardware emulation and virtualization. Amarisoft speciality is basically using software to do things which are usually done by hardware.
The intersection of programming language and system programming seems to me like a pretty fair description of what Fabrice Bellard is extremely good at.
https://github.com/yt-dlp/yt-dlp/wiki/EJS
(Note that Bellard's QuickJS is already a supported option.)
> It only supports a subset of Javascript close to ES5 [...]
I have not read the code of the solver, but solving YouTube's JS challenge is so demanding that the team behind yt-dlp ditched their JS emulator written in Python.
* espruino (https://www.espruino.com/)
* elk (https://github.com/cesanta/elk)
* DeviceScript (Microsoft Research's now defunct effort, https://github.com/microsoft/devicescript)
<https://www.moddable.com/faq#comparison>
If you take a look at the MicroQuickJS README, you can see that it's not a full implementation of even ES5, and it's incompatible in several ways.
Just being able to run JS also isn't going to automatically give you any bindings for the environment.
So cool. Where did the name come from? I am so stoked and glad that we are going to have a JS to native binary compiler. The best thing ever!
I was going to set up an AI automation to run on this against the autotests, but as I got started, I felt - why not just create a new language where I can pick my own concurrency paradigms and syntax? So I went with that instead.
So glad someone is doing this. What more do you know about this proejct, kind person?
It has stable funding and a full-time development team of 1.
At first glance Espruino has broader coverage including quite a bit of ES6 and even up to parts of ES2020. (https://www.espruino.com/Features). And obviously has a ton of libraries and support for a wide range of hardware.
For a laugh, and to further annoy the people annoyed by @simonw's experiments, I got Cursor to butcher it and run as a REPL on an ESP32-S3 over USB-Serial using ESP-IDF.
Blink is now running so my work here is done :-)
led.init(48)
function blink() {
led.rgb(0, 0, 255)
setTimeout(function() {
led.off();
setTimeout(blink, 500)
}, 500)
}
blink()One strategy is to wait for US to wake up, then post, during their morning.
Other strategy is to post the same thing periodically until there is response.
- Date: only Date.now() is supported. [0]
I certainly understand not shipping the js date library especially in an embedded environment both for code-size, and practicality reasons (it's not a great date library), but that would be an issue in many projects (even if you don't use it, libraries yo use almost certainly do.
https://github.com/bellard/mquickjs/blob/main/README.md#:~:t...
As I read it, these are supported es5 extensions, not missing as part of stricter mode.
- FFmpeg: https://bellard.org
- QEMU: https://bellard.org/qemu/
- JSLinux: https://bellard.org/jslinux/
- TCC: https://bellard.org/tcc/
- QuickJS: https://bellard.org/quickjs/
Legendary.
That was a sort of defining moment in my personal coding; a lot of my websites and apps are now single file source wherever possible/practical.
$ wc -l ...
265908 sqlite-amalgamation-3510100/sqlite3.c
Is there any as large as possible single source (or normal with amalgamation version) more or less meaningful project that could be compiled directly with rustc -o executable src.rs? Just to compare build time / memory consumption.I've had the inverse experience dealing with a many thousand line "core.php" file way back in the day helping debug an expressionengine site (back in the php 5.2ish days) and it was awful.
Unless you have an editor which can create short links in a hierarchical tree from semantic comments to let you organize your thoughts, digging through thousands of lines of code all in the same scope can be exceptionally painful.
The reason FB (and myself, for what it is worth) often write single file large programs (Redis was split after N years of being a single file) is because with enough programming experience you know one very simple thing: complexity is not about how many files you have, but about the internal structure and conceptually separated modules boundaries.
At some point you mainly split for compilation time and to better orient yourself into the file, instead of having to seek a very large mega-file. Pointing the finger to some program that is well written because it's a single file, strlongly correlates to being not a very expert programmer.
It reminded me how important organization is to a project and certainly influenced me, especially applied in areas like Golang package design. Deeply appreciate it all, thank you.
On reflection, however, I’m unsure how that goes when working on higher-order abstractions or cross-cutting concerns that haven’t been refactored, and it’s too late to ask.
You probably don't need this, but ...
It may not be immediately obvious how to approach modularity since it isn't directly accomplished by explicit language features. But, once you know what you're doing, it's possible to write very large programs with good encapsulation, that span many files, and which nevertheless compile quite rapidly (more or less instantaneously for an incremental build).
I'm not saying other languages don't have better modularity, but to say that C's is bad misses the mark.
You can do a huge website entirely in a single file with NodeJS; you can stick re-usable templates in vars and absue multi-line strings (template literals) for all your various content and markup. If you get crafty you can embed clientside code in your 'server.js' too or take it to the next level and use C++ multi-line string literals to wrap all your JS ie- client.js, server.js and package.json in a single .cpp file
You don't program much in C, do you?
It doesn't necessarily translate to people who are less brilliant.
Honestly, it's a reminder that, for the time it takes, it's incredibly fun to build from scratch and understand through-and-through your own system.
Although you have to take detours from, say, writing a bytecode VM, to writing FP printing and parsing routines...
We underestimate how inefficient working in teams is compared with individuals. We don't value skill and experience and how someone who understands a problem well can be orders of magnitude more productive.
You are absolutely wrong here. Most of us wish that somebody would get him to sit for an in-depth interview and/or get him to write a book on his thinking, problem-solving approach, advice etc. i.e. "we want to pick his brain".
But he is not interested and seems to live on a different plane :-(
Can you elaborate a little about the methods you mention and how you analysed them?
So much of the discussion here is about professional practice around software. You can become an expert in this stuff without actually ever learning to write code. We need to remember that most of these tools are a cost that only benefits for managing collaboration between teams. The smaller the team the less stuff you need.
I also have insights from reading his C style but they may be of less interest.
I think it’s also impressive that he identifies a big and interesting problem to go after that’s usually impactful.
played with implementing analog modem DSP in software in 1999 (linmodem is ~50-80% there, sadly never finished)
probably leading to
played with implementing SDR (again DSP) using VGA output to transmit DVB-T/NTSC/PAL in 2005
probably leading to
Amarisoft SDR 5G base station, commercial product started in 2012 - his current job https://www.amarisoft.com/company/about-us
It's similar to the respect I have for the work of Anders Hejlsberg, who created Turbo Pascal, with which I learned to program; and also C# and TypeScript.
I would not want to dismiss or diminish by any amount the incredible work he has done. It's just interesting to me that the problems he appears to pick generally take the form of "user sets up the parameters, the program runs to completion".
It's kind of crazy it ever became some accepted world view, given how every field has a 10xer that is rather famous for it, whether it be someone who dominates in sport, an academic like Paul Erdős or Euler, a programmer like Fabrice or Linus Torvalds, a leader like Napoleon , or any number of famous inventors throughout history.
Guy is a genius. I hope he tries Rust someday
The design intent of Rust is a powerful idea, and Rust is the best of its class, but the language itself is under-specified[1] which prevents basic, provably-correct optimizations[0]. At a technical level, Rust could be amended to address these problems, but at a social level, there are now too many people who can block the change, and there's a growing body of backwards compatibility to preserve. This leads reasonable people to give up on Rust and use something else[0], which compounds situations like [2] where projects that need it drop it because it's hard to find people to work on it.
Having written low-level high-performance programs, Fabrice Bellard has the experience to write a memory safe language that allows hardware control. And he has the faculties to assess design changes without tying them up in committee. I covet his attentions in this space.
[0]: https://databento.com/blog/why-we-didnt-rewrite-our-feed-han...
[1]: https://blog.polybdenum.com/2024/06/07/the-inconceivable-typ...
The principle of zero cost abstractions avoids a slow slide of compromising abstraction cost, but I think there could be small cost abstractions that would make for a more pragmatic language. Having Rust to point at to show what performance you could be achieving would aid in avoiding bloating abstractions.
I don’t think it can, no.
See also
FineZip : Pushing the Limits of Large Language Models for Practical Lossless Text Compression https://arxiv.org/abs/2409.17141v1
Using a LLM to compress text (o565.com) https://news.ycombinator.com/item?id=40245261
https://searchthearxiv.com/?q=llm%20text%20compression&tab=p...
The math checks out.
Real people have to sleep at some point!
In my engine Arrays are always dense from a memory perspective and Objects don't special case indexes, so we're on the same page in that sense. I haven't gotten around to creating the "no holes" version of Array semantics yet, and now that we have an existing version of it I believe I'll fully copy out Bellard's semantics: I personally mildly disagree with throwing errors on over-indexing since it doesn't align with TypedArrays, but I'd rather copy an existing semantic than make a nearly identical but slightly different semantic of my own.
Figma for example used QuickJS, the prior version of the library this post is about, to sandbox user authored Javascript plugins: https://www.figma.com/blog/an-update-on-plugin-security/
It's pretty handy for things like untrusted user authored JS scripts that run on a user's client.
That way, programs that embed WebAssembly in order to be scriptable can let people use their choice of languages, including JavaScript.
Just in time for RAM to become super expensive. How easy would it be to shove this into Chromium and Electron?
The good news is that it would probably not matter much for chromium's memory footprint anyway...
https://www.macplus.net/depeche-82364-interview-le-createur-...
https://www.mo4tech.com/fabrice-bellard-one-man-is-worth-a-t... (few quotes, more like a profile piece)
He keeps a low profile and let his work speak for itself.
He really is brilliant.
Being an engineer and coding at this stage/level is just remarkable- sadly this trade craft is missing in most (big?) companies as you get promoted away into oblivion.
One such award is the Turing Award [1], given "for contributions of lasting and major technical importance to computer science."
AIUI the Turing award is primarily CS focused.
Here's the commit history for this project
b700a4d (2025-12-22T1420) - Creates an empty project with an MIT license
295a36b (2025-12-22T1432) - Implements the JavaScript engine, the C API, the REPL, and all documentation
He went from zero to a complete JS implementation in just 12 minutes!
I couldn't do that even if you gave me twice as much time.
Okay, but seriously, this is super cool, and I continue to be amazed by Fabrice. I honestly do think it would be interesting to do an analysis of a day or week of Fabrice's commits to see if there's something about his approach that others can apply besides just being a hardworking genius.
// global. initialized by SomeConstructor
var fooInstance
class SomeConstructor {
constructor(...) {
fooInstance = this;
}
static getInstance(...) {
if (fooInstance != null) return fooInstance;
return new SomeConstructor(...);
}
} a = []
a[0] = 1; // OK to extend the array length
a[10] = 2; // TypeError
If you need an array like object with holes, use a normal object insteadGuess I'm a bit fuzzy on this, I wouldn't use numeric keys to populate a "sparse array", but why would it be a problem to just treat it as an iterable with missing values undefined? Something to do with how memory is being reserved in C...? If someone jumps from defining arr[0] to arr[3] why not just reserve 1 and 2 and inform that there's a memory penalty (ie that you don't get the benefit of sparseness)?
- A small and efficient JS subset, HTML, CSS
- A family of very simple browsers that do just that
- A new Web that adheres to the above
That would make my year.Browsers are complex because they solve a complex problem: running arbitrary applications in a secure manner across a wide range of platforms. So any "simple" browser you can come up with just won't work in the real world (yes, that means being compatible with websites that normal people use).
No, new adhering websites would emerge and word of mouth would do the rest : normal people would see this fast nerd-web and want rid of their bloated day-to-day monster of a web life.
One can still hope..
Oh right. 99% of people don't do even that, much less switch their life over to entirely new websites.
In 2025, depending on the study, it is said that 31.5~42.7% of internet users now block ads. Nearly one-third of Americans (32.2%) use ad blockers, with desktop leading at 37%.
(There are even a lot of developers who would inherently drop any feature usage as soon as you can get 10% of users to bring down their stats on caniuse.com to bellow ~90%.)
The embedded use case is obvious, but it'd also be excellent for things like documentation — with such a browser you could probably have a dozen+ doc pages open with resource usage below that of a single regular browser tab. Perfect for things that you have sitting open for long periods of time.
For a “lite web” browser that’s built for a thin, select slice of the web stack (HTML/CSS/JS), dragging around the heft of a full fat JS engine like V8 is extreme overkill, because it’s not going to be running things like React but instead enabling moderate use of light enhancing scripts — something like a circa-2002 website would skew toward the heavy side of what one might expect for a “lite web” site.
The JS engine for such a browser could be trimmed down and aggressively optimized, likely even beyond what has been achieved with MQJS and similar engines, especially if one is willing to toss out legacy compatibility and not keep themselves beholden to every design decision of standard JS.
Also, legacy machines couldn't run it as fast as they could.
But it was not insane, and it represented a clarity of thought that then went missing for decades. Several things that were in WML are quite reminiscent of interactions designed in web components today.
Gemini is not a good or sensible design. It's reactionary more than it is informed.
I understand this has been tried before (flash, silverlight, etc). They weren't bad ideas, they were killed because of companies that were threatened by the browser as a standard target for applications.
Or maybe just make it all a single lispy language
Work towards an eventual feature freeze and final standardisation of the web would be fantastic though, and a huge benefit to pretty much everyone other than maybe the Chrome developers.
Now I know that Markdown generally can include HTML tags, so probably it should be somewhat restricted.
It could allow to implement second web in a compatible way with simple browsers.
With a markdown over HTTP browser I could already almost browse Github through the READMEs and probably other websites.
Markdown is really a loved and now quite popular format. It is sad gemini created a separate closed format instead of just adopting it.