Properties vs. methods

· 4 minute read

Here’s a potentially controversial thought that keeps coming back to me as I spend more and more time developing in Swift: I don’t think that properties should be part of a type’s public interface.

The Swift Programming Language states that “Properties associate values with a particular class, structure, or enumeration.” This is all well and good, since associating types with values is not functionality that could otherwise be provided by methods alone. I certainly don’t have a problem with using properties to implement a type. I’m solely bothered by this implementation detail subsequently leaking out into a type’s API. Let’s take a look at an excerpt from String’s public interface:

public struct String {
  public var lowercaseString: String { get }
}

From this, a caller knows that stringInstance.lowercaseString can be called without parentheses. On the other hand, the standard library authors could’ve just as easily implemented String as follows:

public struct String {
  public func lowercaseString() -> String
}

In which case, we’d call stringInstance.lowercaseString() to achieve the same result. But why on Earth should a caller need to concern themselves with this distinction?

Over the years, I’ve heard many variations on the following: properties are for accessing instance variables, while methods are for performing actions. I have two major problems with this line of thinking:

  • If properties are for accessing instance variables, having them be part of a class’s public API provides unnecessary transparency into how that class is implemented, violating encapsulation.
  • We all know full well that properties aren’t just for accessing instance variables. Computed properties were and are commonly used in Objective-C. Swift even perpetuates this further by providing first-class language support for them1.

While Swift eschewed Objective-C’s brackets in favor of dot-syntax for everything, it didn’t actually shake having different invocation syntaxes for properties and methods. I wish it had.

Consistency when calling a property accessor or a method would be beneficial for other reasons as well. Every zero-argument method could be implemented as a property, but adding an argument would then change the call site from foo.bar to foo.bar(argument: baz) instead of from foo.bar() to foo.bar(argument: baz). Isn’t that kind of weird?

Instance methods can also be curried, and in fact, are already curried class methods. You can get a handle to them as follows:

struct SomeType {
  func doSomething() {
      // ...
  }
}

let somethingDoer = SomeType.doSomething

You can’t do this with properties though, meaning you can’t employ tricks like this with higher-order functions, the way that you could if they were argument-less methods.

Properties provide a hugely beneficial, expressive way to instruct the compiler how to generate boilerplate accessors and mutators for you. Swift expands on this by providing a whole slew of additional ways to not only define them, but also hook into changes being made2. I’m really glad I don’t need to implement all of this myself.

At the same time, I can’t help but feel like Swift is missing an opportunity to provide a conceptually simpler programming model by removing this distinction from its types’ public interfaces.

  1. Calling Objective-C methods like -[NSArray count] using dot-notation was a surefire way to be chided, due to count not having been a property. Then Apple changed count to be a property instead of a method, ostensibly because array.count is nicer than [array count]. In the process, I’m assuming they didn’t stop computing the count in favor of storing it in an instance variable. 

  2. As an aside, I do worry that properties are overused as a result of how nice it is to define them, syntactically. It’s incredibly tempting to have a user property whose didSet block updates a persistent store and notifies a delegate, when a method named something like persistUserAndUpdateDelegate: is far more informative to someone reading the call site. I like these two posts on the subject matter.