Essentially while this is certainly a basic question with numerous reasons, I cannot seem to understand why it would be good idea to use throw when writing functions that validate.
For example if you take this simple username and password validation scenario, why would anyone want to use throw to help with the validation?
Does it just come down to coding style preference? Or is there a good reason one would opt for using throw for the return of this function?
enum ReturnMessages: String {
case passed, failed, tooshort, nonumbers
}
func validateCredentials(username: String, password: String) -> ReturnMessages {
guard (username.count >= 4 && password.count >= 4) else {return ReturnMessages.tooshort}
guard (password.rangeOfCharacter(from: .decimalDigits) != nil) else {return ReturnMessages.nonumbers}
return ReturnMessages.passed
}
validateCredentials(username: "jeff", password: "password")
Returning an enum value in this case is fine because the possibility to fail is quite high.
But consider that you have to use always a switch to distinguish the good from the bad path.
On the other hand in many cases the expected result is passed or some return value with a very low rate of errors. So isnβt it a better idea to return the good path directly and throw the bad paths.
The benefit is that you can continue your workflow without a runtime check good/bad.
Related
I was wondering how I can enforce the following restrictions on this struct:
struct QandA {
let questions: [String] // Question to be displayed per page
let mcqs: [[String]] // Prompts to be displayed per page
let answers: [Int] // Answer will be the correct index
}
questions.count == mcqs.count == answers.count
forEach mcq in mcqs, mcq.count == 4 (must only be 4 options per mcq)
forEach answer in answers, answer < 4 (correct index must be 0...3)
The reason for this is that I think it would be very easy to perhaps, add an extra question, or even say the correct answer is 4 when I meant to put 3 (off by 1 error), and also add an extra prompt when there are only meant to be 4 multiple choices per question.
To protect myself from these errors here is what I think I can do:
Option 1
init?(questions: [String], mcqs: [[String]], answers: [Int]) {
guard
questions.count == mcqs.count && mcqs.count == answers.count,
mcqs.allSatisfy({ $0.count == 4 }),
answers.allSatisfy({ $0 < 4 })
else {
return nil
}
self.questions = questions
self.mcqs = mcqs
self.answers = answers
}
Option 2
init(questions: [String], mcqs: [[String]], answers: [Int]) {
assert(questions.count == mcqs.count && mcqs.count == answers.count)
assert(mcqs.allSatisfy({ $0.count == 4 }))
assert(answers.allSatisfy({ $0 < 4 }))
self.questions = questions
self.mcqs = mcqs
self.answers = answers
}
Option 3
Have my Views deal with these issues and have no management code for initialisation; perhaps use try-catch blocks somewhere?
Option 4
Just make sure I don't mess up when creating QandA's
My question is whether I should not allow a QandA instance to be initialised unless these restrictions are met (option 1); or should I add preconditions / asserts to not allow my code to continue if I mess up somewhere (option 2); or should my app just allow these things and me as a coder should take on the full responsibility of making sure the data is consistent, possibly making use of error handling (option 3 & 4). Perhaps using a #propertyWrapper may be the best option? What even are the pro's and con's of these different approaches?
I'm also wondering what is considered "best practice" for situations like this.
Thanks in advance.
If you really want to exclude invalid states, then you could consider modelling your quiz like this:
struct QandA {
let question: String
struct Right {
let value: String
}
struct Wrong {
let value: String
}
enum Options {
case A(Right, Wrong, Wrong, Wrong)
case B(Wrong, Right, Wrong, Wrong)
case C(Wrong, Wrong, Right, Wrong)
case D(Wrong, Wrong, Wrong, Right)
}
let options: Options
}
struct Quiz {
let questions: [QandA]
}
Here you can't have more than 4 (3 wrong + 1 right), and you must have exactly one right answer in the options.
If you find that you have two collections, e.g. [A] and [B] and you need them to be the same size always, you probably mean to say you have an array of pairs of A's and B's, like [(A, B)], and often where you have tuples, like pairs, then there's a named Struct that's waiting to be created.
You almost always want to make your data structure smart so your algorithms don't have to be. Use knowledge of "type algebra" to refactor invalid states out of existence - a classic example you can find online if you search, is the refactoring of the types in the completion handler of URLSession dataTask(with:completionHandler:) - some of which are not valid - into a type that make those invalid states inexpressible. The key idea is that sum types (enum) and product types (structs) can be thought of just like algebra A+B and A*B, and can be literally refactored just the same.
We are working in a Swift project. A function was there like,
fun getSleepAmmount() -> Int {
// calculate sleep time
// return value when valid
// else
return -1
}
My team member prefers the above function where caller needs to check with -1 which is not I am comfortable with. My suggestion is to redesign with nil return (although callers still need to check nullability) like,
fun getSleepAmmount() -> Int? {
// calculate sleep time
// return value when valid
// else
return nil
}
But my colleagues do not want to redesign. Which version of the functions is cleaner and why?
Obviously, nil is much cleaner. Because of -1 means nothing. This is just a magic word. It is difficult to support, refactor and handle this case.
Returning nil is a better solution instead of using any garbage or default value.
Returning any default value may in future clash with the actual result.
Also, there might be other developers dealing with the same code. So, using nil will have a better explanation than using -1.
Second is the better as youll do
if let v = getSleepAmmount() {}
But with First
let v = getSleepAmmount()
if v > 0 {}
Returning nil means this isn't a valid return while -1 may mean another thing that will be miss-understood by a new developer that checks the code
If there is code in the caller that should only run if there is a valid sleep amount, then optionals is the better and clearer way to go. This is exactly what guard let and if let are designed for:
guard let sleepAmount = getSleepAmount() { else return }
// do something with sleepAmount
An even better way would be to throw an error inside the function:
func getSleepAmmount() throws -> Int {
// calculate sleep time
// return when valid
// else
throw InvalidSleepAmount
}
Then
do {
let sleepAmount = try getSleepAmount()
// do something with it
} catch InvalidSleepAmount {
// error processing
}
(If you want, your function could throw different errors so the caller gets to know why the sleep amount is invalid, SleepTooShort, SleepTooLong, NoSleep etc)
I'm new to coding and am about to finish the "Intro to App Development with Swift" iBook. I am currently in lesson 19, Enumerations and Switch and, at page 8 of the associated playground it shows the following code:
enum LunchChoice {
case pasta, burger, soup
}
func cookLunch(_ choice: LunchChoice) -> String {
if choice == .pasta {
return "π"
} else if choice == .burger {
return "π"
} else if choice == .soup {
return "π²"
}
return "Erm... how did we get here?"
}
cookLunch(.soup)
Per se, this is not a problem for me to understand but, once I call cookLunch(.soup), the last return statement doesn't show up.
The exercise just below ask me:
try to change the value passed in to cookLunch so that the final else statement is called
And that is where I got stuck because it seems impossible to pass something different to the cookLunch function other than the choices present in the enumeration.
Could you help me understand the sense behind all this and maybe provide me a solution?
You have two options:
Comment out the third comparison
// } else if choice == .soup {
// return "π²"
Add a fourth case which is not covered by the comparisons
enum LunchChoice {
case pasta, burger, soup, steak
}
and pass it:
cookLunch(.steak)
However nobody would seriously write such an if - else chain, in Swift a switch expression is appropriate
func cookLunch(_ choice: LunchChoice) -> String {
switch choice {
case .pasta: return "π"
case .burger: return "π"
case .soup: return "π²"
default: return "Erm... how did we get here?"
}
}
Your instructions say "so that the final else statement is called". That would be the soup return, not the "how did we get here" return. As you say, with 3 lunch choices and 3 if/else statements, one of them will always be invoked. You have to add a 4th lunch choice that doesn't have a corresponding if or else if in order for the "how did we get here" code to execute.
I have encountered numerous situations where a coder have used the guard keyword. And then later, in a seemingly almost identical situation the same coder in the same code does not use the guard keyword. I am aware that this may be a stupid question, so please don't bash it. When should I use the guard keyword and where shouldn't I?
Here is an example (there are many more). This is part of a script that is requesting data form an API.
//Here I am using guard
guard let json = json else {
//Now I am not using guard
if let error = error {
completion(.Failure(error))
} else {
//Error handling
}
return
}
Why not use the:
if let var1 = var1 {
//Keep on going
} else {
//Don't crash
}
syntax all the time instead of the guard syntax? At first glance it even seems to have more functionality, but I am certain that does not have to be the case.
One great benefit of the guard statement is that you know that if the condition is not satisfied then the execution flow gets stopped.
This is important for several reasons
Unwrapping
You can define unwrapped values which don't need a new scope { ... } to be available
func next(num:Int?) -> Int? {
guard let num = num else { return nil }
return num + 1
}
Readability
When you read the code you know that if the guard condition is not satisfied then the following lines won't be executed.
Semantics
You know a guard statement is there to check conditions required for the following block of code.
But I can replace every guard with an if
Sure. We could also replace every while and for with a goto in some languages. And we could always replace recursion with iteration (and viceversa).
But this doesn't necessarily means it is always a good idea.
Despite we can implement some behaviours with more then one programming "tool", we should still use the one that better fits that specific scenario.
I'm writing some debug code to which I need to pass a parameter of type Any. For printing purposes I'd like to unwrap the parameter value iff it's an optional, but I can't figure out how to test that - every syntactic form I can think of is rejected by the compiler. E.g.,
switch val {
case as Optional<Any>:
.
.
and a variety of let forms (including trying .dynamicType) aren't legitimate. Does anyone know how to actually do this? Overall, what I'm trying to accomplish is such that whether or not the value is an optional, I get the actual value into a string and not Optional.
Martin is absolutely correct. From the linked post, modified slightly because I wanted a different return for nil:
func unwrap(any:Any, ifNil: Any = "nil") -> Any {
let mi = Mirror(reflecting: any)
if mi.displayStyle != .Optional {
return any
}
if mi.children.count == 0 { return ifNil }
let (_, some) = mi.children.first!
return some
}