Reputation: 105
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
}
Upvotes: 0
Views: 240
Reputation: 105
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:
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.i
times i
(or i
squared) should have been assigned to a new object.if
statement should be equal to this new object, instead of i
.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.for
loop stops when i
is returned. That happens when the guess (i
) is equal to the input (userInputInteger
).for
loop will continue through 100 if the input doesn't have a square root.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
Upvotes: 1
Reputation: 36
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
}
Upvotes: 1