Swift Regret: Subscript Argument Label Rules

Part of the Swift Regrets series.

I bet a lot of people don’t know how flexible subscripts are in Swift. The reason they’re declared with function—like syntax is because the index part really is a parameter list. You can have labels. Multiple params. Zero params, even. But if you want labels, you have to say so explicitly:

subscript(at path: String)

even if the label is the same as the argument name:

subscript(path path: String)

which is different from function and initializer arguments. Why are subscripts different in this way?

Well, back before Swift 3, all three types of argument lists were different:

  • Initializers had all arguments labeled by default.
  • Functions had all arguments except the first labeled by default.
  • Subscripts had no arguments labeled by default.

This matched the most common way each member showed up in APIs imported from Objective-C: init methods with the selector parts mapped to argument labels; regular methods with the first selector piece serving as the base name; and single-argument unlabeled subscripts.

But the rule for functions felt weird, and that was exacerbated when Swift’s current preposition-heavy naming conventions were settled on in Swift 3. Even imported methods had first-arg labels now. So functions changed to match initializers in SE-0046. And subscripts…were not changed. The most common subscripts by far are still unlabeled single-argument ones. But you also use members a lot more than you write them, and consistency across all three members with argument lists would have been better, in my opinion.