25

Say I have have a class Event as follows:

class Event {
    private var attendees: [Person] = []

    // Case 1
    //*******
    // Should I use a func…
    func countOfAttendees() -> Int {
        return attendees.count
    }

    // …or a var
    var countOfAttendees: Int {
        return attendees.count
    }

    // Case 2
    //*******
    // Should I use a func…
    func countOfPaidAttendees() -> Int {
        return attendees.filter({$0.hasPaid}).count
    }

    // …or a var
    var countOfPaidAttendees: Int {
        return attendees.filter({$0.hasPaid}).count
    }
}

Is it best practice to use functions or computed properties in the 2 cases indicated above?

14

Follow the Uniform Access Principle,

All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation

To me, this means that I don't write funcs that take no arguments and return a value. I always use computed properties. That way, if I later decide to change the computed property into a stored property, I can do so without having the urge to remove the parens everywhere in my app and without having a separate "getter" method that just returns the value of a stored property, which seems pretty wasteful IMHO.

And if I change a stored property into a computed one, I don't have to add parens to the end of it, and everywhere that it is used in the app.

  • I originally went with @Anton's complexity answer, but in practice I realised that this is the way I do it… properties by default. – Ashley Mills Dec 29 '16 at 9:38
17

I would say it depends on complexity of calculation vs. usage frequency.

  • If it's O(1) / *, then use computed property.
  • If it's O(N)+ / rare-use, then use function.
  • If it's O(N)+ / frequent-use, think whether in the future you might decide to use caching or other "smart" techniques to compensate for the complexity, if "yes" then use property, if "no-no-no, it's just heavy" then use function.
  • 2
    Funny how I started doing it using the same reasoning. If you "can" give it the impression of being a property, even if you have to make a lightweight processing, as long as it doesn't change the object, make it a property. – Dielson Sales Jul 18 '16 at 3:40
8

I recently started learning Kotlin and they have a great heuristic about when to use computed properties:

Functions vs Properties

In some cases functions with no arguments might be interchangeable with read-only properties. Although the semantics are similar, there are some stylistic conventions on when to prefer one to another.

Prefer a property over a function when the underlying algorithm:

  • does not throw
  • has a O(1) complexity
  • is cheap to calculate (or caсhed on the first run)
  • returns the same result over invocations

-- https://kotlinlang.org/docs/reference/coding-conventions.html

  • The ‘does not throw’ is also important for Swift because properties can’t throw (yet?) – alejandromp Apr 19 at 7:19
  • "has a O(1) complexity" has removed from the documentation – Mahmoud Shahoud Aug 5 at 6:05
7

In Swift, functions without parameters and computed properties have almost the same capabilities (there may be a difference that a function without parameter is also a closure, while a computed property isn't).

The difference is semantically. If your code performs an action and returns for example a description of the outcome of that action, then I would use a function. If your code calculates a property but from the user's point of view this could have been a stored property, or maybe a stored property that requires updating some cached value first, then I would use a calculated property.

A big difference: What happens if you call the function or the calculated property twice? For a calculated property I expect that x = property; y = property has exactly the same behaviour as x = property; y = x except it might run a tiny bit slower. For functions, I wouldn't be surprised if the behaviour was different.

4

Use countOfAttendees and countOfPaidAttendees().


A computed variable is one that returns a calculated value each time it is accessed. That is, it doesn’t store a value. Internally it is implemented as a function.

What is the difference with a function?

  • Semantically, a variable is state, a function is an action.
  • A function regulates access to private storage. A calculated variable may do the same in a more compact way. Example.
  • A computed variable can be used with KVO, passed as a #keypath, and has facilities for observing: willSet, didSet.

You should use a variable when

  • it does not throw
  • it returns a simple property
  • it doesn’t have a side effect or a verb in its name
  • it’s O(1), that is, it doesn’t incur a significant cost. In your example it will be O(n).
  • it is idempotent. Multiple identical invocations return the same value or set the object to the same state.

Irrelevant reasons to prefer a variable over a function

  • A computed variable saves you from typing (). However, clarity is more important than brevity, so this is a weak argument.
  • A read only variable can be overriden as read/write. A function indicates it is always read only. However, Apple uses properties for read-only variables like array.count. When in doubt seek consistency with the platform.

Resources

From WWDC 2014 - 204 What’s new in Cocoa > 24:40 When to use a @property

Use property for anything that is about the value or state of an object or its relationship to other objects. Bad candidates:

  • Methods that do things: load, parse, toggle, …. They have verbs in its name.
  • Generators: init, copy, enumerated, …. These methods are not idempotent.
  • Methods which change state: nextObject.

From Swift Style by Erica Sadun > Computed Properties vs. Methods

A property expresses an inherent quality of an instance, while a method performs an action.

  • Methods have parameters; properties don’t. Prefer methods for any call with side effects. If a method does something (for example, it loads, parses, toggles, or prints) or has a verb name, it should not be a property.
  • Prefer properties for simple values that you can get and/or set.
  • Properties should express a semantic intrinsic quality of a type instance.
  • Properties allow you to add observers via willSet and didSet. Unlike stored instance properties, stored type properties must always be given a default value.

From Kotlin coding conventions > functions vs properties. See Daniel’s answer above.

Other resources with no relevant information:

3

I'd use a func. Object-oriented programming works just fine without computed properties. Because you are getting a value back that was computed/filtered some may argue that a computed property feels right. But here's my complaint, if you do that then readability takes a hit, because it feels like a value.

In this context it wouldn't make sense to try to assign the computed value (and luckily the IDE helps us avoid this) but what if I try to assign something that is computed but looks like a value?

event.countOfAttendees = 0; // not possible

While using func the caller know's you aren't dealing with a value directly:

event.countOfAttendees()

I think if its a behavioral object it should look like it behaves rather than looking like a data structure. If your object is dumb and doesn't have any behavior then why try to encapsulate it? In that case you might as well just have attendees be public

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.