Variable 'xxx' was never mutated, consider changing to 'let'

24.8k views Asked by At

Updated to xcode7-beta I run across a new kind of warning. Here is my code

override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    var attributes: [UICollectionViewLayoutAttributes]? = super.layoutAttributesForElementsInRect(rect)
    if let layoutInfo = self.layoutInfo {
        attributes?.append(layoutInfo)
    }
    return attributes
}

the warning message is Variable 'attributes' was never mutated, consider changing to 'let' constant

Why does xcode say Variable 'attributes' was never mutated?

Question Update

the warning is gone when I change my code to this

override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    var attributes: [UICollectionViewLayoutAttributes]? = super.layoutAttributesForElementsInRect(rect)
    if let layoutInfo = self.layoutInfo {
        attributes!.append(layoutInfo)
    }
    return attributes
}

so forced unwrapping can take it away. But it might not be a good thing right?

6

There are 6 answers

4
matt On BEST ANSWER

They talked about this in the WWDC videos and the release notes.

It has always been the case that you get much, much better performance (faster speed, smaller space) if you use let instead of var whenever you can. This tells the compiler that this thing is a constant, not a variable, and that fact allows the compiler to optimize all kinds of things away.

But the compiler can't do that unless you do use let whenever you can. It won't change a var to a let for you.

Therefore, in Swift 2, the compiler does a smarter analysis at build time and warns you if you are using var where you could have used let. Eventually this feature will work properly, at which point you should take the compiler's advice!

0
rickster On

By declaring a constant with let, you ensure that it can never be changed. This is good for making sure that you don't accidentally change it later, and it (in theory) can help the optimizer generate faster code.

If you declare a variable with var, and you don't intend to change it or call mutating methods on it, using let instead helps you enforce that contract.

0
Nilesh Patel On

You have created that object as var object but value of that object not changing then after better to make it let. That's it.

As per Apple Developer Guidelines, create var object if value of that object is going to change else create let variable. Best practise

0
Warren Burton On

Your code implies that attributes could be mutated if self.layoutInfo is non nil

Perhaps the warning is saying that no path leads to self.layoutInfo being non nil and hence attributes has no need of being a var.

Examine what conditions if any can lead to self.layoutInfo having data

0
Top-Master On

Why this warning?

Because in Swift "let" means "value is constant" and allows compiler to do some optimizations, hence "let" is faster than "var",
And since "Swift 2", the compiler warns if we use "var" wherever it detects that we could use "let" instead.

Class vs Struct

However, in Swift the "class" is a reference-type (just like in Java), meaning the "value" is just "a reference and/or pointer to actual data".

Even if we use "let" with "class", the "data" pointed is never constant (and is always mutable).
So, if changing the "data" is a big thing and should not happen unnoticed, consider using struct.

In Swift "struct" is a value-type, and unless it's defined with "var" (or "inout" in "func" parameters), any mutation to the "data" it holds should cause compile error.

Basically same as const keyword available in C and C++ languages, but in C++ we don't need to migrate from "class" to a complete different type, jsut to have mutability sensitive class.

That's a plus for C++, but it fades to nothing, once we see the other C++ overcomplications.

3
Greg Veres On

This has been driving me crazy too. Whenever I have a class and I change member properties, it still tells me that I should make the variable a constant. For instance:

class X { 
    var name = ""
}

var xInstance = X()
xInstance.name = "my name"

Near as I can figure, the compiler is correct. xInstance is a constant. It is assigned the pointer to the X instance during its initialization and is never assigned another value. So xInstance is constant. The class that it points to is not constant. This is more obvious in a language like C or C++ but when you realize that all class instances are really pointers to heap backed classes, this makes sense.

For those who understand C++

xInstance is equivalent to:

X *xInstance

making it a let instead means that it changes to:

X * const xInstance

I think most people would intuitively think that the swift declaration would be equivalent to

X const * xInstance