Code after return statement gets executed even if function does not specify a return type

Just spent a while trying to figure out a bizarre, paranormal bug:

I had a function for testing physics components for a game. One entity was moving faster than the other despite being exactly the same.

Turns out that it was being added to the scene twice because code after a return was being executed:

You can replicate this in a Playground:

var wth = 0

func SwiftPlease() {
    wth += 1
    return
    wth += 1 // ⚠️ Expression following 'return' is treated as an argument of the 'return'
}

SwiftPlease()
print(wth) // Can you guess what this will be?

I can almost see what's happening here, but why allow an argument for the return at all if the function's signature does not specify a return value?

1 Like

Try adding semicolon after a return you should be fine.

1 Like

I would be very surprised/disappointed if this fixes it.

@SubjugaterCephalopod Have you tried doing a clean build? I suspect your code's just running some old version before the return was put in.

+= returns Void, and you're free to explicitly return Void.

5 Likes

Perhaps this should be a compiler warning. Since it's technically valid, but likely not something people would be doing.

This seems to be a known issue, reported as SR-2028 "return" in func returning void should not have an argument.

There is an warning, but it seems to be delayed.

I‘d be against a warning because I frequently use that in the else body of a guard statement. There is nothing wrong learning that several operators including = return Void and using that in combination with return.

To me this is a programmer mistake, not a bug, since in Swift there is always a return type, but for convenience it could be implicit. Not understanding this fact is a source of bugs.

4 Likes

I’m quite interested as to why you’d do that instead of just using multi-line statements, or is it just purely stylistic choice?

I’d say it’s a rarely-used fact, and most programmer won’t ever need to think in terms of Void-returning function.

Anyhow, I don’t have a strong opinion on this matter. I know of the technicality of it (for a long time actually). I still feel that it’d be hard to read if I actually use it, but that’s about it.

This :point_up:.

This should be the else body from a guard statement.

// #1
return self.foo()

// #2
self.foo()
return

#2 feels redundant to me and therefore I prefer #1.

1 Like

In a lot of async code that take a completion handler, the completion handler is semantically like a (delayed) return value. You need it on every early return path.

guard condition else { return completion(nil) }

…neatly mirrors return nil in a synchronous function.

2 Likes

I would always have return and its argument on the same line though. Using a newline between the two would probably put me off.

I am also fond of

return voidReturningFunction()

and would be dismayed to have it produce a warning, but I would not be sad to see

return
voidReturningFunction()

produce a warning. Does anyone have a use case for why it shouldn’t be discouraged? Assume we’re being conservative and no warning is produced for

return operand
    += otherOperand
6 Likes

That does produce a warning, and the warning is shown in the original post.

1 Like

I'm also an avid user of return funcThatReturnsVoid() in callbacks and guard clauses, but if this is a impediment for new Swift users, I would relent.