Jaxon
Jaxon

Reputation: 303

Under which conditions I should prefer computed properties over stored properties?

I saw this piece of code today, and was wondering why you would not instead use simple static stored properties?

This is the code that I am curious about:

class ApiKeys {

// movie keys
class var HomePage: String { get { return "homepage" } }
class var Id: String { get { return "id" } }
class var Overview: String { get { return "overview" } }
class var PosterPath: String { get { return "poster_path" } }
class var ReleaseDate: String { get { return "release_date" } }
class var Runtime: String { get { return "runtime" } }
class var Tagline: String { get { return "tagline" } }
class var Title: String { get { return "title" } }
class var Rating: String { get { return "vote_average" } }


// query params
class var ApiKey: String { get { return "api_key" } }
class var Query: String { get { return "query" } }
}

And this is how I would have written the same code:

class ApiKeys {

static let homePage = "homepage"
static let id = "id"
static let overview = "overview"
static let posterPath = "poster_path"
static let releaseDate = "release_date"
static let runtime = "runtime"
static let tagline = "tagline"
static let title = "title"
static let rating = "vote_average"


//Query Params
static let ApiKey = "api_key"
static let query = "query" 
}

There won't ever be any need to override the variables, so use of static should be okay. Am I missing something? Is there any advantage or reason to use the first method over the second?

Upvotes: 2

Views: 91

Answers (4)

Rob
Rob

Reputation: 437412

For what it's worth, I wouldn't be inclined to use computed or stored properties at all. Rather than defining this to be a class, this seems like a textbook case for an enum:

enum ApiKey: String {
    // movie keys
    case HomePage    = "homepage"
    case Id          = "id"
    case Overview    = "overview"
    case PosterPath  = "poster_path"
    case ReleaseDate = "release_date"
    case Runtime     = "runtime"
    case Tagline     = "tagline"
    case Title       = "title"
    case Rating      = "vote_average"

    // query params
    case ApiKey      = "api_key"
    case Query       = "query"
}

This more accurately captures the notion that a "key" can be one of those values.

And you'd use it like so:

if key == ApiKey.HomePage.rawValue {
    ...
}

Or

if ApiKey(rawValue: key) == .HomePage {
    ...
}

In answer to your original question, “when should I prefer computed properties”, the answer is that you generally use them to retrieve a value computed from other properties and, optionally, if you want to set other (possibly private) properties and values indirectly. There's little benefit to using computed properties if you're just going to return some static, unchanging string.

Upvotes: 2

dfrib
dfrib

Reputation: 73176

Possibly somewhat off-topic: but one possibly contrived usage scenario where static stored properties cannot be used is if you define non-blueprinted static computed properties with default implementations in an extension to some "constants" protocol. Classes/structs/etc that conform to such a protocol can be allowed to access type constrained generics, where these generics are the the only context in which the protocol constants are accessible (limit the accessibility to the constants) where they are guaranteed to be constants (since they can also be used directly from the concrete types that conform that protocol, but these can "override" the "constants" with new values).

protocol HasAccessToConstants {
    /* since we don't blueprint 'theAnswer', the default
       implementation below will always be used for objects
       conforming to this protocol when used in a generic
       context (even if they attempt to "override" these
       "constants" with implementations of their own, these
       custom ones can only be accessed for concrete-types). */
}

extension HasAccessToConstants {
    static var theAnswer: Int { return 42 }
    /* for protocols: we may implement a default  
       implementation only for computed properties */
}


class Foo : HasAccessToConstants {
    /* Even if the developer implements its own "constant"
       implementation, this will not be used for accessing 
       Foo type in a generic context. */
    static var theAnswer: Int { return 9 }
}

func onlyForObjectsWithAccessToConstants<T: HasAccessToConstants>(obj: T) {
    // do something with obj ...

    // make use of constants available to the type of obj
    print("Constants available to the type of this object (e.g. '\(T.theAnswer)')")
}

onlyForObjectsWithAccessToConstants(Foo())
/* Constants available to the type of this object (e.g. '42') */

// not really "constants" as they can be "overridden" for concrete types
print(Foo.theAnswer) // 9 (since concrete type)

Again, contrived, and included for the technical discussion, as I can't really see in what scenario this would be more useful than other, better alternatives.

Upvotes: 1

JAL
JAL

Reputation: 42449

Computed properties can be used to dynamically change the value of the property at runtime if necessary, just like and overridden getter can in Objective-C. You can't do that with a static let constant.

Upvotes: 1

Luca Angeletti
Luca Angeletti

Reputation: 59496

A class var can be overridden by a subclass while a static constant can't. That's the first difference I can think about.

Upvotes: 1

Related Questions