lukaslalinsky
lukaslalinsky on Hacker News
But written in Go, and I would expect the NetBSD base only includes software buildable using tools already in the base system.
If you know what you want to do (i.e. you have the architecture/pseudo-code in your head already), LLMs are a actually quite good at transforming that into real code and do save you time/effort. If you are using them like slot machines, and hope for the best after a vague prompt, then yes, it's not worth it, it just leads to frustration and wasted energy.
I was a fan of the Debian GNU/kFreeBSD project, I wanted to use FreeBSD back then, but I was unhappy with the BSD approach to software packaging. But even that was abandoned due to lack of interest. People who want to use BSDs just generally prefer the BSD way of doing things. I might be wrong, but I don't think the anti-AI ex-Linux-user crowd is large enough for this to become successful. I think a more useful work from the anti-AI community would be to start improving the driver situation in NetBSD/OpenBSD, so it can be used on modern machines, and just accept the BSD way of packaging software.
While you could say that, all the operations are documented behavior. You need to assume they will block. If the blocking happens in userspace runtime or in the kernel doesn't matter. And you, as the application author, are the one choosing which runtime to use. This just allows the libraries to be generic.
There is a difference between single-threaded and multi-threaded, but if you use `io.concurrent` or `io.async`, you are expected to have your code assume multi-threaded enviroment. And there is no visible behavior change between blocking and non-blocking backend, assuming you are not calling external libraries that do their own I/O. So code written and tested on blocking threaded I/O, will work just fine on async implementation. All I/O operations are the yield point.
There is no magic about the I/O interface. It's a regular dynamic dispatch, the same as if you use virtual functions in C++. Currently, and in the foreseeable future, there are only two options how it can run, blocking mode where each task occupies a dedicated thread, or using stackful coroutines. The interface implements blocking functions, there is no async waiting anywhere in there. But because it's dynamic dispatch, it allows the async implementation to do the "prepare operation, suspend until completed, wake up" dance, where the threaded implementation would just run the blocking syscall directly. There are plans to add stackless coroutines, but that will require many language restrictions to happen first, so it's not going to happen any time soon and when it does, the interface will likely change to accomodate it.
You are looking at this from the wrong perspective. If you are fine with automatic allocations and RAII like you have in C++ or Rust, or with a garbage collected language, there is pretty much no reason to even look at Zig.
Zig is a language to use when you do need the control, mostly because of performance reasons. And once you are in, you start thinking how to manage your allocations and arenas are the logical outcome, once you notice that your application has scopes that can be destroyed at once.
If you need an argument why arenas are better than RAII, then you likely don't have the performance needs to even consider using Zig, because outside of performance, arenas are not better.
My biggest advice is to keep programming for fun. I don't know what do you do at work, but for me work was never the satisfying activity what I started programming for. Pretty much all the problems at work were obvious and just needed the code written. But outside of work, you get to experiment, you get to learn, solve challenges. I started programming because I was fascinated by how what we learn at math class (trigonometry) can be used to display things on the computer (old 8bit one). Then I rented all the books from the local library and studied, even though I didn't have a computer at home. And this kind of kept me going. I always had a personal project which can occupy my head, and in the past, when I got home, I could try to write the ideas into code. These days, I use the agents for the last step, but that step was never the fun part for me, it was the thinking and "connecting the dots".
How long have you been using it? I've always been disappointed with similar systems, etcd including.
I think you are misunderstanding what the article suggests. std::atomic::wait and std::atomic::notify_all are the C++ abstractions over futexes. The whole concept of the future can be expressed in terms of atomics and futexes. The only problem is that the C++ standard doesn't have std::atomic::wait_for.
I'm Slovak, and when I was a kid, I was really wondering what is the thing that makes people Slovak, what is the unifying thing. And only later in life I realized, that there is not much to it. It's just people that happened to be living in this area and stayed throughout the different times. Many cultures came and left. All the slavic languages we kind of fluid for a very long time, the standardization is recent, if you look at it from global point of view. The sad part is, this is not really even taught in local schools. And I also find it fascinating, that it's such a wild blend of cultures and yet the country/nature where the people lived formed them to something unique.
How fast does it go when you do a few PostgreSQL queries per request?
Look at https://www.http-arena.com/. For raw throughput on keep-alive requests, low-level languages are going to win without a question. But once you put database roundtrip into the mix, the distance gets much smaller.
And I'm saying this as an author of another HTTP server in a low-level language.
You would be surprised how fast Node/Bun can be if you scale them properly. If you use Bun, you are using uWebSockets already. If what you are doing in your application is database queries and some template rendering, you might not actually gain that much from these compiled languages.
And then it reads all the AI-written "docs" from the previous changes, at which point it's all so muddy, it just tries to copy the style and output more junk and more verbose "docs". This is why I never let AIs maintain documents on their own.
In my experience, the worse crap gets into the codebase through updates. Especially when dealing with something hard, Claude will take shortcuts, that undermine the project. In my projects, I deal with it by still pair programming with it. But as far as I understand, Anthropic deals with it by re-creating projects, rather than updating them.
Unfortunately, it you want to handle errors right, it's overly verbose, so no one really does it. That's my problem really. Even in the blog post snippet, I could have show well behaved code, because I'm well aware of it, but then the error handling would be more code than the part I'm trying to showcase. Static analysis will not help there.
Zmpl wants you to build up a JSON-like data tree, and templates work using those values. That unfortunately means you are back to dealing with runtime errors. Minor thing, but they also want to render the template into an allocated string, rather than writing it to std.Io.Writer directly. And then there is the syntax, I prefer the Go Templ approach.
I have a partially written blog post in my head, as I've spent a lot of time thinking about the problem. I'd have preferred if there was a change to the reader/writer interfaces, but even without it, I'm starting to see patterns that work and can be applied to any code to make it safe. People just need to be aware of the problem and that's my goal, although I'm probably failing if my tone is creating the drama, so I'm learning how to communicate it better.
It's a different approach to Rust. There, if you cancel a future, it stops polling and runs the Drop interface. You don't get to do more complex cleanup. But, at the same time, because cancellation is not an error that all functions have to propagate, it's structurally not possible to ignore it. Zig, like many other languages, uses a specific error to indicate cancellation. The application can decide what to do with it, it has some benefits. But unlike Python/Java where exceptions can he thrown from anywhere, Zig errors need to be named and that's where to issues comes from, because the Reader/Writer interfaces no longer are generic, they can't pass the concrete errors returned from the implementations, and cancellation is one of the errors that get hidden that way. It's a comprise either way, Zig would need to have first class support for comptime interfaces/traits to solve it better, but that's not going to happen. So in the meantime, there is a dilema how to handle it, but I'm sure it will get solved, or at least best practices will get developed.
No, that's not the best description. The Io interface is actually one of the best cancellation stories out there. If you combine it with defer/errdefer, you get safer cancellation guarantees than you have in async Rust (you can do async "drop" for example). The only problematic part is the interaction between the Reader/Writer interface and the Io interface, with regards to error handling.
Fun fact, I actually also had a fork of the Google Closure Templates that added support for Python. I used it briefly. I completely forgot about it, but I remember now I did enjoy using it back then.
https://pythonhosted.org/Flask-Soy/
For me web was always about these scripting languages. Even in the CGI days, I learned to use Perl just enough to do a simple web form. I kind of associated the domain with GC languages, as this kind of work usually involves many temporary strings and dictionaries. In fact, the first compiled language I ever used for a web project was Go, and even that was due to the fact that it has garbage collector.
I'm not a fan of Rust, the overly flexible macros are actually one reason for it, but if you can indeed get LSP support in a custom syntax like this, that's really awesome. Thank you for the example.
Posted by
lukaslalinsky on Monday October 12, 2026 @01:02AM
from the lalinsky.com dept.
Programming has the disadvantage that it can be both art and factory work, and there is no language to distinguish these. Unlike writers, musicians, most programmers are unfortunately doing factory work, making CRUD web apps, etc. And the factory work is being replaced, there is no way around it. Artistic programming will forever remain a niche, something that people do as a hobby, at young school ages, or during weekends when older. In commercial settings, the software is not the end product companies are paying for, the solved problem is. In the artistic settings, the software is the project.
Congrats to Philipp and the guys on the release, and thanks for keeping it alive. I was just looking at the MusicBrainz blog today, went down the history lane. I find it unbelievable that it's 20 years since I took over the project from Rob and did my first release with him.
No, this has nothing to do with processes. It has to do with the `context` package, which the best way to do goroutine cancellation in Go, but if you look how it works under the hood, it requires a lot of hacks, because there is no direct cancellation support for operations in the runtime. For example, every single `Read()` in the standard library would have to be wrapped by `AfterFunc()`, not all of them actually do it, so some reads are cancellable, some reads are not. It's all just best-effort with no guarantes.
It's true for almost all pthread implementations, not all. But when talking about asynchronous I/O runtimes and coroutines, you have more options. Systems like Tokio, or zio (the one I'm working on), give you a task handle, and when you call `cancel()` on the handle, it will cancel whatever async operation the task is currently running. And it does so reliably.
I was amazed how well are goroutines integrated into the language when I saw the first videos from Rob Pike. Then I actually started using Go for concurrent code, and noticed one thing, it's extremely easy to leak goroutines. There is no proper way to cancel them, they need to cooperate via select/context. Go developers eventually learn hacks to deal with it, but the simple go+chan style of programming style you see in tutorials is usually not safe. I still consider Go a remarkable piece of software. The runtime really doesn't have any seriously bad edge cases, it just works. But as a developer, I now prefer a slightly more explicit approach to concurrency. I've spent the last year developing an async runtime for Zig and I'm now more comfortable writing concurrent code in Zig than I was every using Go. I have more options for how to handle closed channels, I can cancel any operation, etc.
It takes 10+ years for any storage engine to iron out all the wrinkles, get it to a state where it's both fast enough, and you can trust it to not lose data. It's stupid to throw it away once it reaches that point.