Returning a Bool in a function - swift

I'm getting the error "missing return in function expected to return 'Bool'" but I can't figure out why.
func isPrime(_ number: Int) -> Bool {
for primeDivisors in 2..<number {
if number % primeDivisors == 0 {
return true
} else {
return false
}
}
}
isPrime(13)

Your prime checker is incorrect, because the very first iteration of the loop returns a value. You have to go through the entire loop before deciding that the number is prime.
func isPrime(_ number: Int) -> Bool {
for primeDivisors in 2..<number {
if number % primeDivisors == 0 {
return false
}
}
return true
}
Note that this code is inefficient, because it continues checking divisibility more times than it is necessary: you can stop checking upon reaching square root of number.

It's complaining because not all code paths end up returning something. What happens if number is less than 2? Then your for loop, and the return statements inside it, will never be called, and there's no return that happens after the for loop finishes.

Related

Swift Scope - Returning if and for results from a function

How do i get the result of of i to return from the function here? I can return it from inside the if { } but then I get an error there’s no global return (for the function). My goal is to write a function that accepts an Integer and returns the square root. My next step is to throw an error if it's not an Int or between 1 and 10,000, but please assume simple numbers for this question.
let userInputInteger = 9
func squareRootCheckpoint4(userInputInteger: Int) -> Int {
for i in 1...100 {
let userInputInteger = i * i
if i == userInputInteger {
break
}
}
return i
}
update:
To be able to return it, you will have to declared a variable outside the for-loop, then based on the logic assign the "i" counter to that outside variable.
func squareRootCheckpoint4(userInputInteger: Int) -> Int {
var result = 0 // this is to keep the result
for i in 1...100 {
let powerOfTwoResult = i * i
if powerOfTwoResult == userInputInteger {
result = i // assign result variable based on the logic
break
}
}
return result // return result
}
The error shown is because if the for-loop finishes without any hit on the if statement, the function will not be able to return any Int. That's why the compiler produces that "no global return" error.
One way to do it if you don't want to return a default value is to throw an error. You could throw an error from a function (https://docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html). For example for your goal of returning square root of an integer and throw error if the input integer is not between 1 and 10000 (if I understand correctly), you could do something like this
enum InputError: Error {
case invalidInteger
}
func squareRootCheckpoint4(userInputInteger: Int) throws -> Int {
if userInputInteger < 1 || userInputInteger > 10000 {
throw InputError.invalidInteger
}
// calculate square root
return resultOfSquareroot
}
// and to handle the error, you could encapsulate the squareRootCheckpoint4 function in a do-catch statement
do {
let squareRootResult = try squareRootCheckpoint4(userInputInteger: 4)
} catch InputError.invalidInteger {
// handle your error here
}
Alternatively, you could do a validation on the input integer separately before calling the squareRootCheckpoint4 function. For example
func validate(_ input: Int) -> Bool {
if userInputInteger < 1 || userInputInteger > 10000 {
return false
}
return true
}
func squareRootCheckpoint4(userInputInteger: Int) -> Int {
// calculate square root
return resultOfSquareroot
}
var input: Int = 9
if validate(input) {
let squareRootResult = squareRootCheckpoint4(input)
} else {
// handle when input is invalid
}
A couple of things are swapped around, and something (anything) needs to be returned from the function. The framing of the question only allows solutions that don't work if the input is not an integer with a square root.
List of Specifics:
The function argument name userInputInteger should not have been used to instantiate a new object. That's confusing. I did it because I'm learning and thought it was necessary.
Instead, i times i (or i squared) should have been assigned to a new object.
The if statement should be equal to this new object, instead of i.
Functions should return something. When i is returned in the if statement, it's not available anywhere outside the for loop. The print statements in the code example help explain what is available in these different scopes, as well as what's not.
The for loop stops when i is returned. That happens when the guess (i) is equal to the input (userInputInteger).
The for loop will continue through 100 if the input doesn't have a square root.
The function should return the correct number that the if statement was trying to guess, but you have to tell it to (with a return statement) and do it in the right spot. This is the "global return" error. However, because this approach in the question is setup poorly without error handling, only an Integer with a sqare root will return correctly. And in this case, the function's global return doesn't matter; Swift just requires something be returned, regardless of whether or not it's used.
Code Example - Direct Answer:
import Cocoa
let userInputInteger = 25
let doesNotMatter = 0
print("sqrt(\(userInputInteger)) is \(sqrt(25))") //correct answer for reference
func squareRootCheckpoint4(userInputInteger2: Int) -> Int {
var j: Int
for i in 1...100 {
print("Starting Loop \(i)")
j = i * i
if j == userInputInteger2 {
print("i if-loop \(i)")
print("j if-loop \(j)")
return i
}
print("i for-loop \(i)")
print("j for-loop \(j)")
}
//print("i func-end \(i)") //not in scope
//print("j func-end \(j)") //not in scope
//return i //not in scope
//return j //not in scope
print("Nothing prints here")
// but something must be returned here
return doesNotMatter
}
print("Input was \(userInputInteger)")
print("The Square Root of \(userInputInteger) is \(squareRootCheckpoint4(userInputInteger2: userInputInteger))")
Code Example - Improved with Error Handling
import Cocoa
enum ErrorMsg : Error {
case outOfBoundsError, noRootError
}
func checkSquareRoot (Input userInputInteger2: Int) throws -> Int {
if userInputInteger < 1 || userInputInteger > 10_000 {
throw ErrorMsg.outOfBoundsError
}
var j : Int
for i in 1...100 {
print("Starting Loop \(i)")
j = i * i
if j == userInputInteger2 {
print("i if-loop \(i)")
print("j if-loop \(j)")
return i
}
print("i for-loop \(i)")
print("j for-loop \(j)")
}
throw ErrorMsg.noRootError
}
let userInputInteger = 25
print("Input was \(userInputInteger)")
do {
let result = try checkSquareRoot(Input: userInputInteger)
print("The Square Root of \(userInputInteger) is \(result)")
} catch ErrorMsg.outOfBoundsError {
print("out of bounds: the userInputInteger is less than 1 or greater than 10,000")
} catch ErrorMsg.noRootError {
print("no root")
}
print("Swift built-in function for reference: sqrt(\(userInputInteger)) is \(sqrt(25))") //correct answer for reference

In Swift functions, why 'return' must be outside for loop, when function includes a for loop with if statement inside the loop? [duplicate]

This question already has answers here:
Swift function compiler error 'missing return'
(3 answers)
Closed 2 years ago.
Assume a returning function:
func check(scores: [Int]) -> Bool {
for score in scores {
if score < 80 {
return false
}
}
return true
}
The above code works perfectly. However the below code doesn't. An error pops up saying: Missing return in a function expected to return 'Bool'. I know this error very well but I don't know why it is popping up here:
func check(scores: [Int]) -> Bool {
for score in scores {
if score < 80 {
return false
}
else {
return true
}
}
}
Why the 'return false' can be inside the if condition {} but the 'return true' can not be inside the else {} and must be completely outside the for loop ... ...? I ask this specially because the below code works perfectly and the 'return true' is inside the else {}
func isPassingGrade(for scores: [Int]) -> Bool {
var total = 0
for score in scores {
total += score
}
if total >= 500 {
return true
} else {
return false
}
}
Any insight is highly appreciated and kind regards.
This is because of the assumption that the for loop may not execute at all if scores is empty here
func check(scores: [Int]) -> Bool {
for score in scores {
if score < 80 {
return false
}
else {
return true
}
}
}
so the function need to know what it should return in that case , your first and last blocks are ok as there is a guarantee that some Bool value will be returned in case the for loop is executed or not
In case you ask that the sent array will not be empty , yes but at compile time there is no way to know that , hence the error
If scores is empty, the body of the for loop will not be executed, and the check function will not return anything. It does, however, promise to return a Bool, and that's why it's an error.

Swift Bool Function return will never executed

I want to create a code which can determine whether the character is one of the symbols in my list.
var symbols = ["+","-"]
func issymbol(last:String ) -> Bool{
return true
for i in 0...(symbols.count){
if last == symbols[i]{
return false
}
}
}
You need to add return true at the end and it will execute if last == symbols[i]{ never met. So update your code as shown below:
func issymbol(last:String) -> Bool{
for i in 0...(symbols.count){
if last == symbols[i]{
return false
}
}
return true
}
issymbol(last: "+") //false
Or you can use contains property for that:
func issymbol(last:String) -> Bool{
return !symbols.contains(last)
}
issymbol(last: "+") // false
issymbol(last: "1") // true
No code execute after return keyword. so I update your code try this
var symbols = ["+","-"]
func issymbol(last:String ) -> Bool{
for value in symbols {
if last == value {
return true
}
}
return false
}
Functions only execute until they reach a return statement. Xcode detected that the rest of the code in that function won't be executed, because your function will always return after the first line. You probably meant something like this:
var symbols = ["+","-"]
func issymbol(last:String ) -> Bool{
for i in 0...(symbols.count){
if last == symbols[i]{
return false
}
}
return true
}
Because the return statement is after the for loop, the for loop can execute. This function will return true if the string you pass in is not in the symbols array.
There are a lot issues in this code.
The line return true returns immediately so the check won't be performed (the error message).
The line for i in 0...(symbols.count) will crash because the index starts at 0 and the last index is symbols.count - 1. Alternatively you can write for i in 0..<symbols.count.
The best syntax is not to write an index based loop:
for symbol in symbols { if last == symbol ...
If the item is found the code returns false rather than true.
The code doesn't return a Bool after the loop if the item was not found (will cause another error).
The correct code is
let symbols = ["+","-"]
func issymbol(last: String) -> Bool {
for i in 0...symbols.count - 1 {
if last == symbols[i] {
return true
}
}
return false
}
However this can be reduced to
func issymbol(last: String) -> Bool {
return symbols.contains(last)
}

Return a boolean from a closure

I have been searching in Swift documentation and googling but can't find how to return a value from a block like this:
func checkIfplayerFellDown() -> Bool {
self.enumerateChildNodesWithName("brick", usingBlock: {
(node: SKNode!, stop: UnsafeMutablePointer <ObjCBool>) -> Bool in
if (node.position.y < self.player.position.y) { return false }
})
return true
}
The problem is because I do not understand blocks. I usually use them like this:
world.enumerateChildNodesWithName("name") {node, stop in
if (node.position.y < self.size.height*0.5) {
node.removeFromParent()
}
}
How can I return a boolean from any of this closures? I know I should probably use a syntax out somewhere and I tried some things but none of them worked because I have no idea how the blocks even work.
Any explanation or an example of how this should be done is appreciated.
Use a local variable (outside the block but inside the method) to pass the result out of the block, and also set stop to true when you want to stop the iteration:
func playerFellDown() -> Bool {
var result = true
self.enumerateChildNodesWithName("brick") { (child, stopOut) in
if child.position.y < self.player.position.y {
result = false
stopOut.memory = true
}
}
return result
}

Cannot change tuple in an array

I'm trying to change a tuple in an array , however ,when I try
emo = (type:emo.type,strength:increaseStrength(emo.strength))
it gives me error
"cannot assign to 'let' value 'emo'
here is my code :
var emotions : [(type : String, strength: Int)] = [("happy",0),("scared",0),("tender",0),("excited",0),("sad",0)]
func increaseStrength(i:Int)->Int {
switch i {
case 0: return 1
case 1: return 2
case 2: return 3
case 3: return 0
default :return 0
}
}
#IBAction func HappyBA(sender: AnyObject) {
for emo in emotions {
if (emo.type == "happy" ){
emo = (type:emo.type,strength:increaseStrength(emo.strength))
}
}
println(emotions)
}
If there are better way to do the assignment please tell me I am so appreciated ! Thanks..
There is no point assigning to emo even if you could do it. This is not the same as replacing the corresponding object in the array - which is what you do want to do. emo is a copy; even if you were to set a property of it, it wouldn't affect the one back in the array. And certainly setting the variable would not magically read back into the array!
Here's one solution. Instead of cycling thru emotions in your for-loop, cycle thru enumerate(emotions). Now you have a tuple of an index number along with an emotion. If this is the right emotion type, write into the array via the index number.
for (ix,emo) in enumerate(emotions) {
if emo.type == "happy" {
emotions[ix] = (type:emo.type,strength:increaseStrength(emo.strength))
}
}
Or you could use map.
emotions = emotions.map {
emo in
if emo.type == "happy" {
return (type:emo.type,strength:increaseStrength(emo.strength))
} else {
return emo
}
}