For the past couple of month, I have been building belgie (https://github.com/mplemay/belgie) with the goal of making it easy for agents to dynamically generate user interfaces / code in a sandboxed environment. At a high-level, it supports
1. Create React MCP UIs (and traditional Web UIs) from python without needing a JS runtime installed
2. Provides a deno backed typescript sandbox for agent generated code via pydantic-ai / langchain
A great example use cases is automatically generating UIs for SQL query results.
This opinion is not backed by facts, any insight about linux (or even the languages in question), or even related to this post. Nevertheless, I wonder if it was a good idea to allow rust contributions to the linux project. From all of the bits and pieces I read about zig (including this project), I feel like it would have been better aligned (than rust) to pick up where the mainly C codebase left off.
Not really. Zig's answer to safety is mostly based on runtime panics, and the kernel really, really hates panics.
As such, the only thing left is better ergonomics, and that's not really worth the effort to switch.
Rust isn't being adopted because it's an easier language to code in, and in fact it's being adopted in spite of the fact that it's harder to code in. And that's because to some kernel devs, the promise of better security and fewer vulnerabilities is worth that much.
On the other hand, Zig is great for user-space applications. The stuff to replace GNU's coreutils with.
> Zig's answer to safety is mostly based on runtime panics
This statement is nonsensical.
Zig's answer to safety is based on a precise type system and a simple language that helps the programmer in their quest to write perfect code. If a kernel panics, that is either a bug or hardware failure.
You're right, my bad. It is hard to be precise in a comment where I'm trying to be as concise as possible.
I'm sure you know what I mean though, with regards to temporal memory safety (lifetimes), data races (Send/Sync traits), etc. Rust works by preventing many classes of bugs through compile errors, rather than panics.
> If a kernel panics, that is either a bug or hardware failure.
And this is where Rust differs; Rust will reduce the likelihood of bugs from happening in the first place. I'm not saying Zig doesn't also do that, Rust just does it more.
The Rust compiler devs, in their quest to make a type system that is powerful enough to catch most memory corruption errors, somehow came up with something that can be used to catch far more issues than just that.
The affine(ish) type system, coupled with lifetimes, makes modeling and maintaining correct states much easier than in Zig, for all sorts of objects and abstractions.
From what I've read from Linus on LKML/lore along the years, a kernel oops/panic is seen as one of the worst things that could happen to it; there is generally nothing the user can do at that point to debug it (they likely won't even see the console), and makes the machine unusable for all other tasks. Sometimes you might be lucky and just kill and collect the thread that panicked, but oftentimes you get the nuclear OOPS option. With Zig you don't even get the option to catch it via something like catch_unwind.
> And this is where Rust differs; Rust will reduce the likelihood of bugs from happening in the first place. I'm not saying Zig doesn't also do that, Rust just does it more.
I'd argue that it does this a LOT more. When it comes to spatial safety, Rust and Zig are on par. However in terms of temporal safety I think Zig lags far behind Rust... along with basically every other compiled systems language.
If you had to come up with a single good reason to use Rust over Zig, it would definitely be temporal safety. A majority of applications don't need this though, or can be designed such that they don't.
One of my main issues with Rust is that it makes it easy to write spaghetti code that uses reference counting all over the place. I don't recommend people to use Rust until they become a "N+1 programmer" that Casey Muratori describes as "grouped element thinking" [1]. At this point, most of that programmers problems are solved and suddenly the Zig vs Rust debate becomes much more nuanced.
And those checks are well worth paying for, enough that Rust also has them! I'm sure Rust would have even worse ergonomics if it insisted on no runtime bounds/unwrap checks. The performance cost is low enough that every systems programming language should have spatial safety. To illustrate, Google found that hardening libc++ by adding bounds checks only led to a 0.30% performance impact on their services [1]. It's not hard to imagine that a similar run-time cost affects Zig and Rust. Both languages make attempts to optimize the checks away if the operation is known-safe. Although, maybe Rust is more successful due to the borrow checker.
> and/or misusable allocator passing.
Could you clarify how allocator misuse might lead to a spatial safety violation?
I've done a couple of projects in Rust, and I can appreciate this sentiment.
I don't think my code was pretty and I know it wasn't idiomatic. But I have some experience in writing concurrent code, so I have an understanding of the reasoning behind Rust's borrowing semantics, why lifetimes are important, and the difference between boxed values, rc, arc, and I additionally understand the semantics of semaphores, mutexes, spinlocks, and critical sections.
(As an aside, I don't know if I'm an N+1 programmer. My code works, long term, requires very little maintenance, and generally stays out the way. Just the way I like it.)
But- I see these recurring themes in posts from Rustaceans along the lines of "the compiler tells you what's wrong" and "if it compiles, it's correct!"
These kinds of statements worry me. Not necessarily because I think their code is going to blow something up, but because I think a sizeable portion of the community does not really understand the guarantees Rust provides, and under what contexts they are valid. I mean, sure, you might not have a data race, but you sure as hell can code yourself into race condition or a deadlock, and from what I understand from HNers, these situations are not all that uncommon in Rust crates. I'm also led to believe that the panic handling situation in some crates isn't ideal.
You shouldn't just haphazardly Arc<Mutex<T>> all the things just because that gives you the Send + Sync that you think you're looking for (or the compiler is looking for). You should understand what the hell you're doing, be able to tell if those things are necessary, and understand the ramifications of using those abstractions.
I think there's a lot of good going on in the Rust ecosystem, and I wish I had more work in that area, but there's a lot of blind advocacy there that assumes the Rust approach is the best, but the language does have serious ergonomic limitations in certain low level scenarios. My whole career I've had to focus on scope and objects that outlive their scope, but now every other word I seem to hear from the Rust community is "Lifetimes" and "Ownership", like these concepts were completely unfamiliar to developers before and now the Rust Way(tm) is not only THE WAY, but THE ONLY RIGHT WAY.
I don't want to go too far off the rails, because I find the ecosystem intriguing, and I see tremendous value there. Whether those approaches stand the test of time isn't a given (although let's face it, they probably will because they are sound and they are gaining developer mindshare, which is the most important factor).
I just worry about ergonomics. Coding is not supposed to be easy, so please don't misunderstand- but coding, especially for those that do it day in and day out for decades, should not be a chore. There are definitely some QOL improvements that could be realized in the near term, although I'm not sure what those would look like.
It does not, for slice indexing Rust is just as bad. My best guess is that this will likely blow up into such a big issue that the Rust devs are going to be forced to implement a feature to disable indexing (and leave just the safe .get()), or the kernel devs will fork the core library.
But Rust prevents a myriad of other things that would be panics in Zig or undefined behavior in C. It has a really strong type system, capable of reducing a large amount of invalid states and keeping many invariants throughout very large codebases.
Static checks remove many more potential sources of panic. I suspect that with certain restraint one can write Rust code that is statically guaranteed to not panic.
Also, Rust's panics may be recoverable, it's not necessarily fatal.
Just today, I started exploring the current web development ecosystem in Python. As a long-time Python developer, it is amazing to see all the recent work that has gone into making the web accessible to more than just JavaScript developers.
Despite seeing all these amazing new approaches (e.g., Reflex, Streamlit, and now this), I can't help but think there is still a need to rely on "more mature tech" (though this gap is closing) to make non-trivial websites in Python (and in general). After surveying the Python (and JavaScript) ecosystem, I personally decided that a simple stack consisting of FastAPI, Pydantic, SQLAlchemy, Jinja2, Tailwind CSS, and HTMX would be the fastest approach to build a non-trivial app using Python.
With that being said, I will definitely circle back around in a month or so to see how things have progressed. I wish you all the best in making Python a contender for the next generation of web development.
I am trying out a new stack I’m coining “SLAP” for small web apps.
SQLite, Linux, Apache/Nginx, PHP
It’s reminiscent of LAMP, so it’s very easy and cheap to deploy and maintain. I do wish the P stood for python instead of php, but Nginx integrates so well with php and doesn’t require a long running process like PM2 (nodejs) or Gunicorn.
Well unless you use a less traditional setup such as FrankenPHP, in order to run PHP behind a Nginx server you still need a long running process for PHP-FPM, if I'm not wrong? :-)
Thanks! In general I'm a big fan of choosing the right tool/stack for the job, and for the developer's natural disposition, and I'm a fan of your choice of stack.
Do you mind linking the homepage, google scholar, etc. of "Petar Velolickovic"? The only reference to the name on google search appears to be this post.
Thanks for working on such an awesome project and releasing such useful features!
Yet, what stops us from using supabase is not the set of features, but the state of the current apis. Last night I was evaluating the python sdk and some of the examples were broken, baseline features like RLS are unimplemented (https://github.com/supabase-community/supabase-py/issues/58), and progress seems slow (it seems to have been release two years ago and it is still in alpha). Even though supporting many platforms is boring (i.e. no flashy feature announcements) and costly (many FTEs are required for maintenance let alone adding features), are there any plans to bring feature parity more of the sdks to allow more developers to leverage this awesome platform?
client libs are one of our next focuses. we've been discussing internally how to do this. So far we have concentrated on the JS/Dart libs because that makes up a large portion of our users. Over the last 3 months the community has added (and documented) libraries for Swift[0] and C#[0].
We hope to continue making this a community-driven endeavor, so if anyone reading this would like to become a maintainer for one of the libraries (especially Python), please reach out. If we can't find maintainers we'll find a polyglot who can work on this full-time.
> We hope to continue making this a community-driven endeavor, so if anyone reading this would like to become a maintainer for one of the libraries (especially Python), please reach out. If we can't find maintainers we'll find a polyglot who can work on this full-time.
We don't have a lot of C++ experience in the team, but I'll share your feedback with the Realtime team - perhaps we can find someone in the community to help
TLDR: You're agent will get a isolated v8 runtime (chrome's sandboxed javascript runtime)