HNHacker News
TopNewBestAskShowJobs

gnuvince

2,803 karma · joined March 11, 2010

submissionscomments
gnuvince··on 15k inserts/s with Rust and SQLite (2021)
It's not enormous, but it's good for the simplicity and would probably be sufficient for quite a number of use cases. And I'd guess that it's also probably more than what many programmers get by Lego stacking 14 different abstractions.
gnuvince··on “Clean” code, horrible performance
That's one side of the expression problem; the other is adding a new operation. With dynamic dispatch, you can add new shapes without altering the others, but if you want to add a new operation (e.g., perimeter()) then you have to modify the base class and all the children. With discriminated unions, adding a new shape requires modifying all the operations, but adding a new operation only requires the creation of a new function.
gnuvince··on “Clean” code, horrible performance
The table version also has something really interesting going for it: it just begs to be thrown out and replaced should new requirements come in that don't fit with that design. If a new type of shape comes in that doesn't fit with the factor * width * height model (e.g., a trapezoid), we'd need to go back to the drawing board and figure out how to make the existing and new cases work harmoniously together.

On the other hand, an abstract base class broadcasts the message that we should fold our new cases into the existing design -- that's what base classes are made for. But even when new cases don't fit neatly in the existing design, we often feel as programmers that we need to pay respect and deference to existing design, especially if it was made with extensibility in mind. And so we add more complexity (maybe we need an extra field or an extra method), make more kludges, and soon enough the original OO design is a mountain of complexity and has so much "gravity" that it's nearly impossible to escape it anymore -- nobody can imagine throwing it out and starting fresh, so it just keeps gaining complexity. And for all its complexity, it's also slower.

gnuvince··on “Clean” code, horrible performance
Another quote from Knuth, from that same paper:

> The improvement in speed from Example 2 to Example 2a is only about 12%, and many people would pronounce that insignificant. The conventional wisdom shared by many of today's software engineers calls for ignoring efficiency in the small; but I believe this is simply an overreaction to the abuses they see being practiced by penny-wise-and-pound-foolish programmers, who can't debug or maintain their "optimized" programs. In established engineering disciplines a 12% improvement, easily obtained, is never considered marginal; and I believe the same viewpoint should prevail in software engineering. Of course I wouldn't bother making such optimizations on a one-shot job, but when it's a question of preparing quality programs, I don't want to restrict myself to tools that deny me such efficiencies.

That paper was published in 1974 and yet it captures the mindset of many a programmer in 2023 perfectly. The part I like about this paragraph is the "easily obtained" sentence; I saw a comment from someone mentioning that they made a JavaScript program 10 times faster by replacing the common functional programming combinators (map, filter, reduce, etc.) with for loops. I think most of us would say such a change is easily obtained, does not make the code impossible to debug or maintain, and gives such a massive improvement that it should be a no brainer to reach for it.

gnuvince··on John Carmack on Functional Programming in C++ (2018)
> To me, the most understandable function (lowest context needed, lowest cognitive overhead) is a black box that takes type x as input and produces type y as output, without side-effects

True, however we must be careful not to go completely bananas either; it's really hard for a reader to piece back together a full mental picture if the functionality is spread into dozens even hundreds of general-purpose 3-line functions.

Simple, `y = f(x)` types of functions are indeed the easiest to understand, but you might be no closer to understanding what the code is actually doing.

gnuvince··on Thoughts on what a next Rust compiler would do
The Rust dev builds are very often (1) slower to build than the equivalent Go program, (2) slower to run than the equivalent Go program. Rust programs really need the `--release` flag to shine—and in some cases, the dev builds of a program cannot be meaningfully used, even for local testing, since they're so slow.
gnuvince··on Production Twitter on one machine? 100Gbps NICs and NVMe are fast
Fixed timestamp: https://youtu.be/LjFM8vw3pbU?t=1613
gnuvince··on Production Twitter on one machine? 100Gbps NICs and NVMe are fast
There's a story by Bryan Cantrill [1] about how he went to Twitter to help them understand why it would take 400 milliseconds of compute to process a request (I'll leave the reveal to Bryan). Scaling horizontally is probably necessary for something the size of Twitter, but that doesn't mean that we can half-ass the code and just throw more machines at the problem. If we write code with a bit more mechanical sympathy and avoid the latest non-proven fads, we can surely write software that is 10x faster and requires much less scaling.

[1] https://www.youtube.com/watch?v=LjFM8vw3pbU&t=3240s

gnuvince··on Microfeatures I'd like to see in more languages
I like D's approach of using `d[$]` to get the last element, `d[$-1]` to get the element before last, etc.
gnuvince··on Understanding the N + 1 queries problem
> To be clear, I'm not anti-ORM and use them all the time, but it really helps to understand SQL well when using them and to know when it's appropriate to switch to SQL.

When I did web development, I saw it as a "hack" and a "failure to write clean code" whenever I reached for raw SQL. This is of course not true at all, but it was a powerful psychological blocker and I'd spend too much time trying to figure how to get the ORM to do what I wanted instead of writing the SQL myself and moving on to the next problem.

gnuvince··on Functional Programming – How and Why
> Unless there is clear evidences upfront that the project will be a piece of software where local performance is highly critical, it makes sense to favor code readability and maintainability over optimality.

Sure, but let's also not confuse "optimal" with "reasonable". One of the major challenge of modern programs is how slow they are at every level. Very often, this bad performance can be attributed to a style of programming that tries to completely ignore that the program will run on a real machine with real hardware. A little bit of mechanical sympathy (e.g., operations that make good use of the CPU caches or don't confuse the branch predictor) can yield a program that is 10x faster than a naive implementation, with little to no loss of readability or maintainability. (In fact, as noted by Nelson Elhage [1], faster programs enable simpler architectures, which helps make them more readable and maintainable.)

In FP languages, programmers face an extra difficulty: the distance between the code they write and the machine code that will be executed is greater than in languages like Rust or Go. They will need to be knowledgeable about the language, its libraries, and its compiler to avoid the pitfalls that could make their programs slower than would be reasonable (e.g., avoiding unnecessary thunking in Haskell).

[1] https://blog.nelhage.com/post/reflections-on-performance/#pe...

gnuvince··on Investigating Logan Paul's biggest scam [video]
I'm not an expert on this topic, so I'd like to know as well. My own personal theory is that most people, whatever their intelligence level, feel that they are smarter than the average person and their intelligence is part of their sense of identity. When people fall victim to a scam—when they are outwitted—that sense of identity takes a big hit and it's so hard to admit that they were not as smart as they thought they were, that they were wrong about who they thought they were. And so rather than doing the rational thing which would be to admit being deceived and not seeing through it, they double-down, they want to find a way to make the scam work for them, to prove to others, but mostly themselves, that they were not dumb, that they were the smart ones.
gnuvince··on The best Go framework: no framework?
For junior developers reading this: frameworks are great, but they will become an increasing source of technical debt, performance loss, and frustration. They will allow you to ship your first version faster, but every release after that will become harder. Not that it wouldn't be hard without a framework either, but frameworks make us feel that we need to work within their constraints rather than the constraints of our application and our users.

So learn a framework for whatever language you use, that's useful! But also learn to recognize when you are working against the framework and would be better served with a few libraries that you can combine in the way that you need. Frameworks optimize for certain use cases and expectations, and if your project is no longer aligned with those, it's probably a good idea to think about an exit strategy.

gnuvince··on SwiftUI Is Convenient, but Slow
It hasn't. It's possible for programmers to get massive speedups by re-architecting their code to make better use of the CPU caches or avoid branch mispredictions and that happens because the compiler was not sufficiently smart to do that transformation itself.
gnuvince··on SwiftUI Is Convenient, but Slow
That line of reasoning reminds me of the fabled sufficiently smart compiler: one day, the sufficiently smart compiler will understand what we mean in our programs and generate code that is faster than what an expert could write in C or even assembly. Unfortunately, the sufficiently smart compiler still hasn't arrived.

And similarly, the performance potential of SwiftUI has not been unlocked. Maybe it will happen, but while we wait for the SwiftUI to implement those fabled optimizations, developers have to wrestle with—from what I gather from the article—a lot of extra accidental complexity so that they don't impose an unusably slow interface to their users.

gnuvince··on Data-Oriented Programming in Python
Unfortunately, the terms "data-oriented design" and "data-oriented programming" refer to two different styles of programming. Data-oriented design is the approach to programming made popular by Mike Acton's CppCon keynote—as you say, it focuses on the layout of objects in memory to make the processing of data take advantage of the underlying hardware.

Data-oriented programming is a style of programming that, as far as I know, originates in the Clojure community. It emphasizes using general data structures (vectors, dictionaries) to store all data and make code more re-usable. It has nothing to do with good cache utilization, pre-fetching, or avoiding branch mispredictions.

It's a shame that two styles of programming which are almost diametrical opposites share such similar names.

From the look of the article, it's discussing data-oriented design, but in Python, and I agree that it's kind of a weird match.

gnuvince··on Cracking Passwords Using John the Ripper
That's a program name that I haven't heard in a while and which brings back memories :D

When I was a teenager, sometimes around 1996 or 1997, I watched the movie "Hackers" for the first time and my immature mind was immediately drawn to the idea of using computers to sneak into places you weren't supposed to. (The pretty graphics helped too.) I went online and I found an early version of John The Ripper and thought "yes, this is exactly what I want!" It would be a few years before I even learned what Unix and /etc/passwd were, but it felt so cool to have a real hacking tool on a floppy disk.

gnuvince··on Just don’t
A few months ago, I wrote a blog post[1] about the word "just" that echoes the thesis of Tim's article: avoid using the word "just" if you can, it's reductive.

[1] https://vfoley.xyz/just/

gnuvince··on Almost monospaced: the perfect fonts for writing
Oh, that guy and his stupid habit of putting an asterisk in the font name—impossible to use in Emacs.
gnuvince··on Helix: Post-Modern Text Editor
In Helix, you can use `maf` to mark the outer function and then press `d` to delete it.
gnuvince··on Helix: Post-Modern Text Editor
I'm a long-time user of Emacs, and although I don't see myself switching to Helix, one thing that I really liked when I looked at Helix was how good the out-of-the-box experience was. As I get older, I am annoyed at the amount of customization that I have for different programs, and I wish I had fewer dotfiles that to maintain and carry around. I recently started trying some of my daily drivers (alacritty, fish, tmux, git) without my configurations and though they're a bit less comfortable, they're pretty good nonetheless. I would probably put Helix in that category: I would probably be fine just using the thing without any customization, because the defaults are so well chosen and polished.
gnuvince··on Expectations of professional software engineers
> We want to abdicate responsibility of this kind of memory management to the interpreter, just like we want to abdicate responsibility for handling processor cache levels. If you can articulate how all the data you use is laid out in memory all the time, you are majorly micro-managing the runtime.

Unfortunately, in practice, it's not possible to be oblivious of the layout of data in memory if we want to write fast code. The CPU/memory speed disparity graph [1] shows the new reality for programmers: the slowest part of a program is bringing data from RAM into the CPU registers. Fortunately, modern CPUs have very fast caches that help amortize this cost and it's the responsibility of the programmer to organize data to take advantage of that fast hardware—the compiler cannot do it. That's why two functions, with the same algorithmic complexity, and which compute the same result, can have an order of magnitude of difference in performance between them [2]. The famed sufficiently smart compiler that can do those transformations does not yet exist as far as I know.

[1] https://gameprogrammingpatterns.com/images/data-locality-cha... [2] https://play.rust-lang.org/?version=stable&mode=release&edit...

gnuvince··on Helix: A Neovim inspired editor, written in Rust
It has macros.
gnuvince··on A Review of the Odin Programming Language
Odin and Zig are the two up-and-coming languages that I keep my eye on. I like how they are trying to find a sweet spot where they offer more than plain old C, but without becoming overbearing like Ada, C++, or Rust.
gnuvince··on I like Odin
Odin is currently at the top of my Rust exit-ramp strategy (for personal work).

As I grow older, I find myself wanting to use languages that are more conservative in their designs. Back in my 20s, I was all about expressivity and meta-programming: Scheme, Smalltalk, OCaml, and Haskell were my drugs of choice. I looked down upon those simple peons who used pedestrian languages like Java or PHP and I definitely looked down on those neckbeards who hadn't left their C caverns and didn't know the greatness of closures, higher-kinded types, hygienic macros and all those features that real languages had.

That's how I came to learn about Rust: in the early 2010s, there was a post on Reddit about a new programming language implemented in OCaml. Even before Rust 0.1 was released I was a Rust enthusiast. And what a ride it's been! Rust transformed and evolved a lot since its first days, but what a language it ended up becoming! In a just a few years, Rust went from being a hobbyist toy to an industrial-strength tool used by large projects and corporations like Mozilla, Dropbox, Discord, Amazon, Facebook, and more. I've been using it professionally myself for the past 5 years and it's been (mostly) a great experience.

But as Rust and I continue to change, it seems that the paths of our lives are diverging. As I gather more gray hair, I don't have the energy, the time, or even the passion for learning and master exotic language features anymore. I now avoid a lot of the "cool toys" that I was so enamoured with in my 20s. My programming style is now much closer to what it was when I first learned to program in Turbo Pascal in the mid-90s: mostly functions, arrays, and structs. Rust on the other hand continues its quest to be an industrial language that has ivory tower creds: the community and the core team enthusiastically look forward to having more ways to abstract code, more ways to express constraints at the language level. I feel that before long, my values and Rust's will have grown so far apart that we'll have no choice by to break up our long relationship.

So I've been looking for what else I could use for personal projects. (I think and hope that I continue to use Rust for my professional career.) Odin is at the moment my clear favorite, with Zig slightly behind, and Nim after that. I find that Odin's design represents my own values about what software and a programming language ought to be like better than anything else out there at the moment. It's high-level, has out-of-the-box support for dynamic arrays and dictionaries (I think, the two most useful data structures), and the whole language is simple enough that I learned most of it in a weekend. It does feel like a step back from Rust in certain areas -- null pointers, using product types for returning errors, no ownership checking -- but I think that I'm at a point where I'm ready to forgive and deal with these issues in order to have a tool that is simpler and doesn't evolve at the speed of 20 year olds.

gnuvince··on Bun: Fast JavaScript runtime, transpiler, and NPM client written in Zig
From the webpage:

> An enourmous amount of time spent profiling, benchmarking and optimizing things. The answer is different for every part of Bun, but one general theme: Zig's low-level control over memory and lack of hidden control flow makes it much simpler to write fast software.

With modern hardware, accessing memory efficiently is key to writing fast software. Programs written in programming languages that don't let the developer control how data is laid out in memory usually face an uphill battle to be fast.

gnuvince··on Ask HN: How to level up your technical writing?
Haven't read it, but my reaction to the 2 minute video is "excrement" [1].

[1] https://www.youtube.com/watch?v=LjHORRHXtyI

gnuvince··on The Typography of Legal Opinions
The outrage is two-fold. First, this is removing a right that used to be guaranteed for 50 years and had been reaffirmed, by the Supreme Court. With the stroke of a pen, 6 judges removed a protection that more than 2/3 of citizens support.

Second, the justification is inconsistent with other decisions. E.g., the majority argues that it's up to the States to decide their own laws on the matter of abortion, but just the day before, the same majority found that New York could not decide its own laws on concealed carry. You mention that searching for "abortion" in the text of the U.S. Constitution find nothing: you'll also find nothing about concealed carry.

gnuvince··on How safe is Zig?
Rust has been my primary language for the past 5 years, but it's moving in a direction that gets it farther away from my own values about what software ought to be like. As more features are added to the language, the ways they interact with each other increases the overall complexity of the language and it becomes hard to keep up.

I really like the safety guarantees that Rust provides and I want to keep enjoying them, but the language -- and more importantly, its ecosystem -- is moving from something that was relatively simple to a weird mish-mash of C++, JavaScript, and Haskell, and I'm keeping an eye out for a possible escape hatch.

Zig, Odin, or Hare are not on the same plane of existence as Rust when it comes to out-of-the-box safety (or, at the moment, out-of-the-box suitability for writing production-grade software), but they are simpler and intend to remain that way. That really jives with my values. Yes, this means that some of the complexity of writing software is pushed back onto me, the programmer, but I feel that I have a better shot at writing good software with a simple language than with a complex language where I only superficially understand the features.

gnuvince··on Writing like a pro with Vale and Neovim
A post about writing means that I need to plug a couple talks by Larry McEnerney. [1,2]

The tool described in this blog post is all about text-based rules: what the _text_ ought to look like. To improve your own writing (a) learn who your readers are, (b) know what they value, and (c) write so that as readers, they find your work valuable to them.

[1] https://youtu.be/vtIzMaLkCaM [2] https://youtu.be/aFwVf5a3pZM

← PreviousPage 2 of 20Next →