Wednesday, October 11, 2023

Rescuing Files From Classic Mac OS...with Swift

Jordan Rose:

The biggest benefits of doing this project in Swift are very similar to what the benefits would have been for using C++, back in the 90s, but with even more safety. Take directory walking. In C, this looks something like the following:

FSIterator *iter;
OSStatus err = FSOpenIterator(&directory, kFSIterateFlat, &iter);
if (err != noErr) { return err; }
// use iter
FSCloseIterator(iter); // hopefully no early exits!

But in Swift, without wrapping this API at all…

var iter: FSIterator? = nil
try FSOpenIterator(&directory, .init(kFSIterateFlat), &iter).check()
defer { FSCloseIterator(iter) }

Is it shorter? Not much. Is it nicer? Absolutely! First off, we have defer to ensure no resources are leaked even if there’s an early-exit later in the function. But it’s that throwing check() method that really changes the game.

1 Comment RSS · Twitter · Mastodon

Color me a little skeptical about the latter being nicer.

Ensuring all possible code paths lead to a valid final state when you have exceptions littered through the code it virtually impossible.

You'd need some for of `defer` for every change of state through the function and missing some of those or not thinking enough about the consequences of partial operation is just as likely to cause problems as the early return.

Personally, I'd go with:

FSIterator *iter;
OSStatus err = FSOpenIterator(&directory, kFSIterateFlat, &iter);
if ( err == noErr ) {
// use iter
FSCloseIterator(iter); // no early exits!
}
return err;

Leave a Comment