Passing raw boolean literals as positional args like createUser(user, true, false) creates “boolean blindness” that forces readers to jump to function definitions constantly.
Key Takeaways
createUser(user, { isAdmin: true, sendWelcomeEmail: false }) replaces positional booleans with self-documenting options objects at minimal cost.
If a boolean arg really means “create an admin,” split into createAdminUser(user) and createRegularUser(user) – the flag was hiding two actions.
TypeScript types confirm values are booleans but don’t tell you what they mean; named options objects solve the actual problem.
Single obvious-context bools like toggleMenu(true) are fine; readability drops fast once a second boolean appears.
Inline variable naming (const isAdmin = true; createUser(user, isAdmin, sendWelcomeEmail)) is a lightweight alternative without restructuring the API.
Hacker News Comment Review
Commenters converged on named/labeled arguments as the real fix: OCaml has had ~isAdmin:true syntax for decades, Kotlin supports foo(bar=zaz), and JS devs are reinventing this with options objects.
The C bitmask pattern (createUser(user, ADMIN | SENDMAIL)) was raised as a more concise alternative to verbose options objects, with tradeoffs around discoverability.
There is mild pushback that this is well-trodden ground covered by “boolean trap” and “boolean blindness” literature, with Google’s “Avoid the Long Parameter List” post cited directly.
Notable Comments
@PaulKeeble: argues C-style bitmask flags offer more concision than options objects while still being readable, questioning whether verbosity is worth it.
@esafak: notes linters can enforce named-argument use specifically for booleans in languages like Kotlin, making this enforceable policy rather than just convention.