logoalt Hacker News

spacechild106/16/20250 repliesview on HN

First, thanks for providing SumataraPDF as free software! I don't want to disparage your software in any way. I don't really care how it's written as long as it works well - and it does! This is really just about your blog post.

> I just looked and out of 35 uses of MkFunc0 only about 3 (related to running a thread) allocate the args.

In that case, std::function wouldn't allocate either.

> All others use a pointer to an object that exists anyway. For example, I have a class MyWindow with a button. A click callback would have MyWindow* as an argument because that's the data needed to perform that action. That's the case for all UI widgets and they are majority uses of callbacks.

That's what I would have guessed. Either way, I would just use std::bind or a little lambda:

    struct MyWindow { void onButtonClicked(); };

    // old-school: std::bind
    setCallback(std::bind(&MyWindow::onButtonClicked, window));

    // modern: a simple lambda
    setCallback([window]() { window->onButtonClicked(); });
If your app crashes in MyWindow::onButtonClicked, that method would be on the top of the stack trace. IIUC this was your original concern. Most of your other points are just speculation. (The compile time argument technically holds, but I'm not sure to which extend it really shows in practice. Again, I would need some numbers.)

> I know things because I've been programming, learning, benchmarking for 30 years.

Thinking that one "knows things" is dangerous. Things change and what we once learned might have become outdated or even wrong.

> I know that using 16 bytes instead of 64 bytes is faster. And I know that likely it won't be captured by a microbenchmark.

Well, not necessarily. If you don't allocate any capture data, then your solution will win. Otherwise it might actually perform worse. In your blog post, you just claimed that your solution is faster overall, without providing any evidence.

Side note: I'm a bit surprised that std::function takes up 64 bytes in 64-bit MSVC, but I can confirm that it's true! With 64-bit GCC and Clang it's 32 bytes, which I find more reasonable.

> And even if it was, the difference would be miniscule.

That's what I would think as well. Personally, I wouldn't even bother with the performance of a callback function wrapper in a UI application. It just won't make a difference.

> But I know that if I do many optimizations like that, it'll add up even if each individual optimization seems not worth it.

Amdahl's law still holds. You need to optimize the parts that actually matter. It doesn't mean you should be careless, but we need to keep things in perspective. (I would care if this was called hundreds or thousands of times within a few milliseconds, like in a realtime audio application, but this is not the case here.)

To be fair, in your blog post you do concede that std::function has overall better ergonomics, but I still think you are vastly overselling the upsides of your solution.