Why you shouldn’t mourn the removal of –, ++ and C-style for loops from Swift

One of the neatest things about Swift going open-source earlier this year is that the deliberation process for the future of the language, including breaking changes to the syntax, is out in the open. Case in point are the two accepted proposals to remove the unary -- and ++ operators and to remove C-style for loops.

The case against — and ++

View the proposal.

Chris Lattner, the principle architect of Swift, has stated in the past that the ++ and -- operators were added very early in Swift’s inception simply because Objective-C had them. Now that Swift has had a chance to mature, there are a few factors which indicate they are a poor fit for the language. First and foremost is that they are confusing as hell to programmers who haven’t already spent time banging their heads against them in one of the C-derived programming languages. Consider this case:

The trailing versions of these operators are particularly confusing, where the value is being returned prior to being changed. This difference in pre- and post-incrimenting of the variable is a particularly fruitful source of errors in code, with things like index values going out of range or holding unexpected values because the wrong operator was used.

The strongest case for keeping them is their brevity, but Swift does not favor brevity over security and, as Chris Lattner points out, the more expressive n += 1 is hardly an onerous amount of typing. The main use for the operators seems to be in C-style for loops (based on a survey of Swift-based GitHub projects). Thus, with the imminent removal of those for loops from the language, the main use-case for the operators will die with them.

The case against C-style for loops

View the proposal.

The C-style for loop, like the unary increment and decrement operators, were added early in Swift’s development simply because Objective-C had them. As Erica Sadun so eloquently points out in her proposal, they’re a hold-over from an earlier era of programming and have a complex and error-prone syntax. They accomplish nothing which can’t be accomplished in a more succinct and expressive fashion using the Swift for in loop. Consider these two examples, both of which combine strings from an array to a base string and prints them out:

C-style for loop

Note that the for loop syntax is completely non-expressive. There’s no indication of what each of the “;”-separated fields aims to accomplish…you have to already be familiar with it.

Swift map() function

“But wait,” you might say, “I need the index value as well!” There are a couple of ways to do it in Swift without relying on C-style for loops:

Method 1: enumerate()
The handy enumerate() method is present on all collections conforming to SequenceType is one way:

Method 2: for-in over a Range

The 2nd method is stylistically closest to the C-style for loop, but it is still much easier to understand what values i will hold and isn’t subject the problem of a statement inside the for loop modifying the index and causing it to go out of bounds (i is constant).

Conclusion

It can feel a little jarring to lose language features, but with some thought it is clear to see that the removal of these 2 features will result in a language that is more expressive and less error prone.

Don’t use Swift enums to contain magic strings!

At first glance, using a Swift enum with a raw type of String seems to be a great way to package (or, if you like, enumerate) magic strings used by things like Notifications:

However, this is a poor application of the Swift enum for the following reason: you are not interested in the enum case, only its raw value. Any place you want to use the magic string in your code you’re forced into fully qualifying the enum case (because the argument type is a string, not the type of your enum) and then accessing the rawValue property.

A better approach is to use a Swift struct with static constant string members defining the magic strings:

The look is very similar to an enum, but in practice it ends up being shorter and cleaner to use:

Now, this argument is moot if you have a situation where methods in your classes take your enum type as an argument and use the rawValue at some point internally, but for things like userInfo dictionary keys, user defaults keys, notification names, segue names, etc. you are better off with the struct approach, since the string is all you’re interested in.

2015-12-16 Addendum:
As with any advice on using Swift, this should not be viewed as an Immutable Truth of the Universe™. There are still situations when an enum would be a perfectly reasonable container for your strings: namely, when you have a model built around the use of the enums and not just the strings they contain.

Better mogenerator Swift Templates

It finally happened that Core Data was required for one of my Swift 2 projects, so naturally I turned to mogenerator to produce my human and machine NSManagedObject subclasses. However, I was unsatisfied with the results of the machine file…particularly, the tendency of the template to clutter up the global namespace with enums for the attributes and relationships. Here’s the default template’s output for an entity named Category with a pair of attributes and one relationship.

As you can see, it creates a pair of public enums to enumerate the names of the attributes and relationships. This isn’t too bad for one or two entities, but gets annoying when you have dozens of entities, each adding 2-4 new global-level types.

Moreover, I have a problem with the use of the enum type. Yes, we are enumerating the possible attributes for this entity, but absolutely nothing in the Core Data framework will accept them; it’s purely string-based. As a result, anywhere you use the enum cases, you’ll have to tack on the .rawValue accessor to get the underlying string. I figured we could do better:

The way I chose to address the first issue is to move the declarations inside the class declaration for the entity. Since Swift supports name-spacing, this means that instead of typing “CategoryAttributes.id”, you’d type “Category.Attributes.id”. This is only 1 more character and it results in only “Category” being added to the global namespace.

The second change I made was to convert the enums to structs with each of the entries being a static let string. The structs are never meant to be instantiated, they simply provide a coherent namespace for our attribute and relationship names.

You can get the updated template files here: https://gist.github.com/JoshuaSullivan/2057f09cc18243a3f2df

More information about using custom mogenerator templates can be found in this Stack Overflow post.