swift when should return have parenthesis and when does it not matter? - swift

Is there ever a case where "return n" will cause a problem due to something within ". . ." ?
func foo() -> Int
{
. . .
return n
}
Or, should I always use return( n ) ?
func foo() -> Int
{
. . .
return( n)
}
UPDATE...
The main reason for this question is trouble I once had in viewDidLoad() where the final instruction line was simply "return" because I didn't believe () were needed. However, I had several lines below, which got executed.
(I had temporarily inserted the line with just "return" while debugging.)
This caused confusion and took a while to debug.
From then on, my policy was to always use return( . . . ) and never saw the problem again.
Someone on StackO explained this Swift behavior, but I don't remember the explanation.

I don't think the parentheses are needed unless you declare your function to return a tuple.
As gnasher says in their answer, the parens in the return are weird.
I seem to remember that a function result in Swift is always considered to be a tuple, where Void is a special case empty tuple. If my (vague) memory is correct that might explain why the parens are valid. I need to see if I can dig that up.

The parentheses are absolutely weird. They are weird in C, in Swift they are bizarre.
And since space is relevant in Swift, your weird spacing makes it even weirder.
As a rule, you don’t write anything unnecessary in Swift.

Here is answer to my question:
Parens are only needed if line with "return" is between lines of code
in same func. Other than that case, as far as I know, parens after
return are superfluous.
Here is my test for proving this............
With this code (no parens after return)...
print("viewDidLoad Abort.")
return
print("viewDidLoad WTF!")
...I get:
viewDidLoad Abort.
viewDidLoad WTF!
But, with this code (parens after return)...
print("viewDidLoad Abort.")
return()
print("viewDidLoad WTF!")
...I only get:
viewDidLoad Abort.
Thus, in response to all the esteemed advice above, I shall not use parens after return, unless temporarily aborting a func by using "return()" unless there is a better way to temporarily abort func.

Related

Swift - understanding return types in recursion: when should return the function vs. just return on its own

This may be a little too general for this forum, but hoping someone can explain this in a way that makes sense to my brain. I've tried reading and researching and have found lots of examples - but I still don't understand the "why" which means that I am not understanding exactly how a program comes back from a function return.
Here is a very simple function I wrote that solves a puzzle using backwards recursion. It works well.
func solver(grid: [[Int]])->[[Int]] {
var returnGrid = constraintPropogation(grid: grid)
if contradictionCheck(grid: returnGrid) == false {
return returnGrid
} else {
if returnGrid.flatMap({$0}).filter({$0 == 3}).count == 0 {
print("SOLVED**********")
gridPrint(grid: returnGrid)
print()
stopFlag = true
stopAnswer = returnGrid
return returnGrid
} else {
let randStart = getRandomStart(grid: returnGrid)
returnGrid[randStart.x][randStart.y] = 0
solver(grid: returnGrid)
returnGrid[randStart.x][randStart.y] = 1
solver(grid: returnGrid)
}
}
if stopFlag == true {return stopAnswer}
return solver(grid: returnGrid)
}
My issue is understanding the returns. In the third line of the function if a contradiction check fails this means that we've gone down a path that would not be possible. Therefore we return. That makes sense. The second return in the middle of the function occurs when the puzzle is solved, so it makes sense to return there. But the last one at the end "return solver(grid: returnGrid)" is challenging to my understanding. Here we are returning but also calling this same function again. This is not going deeper into the potential solution path (that happens in the "else" section where the function is called). Why do we need to call the function again rather than just returning? What is happening under the hood? Does the return happen first where we "pop back up a level" and then we are calling the function again effectively one rung higher on the stack? When I write these words I realize that I have a vague understanding - but somehow it is not all clicking together for me.
Am at the point now that when I'm writing functions that involve recursion I just try both returning on own or returning and calling function again to see which one achieves what I want. But I'd really like to understand it rather than just guessing. If anyone had a simple explanation I would appreciate it.
Your function solver takes an array of arrays, and returns an array of arrays. Any call to return(something) returns that something to the caller.
Saying return(someArrayOfArrays) means you are done, and have a result.
Saying return(solver(someArrayOfArrays)) says "call this function again, passing in a new value. Return whatever the result is as the function result." The current call to solver() is done doing work, and passes its intermediate results to another call to the function. That's the recursion. You can think of this as nesting a function call inside a function call inside a function call, or stacking function calls on top of each other.
The call to solver(grid: returnGrid) does not make any sense. That is a recursive call, but you ignore the result. Thus, that call does nothing useful. If your remove that line, it won't make any difference to the outcome. That line is saying "Go do a bunch of work and find an answer for me, but I will throw away your answer". The compiler should give you a "function result ignored" warning at that line.
Beyond that, I can't tell what your code is doing. It appears to be modifying at least one global variable, "stopAnswer". That suggests it's not a pure recursive function.

Swift execute code after return, unbelievable

I created a tableview and there is a toggle in a cell, I click the toggle there will be a function in the cell's protocol, and in the implement of the function I have a logic like this:
The print function after the return is executed! can't believe this anybody know why? Or this is a bug of apple?
The warning in your screenshot tells you exactly what's happening:
Expression following ‘return’ is treated as an argument of a ‘return’.
When return is being called it sometimes takes an expression, which in this case is a function.
If you don't want the print statement to be part of the return, you could add a ; to the end of return

Is there *any* situation under which "for _ in [1,2,3]" will not loop at all?

I was writing some code and made a mistake that simplifies to:
func f() -> Int {
for _ in [1,2,3] {
return 1
}
}
And the compiler shows me an error saying that f is missing an return, which caused me to realise my mistake. I forgot to put an if statement around the return!
But then I realised that the compiler is actually lying! The function will always return a value. Or will it? Is there any situation under which the for loop will not loop?
I'm asking this because other tautological constructs compiles fine:
if 1 < 2 {
return 1
}
while true {
return 1
}
And I also understand that the compiler can't evaluate every expression at compile time to see if they are tautologies. I know properties accesses and method calls usually don't get evaluated at compile time, so this is not expected to compile:
if "".isEmpty {
return 1
}
But generally literals are ok, right? After all, the compiler has to evaluate the literal [1,2,3] to translate it into machine code that says "create an array with 1, 2, 3".
So why is it not smart enough to figure out the for loop? Will the for loop not get run in some rare situation?
While for a human it is trivial to see that the loop will always repeat three times, because the list literal is a constant with three elements, this is a non-trivial thing to see for a compiler at the level of semantic analysis.
During semantic analysis, the compiler will evaluate "a generic list literal" ([1,2,3]) and determine that it is an expression of type Array<Int>. But now, of course, the information that this is a constant or that this array contains three elements is lost.
Semantic analysis is normally performed using the same (or a very similar) type system the programmer is using. Since there would be little benefit from attaching the number of elements in an array to the type (the number of elements is normally not known at compile time) compared to the cost, this is normally not done. On the other hand, constant folding (if 1 < 2 {) is easier to implement and occurs more often.
While on a lower-level the compiler will likely unroll this loop and use constant values, this happens much later – in Swift after generating the Swift Intermediate Language representation – and probably only just during code generation – after SIL has been emitted to LLVM IR and when LLVM optimizations are run.
for-in doesn't know if all it's going to get from an iterator is nil. You'll get the same error message, Missing return in a function expected to return 'Int', no matter what the sequence is.
extension Bool: Sequence, IteratorProtocol {
public func next() -> Void? { () }
}
for _ in true {

Swift for in loop with parentheses

I normally use the for in loop in swift without parentheses, but today I put them on just for kicks thinking they were just optional and it did not worked as expected.
This code works:
if let tasks = getAllTasksWithManagedObjectContext(appDelegate.managedObjectContext){
for task in tasks{
appDelegate.managedObjectContext.deleteObject(task)
}
}
This one does not:
if let tasks = getAllTasksWithManagedObjectContext(appDelegate.managedObjectContext){
for (task in tasks){
appDelegate.managedObjectContext.deleteObject(task)
}
}
I get this errors:
Whats going on here?
You are simply not allowed to use parentheses here.
Take a look at the Language Reference -> Statements and compare the C-style for-loop against the swift for-in
for-statement → for­ for-init­;­expression­;­expression­ ­code-block
for-statement → for­ (for-init­;­expression­;­expression­) ­code-block
vs.
for-in-statement → for ­case(opt) ­pattern ­in ­expression ­where-clause­(opt­) code-block
The first one can be used with or without parentheses - your choice as the developer.
However the later one, the one you are actually asking about does not have a version with ( and ), only the one version without them. That means that it is not allowed to use them parentheses around the "argument" of the loop.
Screenshots from the docs linked above for better readability:
vs.

What'S the difference between these two initialization snippets? Which one is correct?

While looking through some code, I found two different code snippets for initialization. I don't mean the method names, but the round brackets.
This one has just two of them:
if (self = [super initWithFrame:frame]) {
That's the way I do it all the time, and it seems to work. Now in an Apple example I found this:
if ((self = [super init])) {
Do I have to put it twice into round brackets here? Or is it just fine to put it in one pair of brackets, like the first example?
One pair of brackets is just fine
I call them "paranoia brackets" :)
EDIT: some C/C++ compilers will issue a warning because of the use of the assignment operator (it will say something like "did you mean ==" ?). Using extra parentheses prevents this warning. But XCode doesn't show this kind of warning, so there's no need to do that.
In some languages, if( foo = bar ) implies that the assignment was correctly applied. So the calls:
if( ( foo = bar ) )
would evaluate the assignment and return the result as the outer () act as a LHS, ie,
blah = foo = bar
the outer () act sort of like blah.
In ANSI C and it's children C++ and Objective-C this isn't strictly necessary. However as has been mentioned some compilers will issue a warning since the "=" / "==" type-o can be a nasty one. That type-o led to the idiom of putting the invariant or constant at the left hand side to cause compile time catching of the problem:
if( nil == foo )
if both sides are variables though it's still possibly a mistake.
There is a good reason for doing this even though gcc isn't warning you or evaluating things differently.
If you are writing code in a team environment your peers may not be sure you meant "=" or just mistyped "==", causing them to peer more closely at what you're doing even though there's no need to. In the style of "write once to be read 1000 times" you put in clues to prevent people from having to waste time when reading your code. For instance, use clear and spelled out variable names (no economy on bytes these days!). Don't use obtuse and overly optimized constructs in areas that aren't drags on performance - write your code cleanly.
In this case, use (( )) to indicate you knew it was "=" not "==".
Don't forget, Apple is writing their examples for not just a dozen people to read, but potentially every man, woman, and child on earth to read now and in the future. Clarity is of upmost importance.
Looks like a cut and paste error to me! (Or a lover of Lisp.) There is no good reason to have the second pair of brackets but, as you note, it's not actually harmful.
If I've got this right the first one checks that the assignment self = [super initWithFrame:frame] happens and the second one checks that the result of that assignment is true
But this could just be a lack of tea speaking...