Can I use guard var instead of guard let?

Here’s an example that Apple provided in The Swift Programming Language. Please take a few moments to read the code so I can explain my question, sorry if it’s a bit long.

enum VendingMachineError: Error{
    case invalidSelection
    case insufficientFunds(coinsNeeded: Int)
    case outOfStock
}

struct Item {
    var price: Int
    var count: Int
}

class VendingMachine {
    var inventory = [
        "Candy Bar": Item(price: 12, count: 7),
        "Chips": Item(price: 10, count: 4),
        "Pretzels": Item(price: 7, count: 11)
    ]
    var coinsDeposited = 0
    
    func vend(itemName name: String) throws {
        guard let item = inventory[name] else {
            throw VendingMachineError.invalidSelection
        }
        
        guard item.count > 0 else {
            throw VendingMachineError.outOfStock
        }
        
        guard item.price <= coinsDeposited else {
            throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
        }
        
        coinsDeposited -= item.price
        
        var newItem = item
        newItem.count -= 1
        inventory[name] = newItem
        
        print("Dispensing \(name)")
    }
    
}

Note that the first guard let statement inside the vend method assigns the value of inventory[name] to a constant called item.

And towards the end of the vend method’s definition, the item constant’s value is assigned to a newly created variable called newItem . I understand that the reason why this newItem variable is declared is because Apple wants to change the count property of item, but that’s impossible because item is a constant, therefore the newItem variable is created to do that.

But I found an easier way to write the above code without creating a newItem. Instead of assigning the value of inventory[name] to a constant, I assign it to a variable. Here’s my modified version of the code:

enum VendingMachineError: Error {
    case invalidSelection
    case insufficientFunds(coinsNeeded: Int)
    case outOfStock
}

struct Item {
    var price: Int
    var count: Int
}

class VendingMachine {
    var inventory = [
        "Candy Bar": Item(price: 12, count: 7),
        "Chips": Item(price: 10, count: 4),
        "Pretzels": Item(price: 7, count: 11)
    ]
    var coinsDeposited = 0
    
    func vend(itemName name: String) throws {
        guard var item = inventory[name] else {
            throw VendingMachineError.invalidSelection
        }
        
        guard item.count > 0 else {
            throw VendingMachineError.outOfStock
        }
        
        guard item.price <= coinsDeposited else {
            throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
        }
        
        coinsDeposited -= item.price
        item.count -= 1
        inventory[name] = item
        
        print("Dispensing \(name)")
    }
    
}

So, instead of guard let item = inventory[name], I wrote guard var item = inventory[name]. In the hope that the value of inventory[name] gets assigned to a variable, instead of a constant. This way I can just change the count property of the item variable without having to create a separate newItem variable to modify the count property like Apple did.

My question is, is there a reason why Apple uses guard let instead of guard var? Guard var is never used in The Swift Programming Language. I’m worried that there might be unwanted consequences of using guard var that I’m not aware of.

In this particular case there is no real reason for using let over var, it feels more like a matter of personal preference from the author. That said you should be fine with guard var item in this particular case. You can do this in if var item or while var item etc., so it really depends on the use case.

The compiler will warn you if you have created a variable but do not mutate it anywhere and suggest changing it to a constant.


If you got a minute, you could fix the markdown styling in your post for better readability. Use triple back-tick blocks for code blocks.

2 Likes

I see. Thanks a lot for the answer. Just added the triple back ticks to fix the format

2 Likes