Swift Regret: Bound Methods
Swift Regret: bound methods. You know, saying something like `object.action` without calling it. This isn’t some grand mistake, just a feature that’s turned out to be less useful and more problematic than anticipated.
— Jordan Rose (@UINT_MIN) September 8, 2021
Part of the Swift Regrets series.
“Bound methods” refers to saying something like object.action
without calling it. This isn’t some grand mistake, just a feature that’s turned out to be less useful and more problematic than anticipated.
There are a few problems with this. One of them is that Swift supports overloading, so .action
might be ambiguous. You can control type-based overloading with additional type context, and name-based by using full names (append(_:)
vs. append(contentsOf:)
). Personally I think that during the move to “full names”, we should have deprecated base-name-only method references, but we didn’t have a good syntax for no-argument methods.
Still, even setting that aside, we still have problems. If you use this syntax with an object (class instance), well, now you’ve got a function value you can use anywhere. So the object must’ve been captured. Strongly? Weakly? unowned
? We went with strong
because it doesn’t crash or silently fail, but…that’s probably too subtle. And if you use it with a value type, it doesn’t work with mutating
methods. Because, uh, when does the mutation start? How does it write the value back? In this case we just disallowed it rather than come up with some implicit behavior.
So, what do I recommend? Just use a closure! It’s more verbose, but again, clarity over brevity. You can control capturing behavior, and mutation is well-defined. And adding new name-based overloads can’t cause problems. I know some people write instance methods specifically to be callbacks, and writing out a forwarding closure feels redundant. But if we didn’t have this feature, I don’t think that would be reason enough to add it.
I still think requiring full names is a good idea though.