🔗 An annoying aspect of Lua’s if-based error checking
Lua does not have error checking/propagation primitives (like `?` or `!` operators in newer languages). The usual convention is to use plain old `if` statements:
local ok, err = do_something() if err then return nil, err end
So any call that propagates an error ends up at least 4 lines long. This has an impact on the programmer’s “threshold” for deciding that something is worth refactoring into a function as opposed to programming-by-copy-and-paste.
(An aside: I know that in recent years it has been trendy to defend copy-and-paste programming as a knee-jerk response against Architecture Astronauts who don’t know the difference between abstraction and indirection layers — maybe a topic for another blog post? — but, like the Astronauts who went too far in one direction by following a mantra without understanding the principles, the copy-pasters are now too far in the other direction, leading to lots of boilerplate code that looks like productivity but can pile up into a mess.)
So, today I had a bit of code that looked like this:
local gpg = cfg.variables.GPG local gpg_ok, err = fs.is_tool_available(gpg, "gpg") if not gpg_ok then return nil, err end
When I had to do the same thing in another function, the immediate reaction was to try to turn this into a nice five-line function and just `local gpg = get_gpg()` in both places. However, when we account to error checking, this would end up amounting to:
local function get_gpg() local gpg = cfg.variables.GPG local gpg_ok, err = fs.is_tool_available(gpg, "gpg") if not gpg_ok then return nil, err end return gpg end local function foo(...) local gpg, err = get_gpg() if not gpg then return nil, err end ... end local function bar(...) local gpg, err = get_gpg() if not gpg then return nil, err end ... end
where as the “copy-paste” version would look like:
local function foo(...) local gpg = cfg.variables.GPG local gpg_ok, err = fs.is_tool_available(gpg, "gpg") if not gpg_ok then return nil, err end ... end local function bar(...) local gpg = cfg.variables.GPG local gpg_ok, err = fs.is_tool_available(gpg, "gpg") if not gpg_ok then return nil, err end ... end
It is measurably less code. But it spreads the dependency on the external `cfg` and `fs` modules in two places, and adds two bits of code must remain in sync. So the shorter version is less maintainable, or in other words, more bug-prone in the long run.
It is unfortunate that overly verbose error handling drives the programmer towards the worse choice software-engineering-wise.
Follow
🐘 Mastodon ▪ RSS (English), RSS (português), RSS (todos / all)
Last 10 entries
- There are two very different things called "package managers"
- Last day at Kong
- A Special Hand
- How to change the nmtui background color
- Receita de Best Pancakes
- That time I almost added Tetris to htop
- Receita de Orange Chicken
- Receita de frango empanado no panko
- Receita de cebola caramelizada
- Receita rápida de crepe