HNHacker News
TopNewBestAskShowJobs

nh2

3,663 karma · joined March 29, 2014

https://github.com/nh2

[ my public key: https://keybase.io/nh2; my proof: https://keybase.io/nh2/sigs/Duv6hcXOkjZU5KWzJ8d01yeD7QKmhG9QpVMOb4ZMkeU ]

submissionscomments
nh2··on PipePipe: NewPipe hard fork implementing SponsorBlock
> Set a sleep timer for bedtime listening

Killer feature!

nh2··on Writing Parquet files using Haskell
There are companies like IOHK or Mercury that hired large swathes (50?) of Haskell programmers in relatively short time, so I don't think bus factor of the programmer market is an issue. Of course it's still an issue if a company hires 1 or 2 Haskell devs only, and those depart.

> from the past three years [..] the latest I’ve seen were Opus-4.6 and GPT-5.5 struggle a lot with standard GHC Haskell

If your experience is from years ago, I totally get that. For my standards, LLMs were pretty bad before 2026.

I haven't tried any serious LLM Haskell before 2026-02, because it was just not a timesaver.

I had good experiences with Opus-4.6 already on Haskell, such as it having detail knowledge on async exceptions, allowing it to immediately pinpoint difficult bugs that me and other experts missed, e.g. https://github.com/snoyberg/conduit/pull/530

But most of my experience is from Opus >= 4.8. I found it excellent at writing difficult TemplateHaskell and Generics implementations, such as oneshotting Postgres JsonPath queries derived from lens-like field accessors on Haskell types.

Note it's still not great at writing general high-quality "engineering" stuff, e.g. Opus 5.0 writes functions that refer to things out of their scope, such as:

    requireFooOr400 :: MyMonad m => Maybe Foo -> m Foo
    requireFooOr400 x = case x of
      Nothing -> throwHttp400 "Cannot perform [very specific action from the caller]: the inputs have no foo"
      Just foo -> return foo
However, that's not a lack of Haskell understanding, and it does that for all languages, e.g. in Python it keeps writing implementation details into API docstrings instead of function body comments.
nh2··on Show HN: Avoid smooth spinners, use low-FPS spinners
> I’ve only ever heard non-frontend developers call them “spinners”

Such as these non-frontend devs?

https://getbootstrap.com/docs/5.3/components/spinners/

nh2··on Show HN: Avoid smooth spinners, use low-FPS spinners
Probably no.

Does "Square ring" really look jerky/retro?

nh2··on Show HN: Avoid smooth spinners, use low-FPS spinners
I'm not describing anything about screen refresh rates, which I'm pretty sure are 60 Hz on my laptop even when the CPU+GPU are at 0% and don't draw anything. Compute != monitor refresh.
nh2··on Show HN: Avoid smooth spinners, use low-FPS spinners
The damage tracking doesn't seem to be effective at reducing the computational cost. Measurement:

Opening https://nh2.me/low-fps-spinners/smooth-spinner.html it doesn't matter if I zoom the spinner to 25% or 500%: Despite the 400x difference in pixels redrawn, the "GPU Process" CPU usage in the "Browser" tab of the Chromium Shift+Esc task manager is equally high.

It only scales down the cost when reducing the FPS.

nh2··on Show HN: Avoid smooth spinners, use low-FPS spinners
But it does. The GPU rerenders your entire screen with all its pixels, even if you change only one. The only thing you can do to avoid that is to not ask the GPU to render a frame. For that you need to reduce FPS.
nh2··on Show HN: Avoid smooth spinners, use low-FPS spinners
Avoiding unnecessary browser repaint of the rest of the page is a basic technique and often already done correctly. If people don't do that, it's just ultra-bad.

But do really have the CPU/GPU go idle, you need to not use them; the only solution to that is to show still images, aka reduce FPS.

nh2··on Writing Parquet files using Haskell
Hiring for Haskell is very easy, unless you need to hire more than 100 people on the spot, or don't offer remote. I've been doing Haskell hiring for 10 years, with more than 50 interviews, the applicants are always great, each time we had to pick the best of multiple candidates.

Cannot confirm functional programming being inefficient token-wise, or worse at being generated than other paradigms. Claude is great at Haskell.

The difficult parts about Haskell, such as understanding type checker error messages, are gone thanks to LLMs.

Type-safe, side-effect free code degrades correctness a lot less under heavy LLM action in my experience.

nh2··on Show HN: Avoid smooth spinners, use low-FPS spinners
I don't think so. This is just what happens when you redraw the screen.

Doing it 30x more frequent than needed costs more, no matter if it's only 1 pixel.

This problem is not isolated to me or to just one machine. Check out the chromium bug about the tab loading spinner, for example. It is a "simple" spinner as well.

Or the Zed editor, which spams screen redraws even when nothing changes at all, so it has high GPU usage for still picture.

nh2··on C++26: Trivial infinite loops are no longer undefined behaviour
Of course the infinite loop should run as expected.

It breaks the most fundamental debugging expectations (such as "delete code until problem disappears") if the fundamental, minimal building blocks of a language, when on their own, do random rubbish.

To understand a program that does something, better first understand a program that does nothing.

As a fan of sensible analogies:

You put a salad bowl with vinegar into the fridge and notice that when you do that, the fridge stinks afterwards. You try again without the vinegar, then without the salad. In C++ world, upon receiving the empty bowl, the fridge detonates ("it is not useful"), blowing up your house. That is not OK.

nh2··on Jemalloc 5.4.0
Generally yes, but the wording of "instantly" begs for the following pedantic remark:

This is controlled by jemalloc settings `dirty_decay_ms`, `muzzy_decay_ms`, and their interaction with `background_thread`.

`dirty_decay_ms` currently defaults to 10 seconds, so it's not that instant.

That is important e.g. for single-threaded programs that start other programs, such as my Python example: If it starts a subprocess before the 10 seconds elapse after `free()`, Python (and jemalloc) do not run, and get no chance to return memory to the OS.

In such cases, either enable `background_thread`, or set the `_decay_` values to `0` to ensure immediate return to the OS upon `free()`. (This costs some performance.)

See e.g. https://github.com/jemalloc/jemalloc/issues/2688

nh2··on Jemalloc 5.4.0
Memory allocation behaviour has visible impact also for users of managed languages, and the behaviour of software for end users.

In our Python program, a bit of numpy processing of large pictures led to 100 GB not being returned to the OS by glibc's default allocator and the machine running out of memory shortly after. With jemalloc's reliable memory return settings, those problems disappear.

nh2··on Ubuntu 26.10 completes transition to Rust-based coreutils
The point is that such bugs shouldn't exist in the first place.

Using recursion on unbounded inputs on a programming language that doesn't support that (which are most) is an extremely classical mistake that really should be known to all programmers, especially those of low level languages that care about safety.

Every time you call something recursively you should be thinking "how deep is this?".

nh2··on The case against JPEG XL
Do you have an example comparison?
nh2··on Terpstra Keyboard
> oh, it seems that the lumatone is the commercialized version essentially

From the same makers or others?

On the website I can find no info whether this project is concluded or not.

nh2··on The creator of Jujutsu has joined ERSC
Thanks, the animation is gone now and the problems are gone as well.

Good choice in my opinion, as I hadn't even noticed the animation existed until I looked for something that might make the scrolling slow.

nh2··on The creator of Jujutsu has joined ERSC
This website has unbearable scroll performance on mobile.

Is it the animation at the top?

nh2··on Stripe said to abandon $50B pursuit of PayPal
Justified fear. A former flat mate of mine reported an unexpected outgoing transfer to his UK bank and they blocked his account for 3 months. He was essentially unbanked. He had to pay his rent in cash after getting it from an ATM with a credit card (which cost a lot extra and hit limits). Resolving it took months even though we lived right next to a branch of that bank, where he went every day.
nh2··on We found a division by zero bug in FFmpeg with a vibecoded fuzzer
In Haskell they are a little less annoying. It is just easier to reason about (including proving) pure functions.
nh2··on Maiao: Gerrit-style code review workflow for GitHub, GitLab, Gitea, others
Code review tools should really compare with reviewable.io, which supports proper review of every-commit in a PR, with force pushes, making sure all changes get read, and comment sign-off and disposition, making sure no comment remains unaddressed.

In contrast to Gerrit and Phabricator, it needs not "Change IDs" inserted in your commits (easier workflow just using git) and "just works" to review whole branches.

It seems to me that "1 PR = 1 commit = 1 review" and "stacked PRs" workflows are just workarounds for not properly having implemented that as Reviewable has. Am I not seeing something?

Reviewable's main drawback is being for Github only and not open source.

nh2··on Malicious Rust crate Arrayref runs a build-time payload
You have just reinvented "Safe Haskell" from 2012.

It guarantees that pure functions are pure.

https://www.microsoft.com/en-us/research/publication/safe-ha...

https://downloads.haskell.org/ghc/latest/docs/users_guide/ex...

nh2··on Stripe to Buy OpenRouter for $7B
> Within certain limits and certain models

For those that hadn't read yet (on https://aws.amazon.com/service-terms/):

"Certain models" means "only AWS's own trained models" (Nova etc), so not e.g. Bedrock Claude or GPT.

"Certain limits" means they don't defent if the input to the model is the IP.

nh2··on A Preview of DuckDB v2.0
If you merge PRs that have commit mesages like this, it's easy to arrive at 10000 commits in 6 months:

    rename to NodePointer instead
    format
    Revert "format"
    Revert "rename to NodePointer instead"
    rename to OptionalNodePtr
    woops
    update comment
    slot renames
    more renames
Source: https://github.com/duckdb/duckdb/pull/23605

If every Ctrl+S is a commit, it'll go up fast.

"woops"!

nh2··on Self hosted email continues to steeply decline
I agree Spam is the hardest. Setting up a mailserver is pretty easy today, e.g. with NixOS-simple-mailserver you can do it with a few lines and a few minutes of config in your DNS provider, and maintenance is minimal.

But I self-host email for ~20 years, and I have not managed to get rid of Spam without not also getting false positives.

I first used SpamAssistant, in later years Rspamd, but I feel like they are just not good enough. Also I find Rspamd config pretty incomprehensible.

Hosted email like also does not solve this, e.g. GMail filters way much (e.g. important company correspondence leading to orders almost being lost because they landed in our GMail spam, so I had to turn off the spam filter entirely).

nh2··on Self hosted email continues to steeply decline
Not in my experience.

My self-hosted email filters too little spam, while GMail etc filter too much (e.g. important company correspondence leading to orders almost being lost because they landed in our GMail spam).

nh2··on Delta
Are you sure you aren't off by 20 years and referring to "Archon Mode" introduced to Starcraft 2 in 2015?

https://news.blizzard.com/en-us/article/19940901/teaming-up-...

nh2··on Zig's Incremental Compilation Internals
Can you point at what you mean?

If you changed a function implementation in the libc crate, not changing that function's signature, how much codegen would happen in downstream packages?

The maximally recompilation-avoiding effect would be: Only that one function gets codegenned. Everything else just gets relinked into their final executable or .so.

nh2··on Zig's Incremental Compilation Internals
10 years ago, I commented on the Rust issue for "Incremental recompilation", where it was suggested that Rust could at least adopt Haskell GHC's model of incrementality, which is currently file-level:

https://github.com/rust-lang/rust/issues/2369#issuecomment-1...

This would already help a lot.

I recommend anybody who's interested in incremental recompilation to read what GHC does, because the effort to achieve that is relatively low.

Of course there's always desire for more:

GHC currently needs to parse+typecheck+codegen a file before it can process other files that import it. Codegen is slow. Thus, there's currently demand split compilation into "stages", so that the next file can be typechecked after its imports have been just typechecked (not codegenned).

I would also enjoy if recompilation avoidance were to happen at the function level, not the file level.

Macro systems are a key language feature that can destroy incremental recompilation. In theory, Haskell is well set up for that, as its macro system (TemplateHaskell) is fully AST based and _theoretically_ could distinguish "fully pure" macros from side-effectful macros (such as splicing the current git commit in as a string literal). But the recompilation avoidance system does not currently exploit such differences.

nh2··on Decathlon Germany adds Wero payment option to decathlon.de website
Im a German with a German Postbank account, living in Switzerland.

Wero app Play Store page: "This item isn't available in your country."

Hard to cheer for a thing when it prevents you to access your own money, and promises to "easily pay" immediately fall flat.

Paypal is bad but at least it doesn't fail at step 0.

← PreviousPage 2 of 26Next →