Unify Type Properties and Methods
When I first learned that Swift use different keywords for type properties and methods for classes and structures, I was unhappy. Obviously, I was not alone:
Then why even use static/class at all? Why not invent a new keyword that makes sense for both types?
The current syntax is definitely confusing. There are two keywords, both essentially mean the same thing to the programmer (although their implementations vary based on whether they are part of an inheritable type). Surely the language, as a means of expression, should abstract the implementation difference away from the programmer under a single expressive concept of a function belonging to the type itself rather than an instance of the type.
The language designer gave an explanation:
We considered unifying the syntax (e.g. using “type” as the keyword), but that doesn’t actually simply things. The keywords “class” and “static” are good for familiarity and are quite descriptive (once you understand how + methods work), and open the door for potentially adding truly static methods to classes. The primary weirdness of this model is that protocols have to pick a keyword (and we chose “class”), but on balance it is the right tradeoff.
I was not convinced so I filed an radar.
Months has passed by and Swift has improved a lot as the version number has reached 1.2.
I think it is time for me to look into it again now that WWDC is approaching. I’m expecting a major new version of Swift and decided to warm myself up to prepare to use it in real projects for iOS 9.
Much to my delight, I found that in Swift 1.2 classes also use “static” to define type properties and methods. Though I think “static” is not as good as “type” as the keyword, the unification of “static” and “class” is exactly what I hope for.
Except that it is not exactly what I hope for, as it turned out later.
As I was verifying new features with some old code, I saw a strange error message for defining type properties using keyword “class”:
error: class stored properties not yet supported in classes; did you mean ‘static’?
My first thought was: oh, they forgot to update the error message, which now should be simply a syntax error since ‘static’ wins out as the chosen keyword.
I reported this finding to one of the Swift language developers I follow on Twitter, also to express my appreciation of their good work:
But this error message should be improved accordingly. @UINT_MIN pic.twitter.com/hH1hJrBAsg
— an0 (@an0) April 3, 2015
To my surprise, I was told that things are not what I thought:
@an0 Note that class computed properties are overridable.
— Jordan Rose (@UINT_MIN) April 3, 2015
@an0 You could write "class var" even in 1.1; it just had to be computed. "static var" (new) can be computed or stored, but not overridden.
— Jordan Rose (@UINT_MIN) April 3, 2015
@an0 Kinda. In the common case (no subclassing), may as well stick to static. "class" = static but non-final (for both props and methods).
— Jordan Rose (@UINT_MIN) April 3, 2015
@an0 Don't want to get into design discussions here; trust me that we considered many alternatives. :-)
— Jordan Rose (@UINT_MIN) April 4, 2015
As I said, I think the coexistence of ‘static’ and ‘class’ is confusing. Especially so now that classes can also use ‘static’ to define type properties and methods.
And do we really need “class instance variables”? To be honest, it is my first time hearing of such a concept, and I’ve never once felt the need of one during my 8-year career as a C, C++, Objective-C and Python programmer.
Of course, we can find some use cases of if, just like anything else. But are they corner cases or common cases? I believe they are corner cases, otherwise it should be a popular feature in many more OO languages and most of us should feel the missing of it at least once in a while.
More importantly, what does it cost to support such a feature? Is its usefulness worth its cost? I definitely don’t think so because it brings so much confusion with so limited use.
Besides, Swift already has the mechanisms to partially implement “class instance variables” — we just need to make type properties overridable:
class Foo {
static var typeProp = 1
}
class Bar: Foo {
override static var typeProp: Int {
// Now Bar has its own version of typeProp.
get {
}
set {
}
}
}
Sadly, in Swift 1.2, static properties and methods are final. Its confusingly similar sibling, class properties and methods, support overriding. However, class properties can only be calculated properties.
Now, suppose that class stored properties are introduced in future, we’ll then have static stored or calculated properties which are final, class stored properties which behave like “class instance variables”, and class calculated properties which are overridable. Such a future feels not right to me.
Do we need to use “static” VS “class” to differentiate “final” from “overridable”? Don’t we already have a keyword “final”?
I really appreciate Swift’s continuous improvement and its team’s good effort. I believe they consider every alternative they can think of for every design decision. But in case there are some possibilities that initially eluded them, we should feedback honest critics and contribute constructive external ideas, because we care.
So here are my ideas about type properties and methods:
- Use a unified keyword “type”, for both type properties and methods, for both structures and classes, also for protocols. It is descriptive and clear. Don’t use “static” or “class” because “good for familiarity” is not good enough, not to mention the original decision to use “static” for class members in C++ was not a good one itself.
- Type properties and methods are overridable by default, and use “final” keyword to make them final, just like instance properties and methods.
- Type properties can be stored or calculated, just like instance properties.
More discussions can be found on devforums.