Swift: when should I use "var" instead of "let"? - swift

As Apple Documentation says:
Use let to make a constant and var to make a variable. The value of a constant doesn’t need to be known at compile time, but you must assign it a value exactly once. This means you can use constants to name a value that you determine once but use in many places.
Let's consider some class:
class A {
var a = [String]()
}
Since array a is mutable, it's defined via var. But what if we consider class B, where instance of A is property?
class B {
let b = A()
}
Even if b is mutable, let keyword will be ok, because reference won't be changed. On the other hand, var will be ok too, because content of b can be changed. What should I pick in this example - let or var?

Use let whenever you can. Use var when you must. Making things immutable makes a lot of bugs impossible, so it should be your default choice. As much as possible, set all your values in init and never change them. Similarly, you should use struct when you can, and class when you must (though in my experience this is harder to achieve than using let).
So in your example, if you cannot set A.a during initialization, then yes, it should be var. But there is no need in your example to use var for B.b. (And there's no reason in either example to use class, at least in the way you've presented the question.)

Let's give these better names to help with our reasoning. Let's say
class Head {
var hairs = [String]()
}
class Person {
let head = Head()
}
In this example, a Person has exactly one head, and for the lifetime of each Person, his/her head will always been that same head. However, that head's hairs can grow in, fall out, or otherwise change. Person's ownership of this head has no bearing on the Head's relationship to its hairs.
As Rob mentioned, you should always use let unless you have a good reason not to. Immutability is your friend when it comes to reasoning about program behavior.

Use let when your object does not change its value after has been set a value.
Use var if your object can change its value more than 1 time.
'let' is for constance. 'var' is for something variable.
However, constant restriction is only applied to the object but not its attributes if the object is an instance of class (value are passed by reference). Depending on type of those attributes (constant or variable), we can change their value after. This is not true for structure.
For example:
class VideoMode {
var interlaced = false
var frameRate = 0.0
var name: String?
}
in a function, you declare
let vm = VideoMode()
print("starting framerate is \(vm.frameRate)") // -> print starting framerate is 0.0
vm.frameRate = 20.0
print("framerate now is \(vm.frameRate)") // -> print framerate now is 20.0
//we can change .frameRate later to 10.0, there is no compile error
vm.frameRate = 10.0
print("framerate now is \(vm.frameRate)") // -> print framerate now is 10.0

When you declare a variable with var, it means it can be updated, it is variable, it’s value can be modified.
When you declare a variable with let, it means it cannot be updated, it is non variable, it’s value cannot be modified.
var a = 1
print (a) // output 1
a = 2
print (a) // output 2
let b = 4
print (b) // output 4
b = 5 // error "Cannot assign to value: 'b' is a 'let' constant"
Let us understand above example: We have created a new variable “a” with “var keyword” and assigned the value “1”. When I print “a” I get output as 1. Then I assign 2 to “var a” i.e I’m modifying value of variable “a”. I can do it without getting compiler error because I declared it as var.
In the second scenario I created a new variable “b” with “let keyword” and assigned the value “4”. When I print “b” I got 4 as output. Then I try to assign 5 to “let b” i.e. I’m trying to modify the “let” variable and I get compile time error “Cannot assign to value: ‘b’ is a ‘let’ constant”.
Source: https://thenucleargeeks.com/2019/04/10/swift-let-vs-var/

Related

How to understand the usage of 'let' or 'var' in Swift?

I'm following tutorial for Swift 4 and have found the usages of 'let' or 'var' in Swift quite inconsistent.
//in try catch : "let ... as" to match a error ?
catch let(or var) printerError as PrinterError
//in switch 1: "let .." to match a case pattern ?
case let(or var) .result(sunrise, sunset):
//in switch 2: "let ... where" pointless for me, why not just use someVar.hasSuffix ?
switch: someVar {
case let x(or var) where x.hasSuffix("pepper"):
Could anyone kindly give a summary of the usage in Swift?
It seems everyone is answering about the difference between 'let' and 'var' and mark the question as a duplication. But, I didn't even mention anything about 'var' in the original post at the first place!
let is keyword that is used to declare a constant value of any data type, using let you can declare a value but you can't change its value again through out the project and if you try to change its value, it will gives you an error stating that this is a let constant. If you want to modify its value kindly change it to var, where var is a keyword used for variables.
let x: Int = 5
let string : String = "Hello! World"
The above values are constant and you can never change these values.
var x: Int = 5
var string: String = "Hello! World"
The above values are variables. You can change their value anywhere in the code.
let is used for constants while var is for variables
let is also used for optional binding like in your examples. You use optional binding to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable.
Let is a keyword to declare a constant.
Think of constant as a box that stores information.
let name = "Bob"
"let" is the keyword to declare the constant.
"name" is the name you assign your constant. This is the box you store your information in. You can name it whatever you want doesn't have to be "name"
"=" assigns the value(your information) from the right side to the "name" constant.
"Bob" is the value aka the information you want to store. It can be anything you want and it's assigned to your constant.
Something you have to remember for constant is that constants are immutable. Meaning the values once declared cannot be changed. That's why it's called constant, because the values are always constant and does not change.

Cannot assign to property: function call returns immutable value

Consider the following example.
struct AStruct{
var i = 0
}
class AClass{
var i = 0
var a: A = A(i: 8)
func aStruct() -> AStruct{
return a
}
}
If I try to mutate the the variable of a instance of class AClass it compiles successfully.
var ca = AClass()
ca.a.i = 7
But If I try to mutate the return value of aStruct method, the compile screams
ca.aStruct().i = 8 //Compile error. Cannot assign to property: function call returns immutable value.
Can someone explain this.
This is compiler's way of telling you that the modification of the struct is useless.
Here is what happens: when you call aStruct(), a copy of A is passed back to you. This copy is temporary. You can examine its fields, or assign it to a variable (in which case you would be able to access your modifications back). If the compiler would let you make modifications to this temporary structure, you would have no way of accessing them back. That is why the compiler is certain that this is a programming error.
Try this.
var aValue = ca.aStruct()
aValue.i = 9
Explanation
aStruct() actually returns a copy of the original struct a. it will implicitly be treated as a constant unless you assign it a var.
Try using a class instead of a struct, as it's passed by reference and holds onto the object, while a struct is passed by value (a copy is created).

Why can you assign non-optional values to optional types in Swift?

Why do assignments involving Swift optionals type check?
For example in,
var foo : Int? = 0
foo = foo!
foo and foo! do not have the same type. Shouldn't you need to wrap the unwrapped value to assign it to an optional type?
This is part of the syntactic sugar behind optionals. Assigning a non-optional value is how you wrap it in the optional type.
Since an optional indicates the presence or absence of a value, you shouldn't have to do anything special to indicate the presence of a value other than provide one. For example, in a function:
func gimmeSomethingMaybe() -> String? {
if arc4random_uniform(10) > 7 {
return "something"
} else {
return nil
}
}
Imagine if every time you wanted to return a real value from a function that's capable of returning nil, you had to write return Optional(value). That'd get old pretty fast, right? Optionals are an important feature of the language — even though they're actually implemented by the standard library, the syntactic sugar / automatic wrapping is there to keep it from being tedious to use them.
Edit: just to go a bit further into this... the sugar also helps to enforce the notion that a real value should not be optional. For example:
let one = 1
one? // error (in Swift 1.2, allowed but meaningless in Swift 1.1)
"two"? // error (ditto)
You can create an optional wrapping a real value with the Optional(one) initializer, but that has little semantic meaning on its own, so you almost never need to.
Optionals should come into play when there's "mystery" as to whether a value is present or absent — that is, when whether one part of a program receives a value (or no value) depends on state unknown to that part of the program. If you know you have a real value, there's no mystery... instead, you let the unknown come into play at the boundary between the code that knows the value and the code that doesn't know — that is, the function/method/property definition that hands that value off to somewhere.
After reading rickster's answer, I came up with a simple laymen terms answer. To me the whole whole gist of his answer is
Since an optional indicates the presence or absence of a value, you
shouldn't have to do anything special to indicate the presence of a
value other than provide one
An optional is an enum. Which has 2 cases a or b.
String?
|
An enum with 2 cases
|
a b
| |
Set notSet
| |
any value like "hi" nil
So you could do either of the things when you want to assign to an optional.
Say the value is either:
a: it's set to "hi"
b: it's not set, so it's nil
c: it just equals to another enum ie another optional
code:
var str : String?
var anotherOptional : String?
str = nil // nil <-- this is like case b
str = "hi" // "hi" <-- this is like case a
str = anotherOptional // nil <-- this is like case c
anotherOptional = "hi again"
str = anotherOptional // "hi again" <-- this is like case c

What are 'get' and 'set' in Swift?

I'm learning Swift and I'm reading The Swift Programming Language from Apple. I don't have any Objective-C background (only PHP, JavaScript, and others, but not Objective-C).
On page 24-25 I see this code:
//...Class definition stuff...
var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
}
//...Class continues...
This part is not specified in the book, and I can't get what those are for.
What are get and set?
The getting and setting of variables within classes refers to either retrieving ("getting") or altering ("setting") their contents.
Consider a variable members of a class family. Naturally, this variable would need to be an integer, since a family can never consist of two point something people.
So you would probably go ahead by defining the members variable like this:
class family {
var members: Int
}
This, however, will give people using this class the possibility to set the number of family members to something like 0 or 1. And since there is no such thing as a family of 1 or 0, this is quite unfortunate.
This is where the getters and setters come in. This way you can decide for yourself how variables can be altered and what values they can receive, as well as deciding what content they return.
Returning to our family class, let's make sure nobody can set the members value to anything less than 2:
class family {
var _members: Int = 2
var members: Int {
get {
return _members
}
set (newVal) {
if newVal >= 2 {
_members = newVal
} else {
println('error: cannot have family with less than 2 members')
}
}
}
}
Now we can access the members variable as before, by typing instanceOfFamily.members, and thanks to the setter function, we can also set it's value as before, by typing, for example: instanceOfFamily.members = 3. What has changed, however, is the fact that we cannot set this variable to anything smaller than 2 anymore.
Note the introduction of the _members variable, which is the actual variable to store the value that we set through the members setter function. The original members has now become a computed property, meaning that it only acts as an interface to deal with our actual variable.
A simple question should be followed by a short, simple and clear answer.
When we are getting a value of the property it fires its get{} part.
When we are setting a value to the property it fires its set{} part.
PS. When setting a value to the property, Swift automatically creates a constant named "newValue" = a value we are setting. After a constant "newValue" becomes accessible in the property's set{} part.
Example:
var A:Int = 0
var B:Int = 0
var C:Int {
get {return 1}
set {print("Recived new value", newValue, " and stored into 'B' ")
B = newValue
}
}
// When we are getting a value of C it fires get{} part of C property
A = C
A // Now A = 1
// When we are setting a value to C it fires set{} part of C property
C = 2
B // Now B = 2
You should look at Computed Properties.
In your code sample, perimeter is a property not backed up by a class variable. Instead its value is computed using the get method and stored via the set method - usually referred to as getter and setter.
When you use that property like this:
var cp = myClass.perimeter
you are invoking the code contained in the get code block, and when you use it like this:
myClass.perimeter = 5.0
You are invoking the code contained in the set code block, where newValue is automatically filled with the value provided at the right of the assignment operator.
Computed properties can be read/write if both a getter and a setter are specified, or read-only if the getter only is specified.
A variable declares and is called like this in a class:
class X {
var x: Int = 3
}
var y = X()
print("value of x is: ", y.x)
//value of x is: 3
Now you want the program to make the default value of x more than or equal to 3. Now take the hypothetical case if x is less than 3: your program will fail.
So, you want people to either put in 3 or more than 3. Swift got it easy for you and it is important to understand this bit - it is an advanced way of dating the variable value, because they will extensively use it in iOS development. Now let's see how get and set will be used here.
class X {
var _x: Int = 3
var x: Int {
get {
return _x
}
set(newVal) { // Set always take one argument
if newVal >= 3 {
_x = newVal // Updating _x with the input value by the user
print("new value is: ", _x)
}
else {
print("error must be greater than 3")
}
}
}
}
let y = X()
y.x = 1
print(y.x) // The error must be greater than 3
y.x = 8 // // The new value is: 8
If you still have doubts, just remember the use of get and set is to update any variable the way we want it to be updated. get and set will give you better control to rule your logic. It is a powerful tool, hence not easily understandable.

Using "let" inside Struct - Swift

I'm currently practicing examples from Swift Language iBook. My understanding of "let" is that we use "let" to make a constant. Once we assign a value to it, we cannot assign another value to it again. Like the codes below:
let city="NY"
city="LA" <--error (Cannot assign 'let' value city)
But I saw this example on iBook which really confused me:
struct Color{
let red=0.0, green=0.0, blue=0.0 //<---declare variables using "let" and assign value
init(red:Double,green:Double,blue:Double){
self.red=red //<---assign value to variable again?
self.green=green
self.blue=blue
}
}
In this example, it has already assigned values to red, green and blue which use "let".
Why can we assign values to these three variables again in init?
The initialization in the let provides default values if you don't initialize them yourself in the constructor.
Constructors (init) are special. Inside them, you can assign to a constant instance variable. In fact, if you don't have a default value for them, you have to assign to them. (This applies to classes too.)
Thanks to Qwerty Bob for finding this in the docs
Modifying Constant Properties During Initialization
You can modify the value of a constant property at any point during initialization, as long as it is set to a definite value by the time initialization finishes.
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/us/jEUH0.l
You may set constant variables during the init process, before the self keyword is used. After this they are then truly 'constant'.
You must do it before the self keyword is used, as if you pass it to another object it could in turn call a method of yours which relies on that constant property
And also: structs get passed by value and not by reference, so you cannot modify the variables in a struct at all after their set. So the let keyword really makes sense.
If you continue reading a few paragraphs after the example you gave from the book (unless they use it in multiple locations), it actually talks about this behavior:
You can modify the value of a constant property at any point during
initialization, as long as it is set to a definite value by the time
initialization finishes.
So basically you can modify constants and upon ending the initialization all constants must have a definitive value. It also goes on to talk about how this works with subclasses too:
For class instances, a constant property can only be modified during
initialization by the class that introduces it. It cannot be modified
by a subclass.
Here is the doc reference for it (same as the book), the quoted sections is under the "Modifying Constant Properties During Initialization" subheading.
Apart from the initialization part, which was answered by Kevin, you're still missing the constant part of let. So to clarify let is not exactly a constant.
According to „The Swift Programming Language.” Apple Inc., 2014-05-27T07:00:00Z. iBooks:
Like C, Swift uses variables to store and refer to values by an
identifying name. Swift also makes extensive use of variables whose
values cannot be changed. These are known as constants, and are much
more powerful than constants in C.
Both var and let are references, therefore let is a const reference.
Using fundamental types doesn't really show how let is different than const.
The difference comes when using it with class instances (reference types):
class CTest
{
var str : String = ""
}
let letTest = CTest()
letTest.str = "test" // OK
letTest.str = "another test" // Still OK
//letTest = CTest() // Error
var varTest1 = CTest()
var varTest2 = CTest()
var varTest3 = CTest()
varTest1.str = "var 1"
varTest2.str = "var 2"
varTest3 = varTest1
varTest1.str = "var 3"
varTest3.str // "var 3"