Guard + reassignment

I was wondering if this should be valid:

var i: Int = 0
while true {
     guard i = self.readInput() else {


Currently, you need to always bind a new variable in the guard statement, so the above mentioned code needs to be this instead:

var i: Int = 0
while true {
     guard let int = self.readInput() else {

     i = int

Generally, the proposed change would be a syntax sugar for the intermediate variable that needs to exist for the sole purpose of re-assignment.

1 Like

It seems like what you really want is for the assignment operator to return the value that was assigned, which is a commonly requested (and rejected) feature.

The example isn't very clear as well. What are you hoping to achieve? If you want to read input until you get a non-nil value, you can use a simple repeat-while:

var i: Int?
repeat {
  i = self.readInput()
} while i == nil

This is not entirely the same - I'm not requesting guard i = i else, etc. In the example you've added, you still end up creating one more variable as you have Int? instead of Int.

That's not what the example is doing... and I think it's not about "assignment returns value" either.

I don't like the common idea of the guard variable else-shortcut, because this would require a spontaneous change of type - but the initial example does not have this issue, because i is never an Optional.

The only problem I see is that the mental model for the proposal requires you to "rewind" the assignment if the result of the method call is nil. That is never needed with guard var, because the variable involved can't be used at all if this happens.

If I take your example literally, you:

  1. Check if input is available.
  2. If so:
  • Do something with this input.
  • Store the value in i, for use later on outside of the scope of the while.
  1. If not, read the next input.

And also, you don't want i to be optional.

Is that correct?

If so, I'd recommend sticking with your second version.

The proposed guard i = self.readInput() is not simply a guard as it:

  1. assigns to an existing value
  2. checks if the assigned value is not nil
  3. rewinds the assignment in case it was

1 introduces a new side effect and will likely be refused as Swift disallows = in places where you typically use ==. It's very easy to write guard i = read() by accident when you actually mean guard i == read(). With your proposal, the compiler will no longer be able to catch this bug.

2 reminded me of C-style while (c = read()) loops that rely on the return value of the assignment operator to check if a value of 0 was assigned. The same could be possible with sugared guards, which have already been proposed and discussed.

Tino already commented on 3. For me, this adds way too much magic and makes guard harder to understand.

So in my opinion the downsides far outweigh what little value this change would add.