TIL: Typed do in Swift

TL;DR: Swift has do throws(MyError). It's helpful.

This is one of those "I can't believe I had missed that" things.

I've been pretty enthusiastic about adopting typed throws in Swift. If you need to process certain kinds of errors, it just makes sense to me. However, it was always a bit painful. You have this:

do {
    // throwing code here
} catch {
    // error is precisely typed here, assuming
    // the block above throws just one type
}

… and all is fine and good, except that the "throwing code" doesn't need to grow particularly complex before Swift decides to widen the type to any Error and your catch block starts producing compilation errors.

When I ran into this, I'd use catch let error as MyError. Fine. Except it isn't, because now your error-handling code is incomplete: you have to add an unreachable catch-all block, and you're unhappy with the language and your life choices.

I did page through the enhancement proposal when it passed through Swift Evolution, but I just never noticed that it doesn't end there. What you do in this situation is this:

do throws(MyError) {
    // throwing code here
} catch {
    // now the compiler doesn't get confused and
    // all is well-typed unicorns and sunshine
}

Now you know too.

Updating multiple rows with SQL and avoiding collisions

I ran into an interesting problem with SQL the other day: how do you update multiple rows while maintaining an uniqueness constraint?

I have a table where each row describes an item in an ordered list. Each row has a position value. They are integers, not necessarily contiguous but each unique. A larger position means the row is further down the list. For reordering the rows, I sometimes need to make space between two positions.

How do you do that? Well, the obvious answer is a simple update statement, assuming you want to make space for one item before position 5:

UPDATE table
SET position = position + 1
WHERE position >= 5

Despite having used SQL since the 90s I don't think I've ever needed to do this before. It seemed simple enough, but I found out the solution I went with is not only obvious but also wrong. When you have contiguous position values, that statement causes a unique constraint violation, in both SQLite and PostgreSQL. Having transaction isolation doesn't prevent collisions during updates, even if the end state would be valid.

A helpful LLM tried to suggest the broken solution, then a solution that caused a syntax error and then a solution that involved creating a temporary table. After that I went back to searching the web and finally found a mention about negating the values temporarily which sounded like way less hassle than temporary tables.

That worked great. So, to add space for N items before position X:

  1. Begin transaction.
  2. Instead of incrementing the value on each row greater than or equal to X by N, multiply the value by -1 and decrement it by N.
  3. Multiply each value smaller than zero by -1.
  4. Commit.
BEGIN TRANSACTION;

UPDATE table
SET position = -position - 1
WHERE position >= 5;

UPDATE table
SET position = -position
WHERE position < 0;

COMMIT;

New Swift Package: tui-fuzzy-finder

Speaking of new Swift libraries, I released another one: tui-fuzzy-finder is a terminal UI library for Swift that provides an incremental search and selection UI that imitates the core functionality of fzf very closely.

I have a ton of scripts that wrap fzf. Some of them try to provide some kind of command line interface with options. Most of them work with pipes where I fetch data from somewhere, parse it with jq, feed it fzf, use the selection again as a part of a parameter for something else, etc. It's all great, except that I really don't love shell scripting.

With tui-fuzzy-finder I want to be able to write tools like that in a language I do actually enjoy a great deal. The package provides both a command line tool and a library, but the purpose of the command line tool is just to allow me to test the library, as writing automatic tests for terminal control is difficult. Competing with fzf in the general purpose CLI tool space is a non-goal.

I haven't implemented the preview features of fzf, nor key binding configuration. I'm not ruling either of those out, but I have not needed them yet and don't plan to work on them before a need arises.

Documentation at Swift Package Index.

© Juri Pakaste 2026