TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

Day 4. For loops. Why is the underscore *number* const and not the variable?

Forums > 100 Days of Swift

https://www.hackingwithswift.com/quick-start/understanding-swift/why-does-swift-use-underscores-with-loops

Code from the example:

let count = 1...10

for number in count {
    print ("Number is \(number)")
}

As I understand it, the Swift compiler makes a temporary number constant for a "for-loop" for every iteration. If it's true, why it's a constant and not a variable if the value changes? E.g., in C, it looks more transparent:

for (int number = 1; number <= 10; number++) {
        printf("Number is %d\n", number);
    }

In this case, number is variable, which makes sense — we change it. Can somebody explain why Swift works differently?

P.S. Sorry if the question was already asked. I couldn't find it in the search.

3      

It doesn't change, though. It's not the same number just with a different value, it's a new number constant each time through the loop.

See this Stack Overflow post from Ben Cohen, one of the Swift engineers at Apple, for insight into what a for in loop becomes behind the scenes and why that answers your question.

3      

I can't think of a language that allows mutable endpoints for loop number boundaries.

In addition to the link given by @roosterboy, imagine this scenario:

  • You're going from 1...10
  • You decrement number

What should number be next time through the loop?

If you decrement the lower boundary instead, what should happen?

I am not a compiler expert at all, but one C compiler would change the C syntax you gave for a for loop into a while loop at compile time. That was ages ago, granted.

3      

Swift will actually allow you to declare the iterator symbol as a var instead of an implicit let:

for var number in 0..<11 {
    print("original: \(number)")
    if number.isMultiple(of: 2) {
        number -= 1
    }
    print("changed: \(number)")
}

Prints:

original: 0
changed: -1
original: 1
changed: 1
original: 2
changed: 1
original: 3
changed: 3
original: 4
changed: 3
original: 5
changed: 5
original: 6
changed: 5
original: 7
changed: 7
original: 8
changed: 7
original: 9
changed: 9
original: 10
changed: 9

I don't really see much use for it, to be honest, but you can do it. You can see that even though you change number inside the for in loop, the next time through the loop it is set to whatever value it would have if you didn't change it. So, what's the point?

Even with something a little more complex than simple numbers, you can use var instead of let, but again I'm hard-pressed to think of a good use for it.

struct Person {
    let id = UUID()
    var name: String
}

let people: [Person] = [
    Person(name: "Shelley Winters"),
    Person(name: "Ryan Beckwith"),
    Person(name: "Amy Chilton"),
]

for var person in people {
    if person.name == "Amy Chilton" {
        person.name = "Amy Beckwith-Chilton"
    }
    print(person)
}
print(people)

And note, too, that the Person items in the people array will remain unchanged, regardless of what you do in the for in loop.

3      

Thank you @roosterboy and @deirdresm for the answers 🙏

3      

Hacking with Swift is sponsored by Blaze.

SPONSORED Still waiting on your CI build? Speed it up ~3x with Blaze - change one line, pay less, keep your existing GitHub workflows. First 25 HWS readers to use code HACKING at checkout get 50% off the first year. Try it now for free!

Reserve your spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.