🎄 If you’re planning to do Advent of Code this year, join The Coder Cafe leaderboard: 261108-ab921387. I’ll find a few prizes for the winner(s). If you’re new to Advent of Code, I wrote a short introduction last year, and I also wrote a blog post called I Completed All 8 Advents of Code in One Go: Here Are the Lessons I Learned if you’re interested. I’ve also created a custom channel in the Discord channel.
☕ Welcome to The Coder Cafe! Today, we discuss a recent comment from Linus Torvalds about the use of a helper function. Get cozy, grab a coffee, and let’s begin!
In August 2025, there was (yet another) drama involving Linus Torvalds replying on a pull request:
No. This is garbage and it came in too late. I asked for early pull requests because I’m traveling, and if you can’t follow that rule, at least make the pull requests good.
This adds various garbage that isn’t RISC-V specific to generic header files.
And by “garbage” I really mean it. This is stuff that nobody should ever send me, never mind late in a merge window.
Like this crazy and pointless make_u32_from_two_u16() “helper”.
That thing makes the world actively a worse place to live. It’s useless garbage that makes any user incomprehensible, and actively WORSE than not using that stupid “helper”.
If you write the code out as “(a << 16) + b”, you know what it does and which is the high word. Maybe you need to add a cast to make sure that ‘b’ doesn’t have high bits that pollutes the end result, so maybe it’s not going to be exactly pretty, but it’s not going to be wrong and incomprehensible either.
In contrast, if you write make_u32_from_two_u16(a,b) you have not a f^%$ing clue what the word order is. IOW, you just made things WORSE, and you added that “helper” to a generic non-RISC-V file where people are apparently supposed to use it to make other code worse too.
So no. Things like this need to get bent. It does not go into generic header files, and it damn well does not happen late in the merge window.
Let’s not discuss the rudeness of this comment (it’s atrocious). Instead, let’s focus on the content itself.
, a popular newsletter, wrote a post about it:the main point Linus makes here is that good code optimizes for reducing cognitive load. {…] Humans have limited working memory capacity - let’s say the human brain can only store 4-7 “chunks” at at time. Each abstraction or helper function costs a chunk slot. Each abstractions costs more tokens.
I share the view that good code optimizes for reducing cognitive load1, but I don’t understand Linus’s comment in exactly the same way.
Yes, Linus is virulent about the helper function, but in my opinion, his main argument isn’t simply that an abstraction costs a “chunk slot” as
mentioned; it’s rather that this isn’t the right abstraction.Here is the code added in the pull request:
/**
* make_u32_from_two_u16 - return u32 number by combining
* two u16 numbers.
* @hi: upper 16 bit number
* @lo: lower 16 bit number
*/
#define make_u32_from_two_u16(hi, lo) (((u32)(hi) << 16) | (u32)(lo))This macro builds a 32-bit integer by putting one 16-bit value in the high half and the other in the low half. For example:
hi = 1010101111001101
lo = 0001001000110100
result = 10101011110011010001001000110100
|--------------||--------------|
hi loThe main problem with this macro isn’t necessarily that it exists. It’s that its intent (meaning what it tries to accomplish) could have been clearer.
Indeed, the helper’s name doesn’t tell which word is high and which one is low and that’s exactly what Linus is calling out with “you have not a f^%$ing clue what the word order is”.
Because we can’t get the intent from the name (make_u32_from_two_u16), we have to open the macro to understand the order. That’s precisely why it costs a “chunk slot.”: not because the abstraction exists, but because it’s an ambiguous one.
If we wanted to keep using a macro, a better approach, in my opinion2, would be to encode the word order in the name itself (msw = most significant word, lsw = least significant word):
/**
* make_u32_from_msw_lsw - return u32 number by combining
* two u16 numbers in msw:lsw word order.
* @msw: upper 16 bit number
* @lsw lower 16 bit number
*/
#define make_u32_from_msw_lsw(msw, lsw) (((u32)(msw) << 16) | (u32)(lsw))In this case, the word order is carried by the macro name, which makes it a clearer abstraction. Reading the call site doesn’t require opening the macro to understand the word order:
u32 v = make_u32_from_msw_lsw(0xABCD, 0x1234);Such an abstraction doesn’t cost a “chunk slot” in terms of cognitive load. Its intent is clear from the name, so we don’t need to load an extra piece of information into our working memory to understand it.
In summary, if we want to optimize for cognitive load, there’s not necessarily an issue with using helper functions. But if we do, we should make the abstraction as explicit as possible, and that starts with a clear function name that conveys what it tries to accomplish.
Resources
More From the Programming Category
Sources
Re: [GIT PULL] RISC-V Patches for the 6.17 Merge Window, Part 1 - Linus Torvalds // The discussion.
GitHub // The code proposed in the pull request
Explore Further
Linus and the two youts // Interestingly, the macro was plain wrong when the second word was negative. The full explanation is here.
❤️ If you enjoyed this post, please hit the like button.
💬 Where do you draw the line between “helpful” and “harmful” abstraction?
At least most of the time. Sometimes we must optimize for performance at the expense of cognitive load.
Mr Torvalds, if you see this and you disagree, please do not insult me.




