2

For example:

var dogName : String {
 return "Buster"
}

VS..

let dogName = "Buster"

Let's say we're declaring each of these at the top level of a class as instance properties. Are these just two ways of doing the same thing? If not, what's the point of having a read-only variable?

Thanks

isherwood
  • 58,414
  • 16
  • 114
  • 157
user7024499
  • 951
  • 1
  • 10
  • 24
  • Possible duplicate of [What is the difference between \`let\` and \`var\` in swift?](http://stackoverflow.com/questions/24002092/what-is-the-difference-between-let-and-var-in-swift) – Eric M. Nov 16 '16 at 16:24
  • I think you misunderstand that the first example is a computed property. – JAL Nov 16 '16 at 16:30
  • Also keep in mind that a read-only property doesn't exist in a vacuum. Normally such a property is found as part of a class or struct. – rmaddy Nov 16 '16 at 16:35

5 Answers5

6

Let me try to sum up what the other answers are saying while also adding missing information that I think is critical in order to understand this.

Properties

Properties are simply values that are associated with an object and may be queried in a trivial amount of time without the need (or ability) for parameters like methods have.

Stored Properties

When you create a stored property, whether with let or var, the value assigned at any given point in time will be stored in memory, which is why it is called a stored property.

var name = "Matt"

For variables using var, the value is stored in memory in a way that makes it mutable (editable). You can reassign the value at will and it will replace the previous value stored in memory.

let name = "Matt"

For constants using let, the value is also stored in memory, but in such a way that it may not be changed after the first time assigning to it.

Computed Properties

Computed properties are not stored in memory. As ganzogo says in the comments, computed properties act similarly to methods, but do not take parameters. When deciding when to use a computed property or a function with no parameters, the Swift API Design Guidelines recommend using a computed property when it will simply create or fetch, and then return the value, provided that this takes a trivial amount of time.

var fullName: String {
    return firstName + lastName
}

Here, we assume that firstName and lastName are already properties on the object. There is no sense of initialization with this property because it is not stored anywhere. It is fetched on demand every time. That is why there is no sense to doing anything like the following:

var dogName : String {
    return "Buster"
}

This has no benefit over a stored property except that no memory will be used in storing the String "Buster".

In fact, this is a simplified version of computed properties. You will notice that the Swift Language Guide describes the use of both get and set in a computed property. set allows you to update the state of other variables when one sets a computed variable. For example:

var stored: Int

var computed: Int {

    get {
        return stored + 5
    }

    set {
        stored = newValue - 5
    }

}

Some useful applications of this were pointed out by Rajan's answer, for example getting and setting volume from width, height, and depth.

A read-only computed var is just a computed var which specifies only a getter, in which case the get keyword and brackets are not required.

Read-Only for Access Control

When developing modules such as frameworks, it is often useful to have a variable only be modifiable from within that object or framework and have it be read-only to the public.

private var modifiableItem: String

public var item: String {
    return modifiableItem
}

The idea here is that modifiableItem should only be mutable from within the object that defined it. The private keyword ensures that it is only accessible within the scope of the object that created it and making it a var ensures that it may be modified. The public var item, then, is a computed variable that is exposed to the public that enables anyone to read, but not mutate the variable.

As Hamish notes in the comments, this is more concisely expressible by using private(set):

public private(set) var item: String

This is probably the best way to go about it, but the previous code (using a private stored property and public computed one) demonstrates the effect.

Community
  • 1
  • 1
Matthew Seaman
  • 7,952
  • 2
  • 37
  • 47
3
let dogName = "Buster"

means that the dogName variable can't be changed later on once assigned "Buster" and it becomes constant

var dogName : String {
 return "Buster"
}

It is a computed read only property where you can have some calculation which can be changed as it is a var but in a way defined below:

The computed property can be changed like

var dogName : String {
     return "Stress"+"Buster"
}

Consider this example from Apple Docs

struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    var volume: Double {
        return width * height * depth
    }
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")

It will print

// Prints "the volume of fourByFiveByTwo is 40.0"

Here the volume is calculated when you initialize the object of struct Cuboid and is computed at run time. If it was let, then you have to initialize it before using by some constant.

If you want to read more about it, read the Computed Properties section here

Rajan Maheshwari
  • 14,465
  • 6
  • 64
  • 98
1

A read-only property in a class/struct means that you can't change the value of the property for that instance of the class/struct. It prevents me from doing:

someObject.dogName = "Buddy" // This fails - read-only property

However, I can still do this:

var someVariable = someObject.dogName // someVariable now is "Buster"
someVariable = "Buddy" // This is OK, it's now "Buddy"

A let constant means you won't be changing the value of that specific constant in that block of code.

let someName = "Buster"
someName = "Buddy" // This fails - someName is a constant
rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • True, but functionally equivalent yes? I mean, the end result is that you are receiving a value that cannot be changed once initialized. – user7024499 Nov 16 '16 at 16:30
  • @user7024499 Not at all. These two things have nothing to do with each other. See my update. – rmaddy Nov 16 '16 at 16:33
  • Maybe 'functionally equivalent' isn't the right term. I mean in the big scheme of things, one of the USAGES you gain with both of these is the ability to set a value and make it restricted from changing once it is set. So in an instance object, the value of the property is restricted from changing b/c it is read only, and with LET, you won't be able to change the value either way – user7024499 Nov 16 '16 at 16:40
  • But they prevent the changing of two completely different things. `let` only protects that specific local variable. The read-only property protects all instances of that property. – rmaddy Nov 16 '16 at 16:42
  • Got you. However, when you use 'let' as a member in a class, is it not also preventing you from changing that value for all child instances of that object type? I.E. class Dog { let name = "buster" } ... for all instances, the name HAS to be buster.. it cannot be changed because let is a constant. In effect, doing the same thing as a read-only variable which cannot be changed. – user7024499 Nov 16 '16 at 16:44
  • 1
    True but typically your read-only property returns a dynamic value, not a hardcoded string. – rmaddy Nov 16 '16 at 16:49
  • Okay so safe to say a huge advantage of a read-only variable (or property in the case that it's a top level class member) is that you can write code that will compute a dynamic value based on other properties in the class before those values have been initialized. Reason being because a computed variable is actually just a shorthand for a function. With LET, I'm assuming you're more compiler error prone if you do that type of thing inside a class before having initialized an instance. – user7024499 Nov 16 '16 at 16:56
  • Yes. And you would never use a read-only property other than as a top-level class member. – rmaddy Nov 16 '16 at 16:58
1

In your example, they are 2 ways of doing the same thing. However, you can do a lot more with a computed property. For example:

var dogName: String {
  return firstName + " " + lastName
}

Here, firstName and lastName might not be known at initialization time. This is not possible to do with a simple let property.

It might help you to think of a computed property as a method with no parameters.

ganzogo
  • 2,516
  • 24
  • 36
  • How about with a Computed Initializer? We can do the same thing with a computed initializer with no compile time error right? – user7024499 Nov 16 '16 at 16:29
  • Not sure what you mean by "computed initializer", but the point is that in my example, `dogName` is dynamic. – ganzogo Nov 16 '16 at 16:31
  • Cool thanks. Computed initializer is like var myNumber : Int = { if (3 ==3) { return 3} }() *must be invoked immediately – user7024499 Nov 16 '16 at 16:33
  • Ah I see. Yes - that is only called once, whereas the block for a computed property is called every time that property is accessed. It might help you to think of a computed property as a method with no parameters. – ganzogo Nov 16 '16 at 16:35
0

There are two different cases:

1) Value type:

struct DogValueType {

    var name: String

}

let dog1 = DogValueType(name: "Buster")

var dog2: DogValueType {
    return DogValueType(name: "Buster")
}

let dog3: DogValueType = {
    return DogValueType(name: "Buster")
}()
  • dog1 - dog3 can't be changed or mutated
  • dog1 & dog3 stores value
  • dog3 computes value each time you accessing it

2) Reference type:

class DogReferenceType {

    var name: String

    init(name: String) {
        self.name = name
    }
}

let dog4 = DogReferenceType(name: "Buster")

var dog5: DogReferenceType {
    return DogReferenceType(name: "Buster")
}

let dog6: DogReferenceType = {
    return DogReferenceType(name: "Buster")
}()
  • dog4 - dog6 can't be changed, but can be mutated
  • dog4 & dog6 stores reference to an object.
  • dog5 creates object each time you accessing it
Silmaril
  • 4,241
  • 20
  • 22