String pattern matching in Swift switch statements - swift

I have a problem with pattern matching in swift switches. I need to check a string to see if it contains some characters and return data according to that.
I have the following (shortened) code:
static func getCorrectChords(chord: String) -> [Chord] {
    let test = chord
switch test {
case let x where x.contains("-") && x.contains("2"):
return allChords[8]
///// other similar statements
default:
return allChords[0]
}
}
If I pass the string “RE-2” to the function, it switch over all the statements and then goes with the default case. If I try a very similar code in Playgrounds, it works correctly.
Is there anything I’m doing wrong? How can I obtain the proper return value?
Thank you very much!
Edit: corrected braces and indentation in the code. Solution is now in the answers.

I found the issue. I did not isolate the problem correctly.
The issue was that my source data had a slightly different "-" character which Swift (rightly so) did not consider equal to the condition in the switch cases. I sanitized the inputs and now it works correctly. In the playground I did manually write the input so the issue did not arise.
Thank you so much anyway!

Related

Is there a way to use switch on an array that includes wildcards in swift?

I want to do this:
var arr = [0,1,0,1,0,2,1,0,0]
switch arr {
case [1,_,_,_,_,_,_,_]: print("Yay")
default: print("Nay")
}
But I get this error: "'_' can only appear in a pattern or on the left side of an assignment"
I searched around on this error message and "wildcards swift array switch statements" and it seems like it is not possible to use wildcards in this context, but there may be some sort of workaround using 'operator overloading' with something involving ~=. However, this is way over my current knowledge, I haven't found a case example exactly like mine, and there seems to be a fair amount of implied concern that operator overloading is bad for some reason. Also, the examples I've found that is sort of like my case look very convoluted. I'm a self-taught amateur just trying to hack together a basic app to make my work life easier, so apologies for any stupid questions but I'd like to better understand the following:
Why can't I use wildcards in this context? It seems like they work with tuples but not arrays for some reason, and I don't get why one would work but not the other.
Is operating overloading actually 'bad' and is there a relatively straightforward way to implement this functionality?
If not- can someone recommend an alternate approach? I chose this approach because I have two arrays, one for a series of questions, one to record responses to each question. I want to implement pretty complicated logic where the configuration of responses to prior questions will determine which question is presented next (example below). I wasted a bunch of time drowning in convoluted 'if' statements before realizing I needed a cleaner approach and this seemed to be it. However, without wildcards or something similar, it would not be practical to explicitly define every case. Could someone recommend a different approach in this situation? Obviously, this is a streamlined example and there would be many more defined cases. Thanks in advance.
var responseArr = [0,2,1,2,1,0,0] // 0 = unasked, 1 = asked answered no, 2 = asked answered yes
switch responseArr {
case: [0,_,_,2,1,0,_]: nextQuestion = questionArr[0] // If 'yes' to question 4, no to question 5, and questions 1 and 6 were not asked yet, ask question 1
case: [1,_,_,2,1,0,_]: nextQuestion = questionArr[5] // If 'yes' to question 4, no to question 5, no to question 1, and question 6 was not asked yet, ask question 6
...
default: print("error")
}
It seems like they work with tuples but not arrays for some reason
The reason is that a tuple is a multi-value type, each value is evaluated separately, on the other hand an array is one value.
A valid syntax is
switch arr {
case arr where arr[0] == 0 && arr[5] == 2 : print("Yay")
default: print("Nay")
}
The tuple syntax would be something like
switch (arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7], arr[8]) {
case (0,_,_,2,1,0,_,_,_): print("Yay")
default: print("Nay")
}
This is heavily implied by Joakim's and vadian's responses, but for the benefit of other beginners that might come across this- a very simple conversion of the array to a tuple (as below) seems to work perfectly for what I was trying to accomplish in the first place, and only really requires addition of one intermediary variable and replacing some brackets with parentheses:
var arr2 = [0,1,0,1,0,2,1,0,0]
let arr2AsTuple = (arr2[0],arr2[1],arr2[2],arr2[3],arr2[4],arr2[5],arr2[6],arr2[7],arr2[8])
switch arr2AsTuple {
case (1,_,_,_,_,_,_,_,_): print("Yay")
default: print("Nay")
}

Swift 2 to 3 Migration Error Regarding String Concatenation

I have the following code below.
let url = "http://websitehere.com/restapi/v1/userlogin?email="+username+"&password="+password+"&deviceid="+deviceid
For some reason the compiler won't take it. Gives me the following error below.
Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
Why won't the old swift2 code work anymore, what is it even talking about here? If it is too complex, how would I fix it and why is it to complex?
I would always use this format:
let url = "http://websitehere.com/restapi/v1/userlogin?email=\(username)&password=\(password)&deviceid=\(deviceid)"

Is there any technical benefit in adding semicolons in Swift?

I wrote couple of programs in Objective-C.
I've seen that Swift syntax does not require use of semicolons.
My question is - is there any technical point in using them anyway?
The short answer is: No.
Swift does not require a semicolon after each statement in your code. They are only required if you wish to combine multiple statements on a single line.
Do not write multiple statements on a single line separated with semicolons.
Preferred:
var swift = "not a scripting language"
Not Preferred:
var swift = "not a scripting language";
For more informations, please refer to this page:
https://github.com/raywenderlich/swift-style-guide#semicolons
There are (or used to be) situations where two separate statements on two different lines would taken by the compiler as a single statement. The typical locus is return followed by another statement that you don't want executed. In that situation, and in that situation alone, the semicolon is crucial.
override func viewDidLoad() {
super.viewDidLoad()
return // need semicolon here
print(1) // oops
}
However, in modern Swift the compiler warns and compensates. Adding a semicolon (return;) quiets the warning (though it then causes a different warning).
Otherwise, a semicolon never has any technical benefit.
Yes there is, you can write multiple statements in one line. For example you could write statements more compact when needed, for example:
var progress: Progress {
get { _progress.value }
set { _progress.value = newValue; parent?.update() }
}
Use sparingly though. But in this specific case I prefer it instead of expanding everything to a separate line since its still quite readable and only 2 statements.

return inside a switch block yields "unreachable code" warning

I'm writing UnityScript code and at one point in my program, I want to terminate a function from within a switch block. This is a boiled down version of my code:
function Move(target: int) {
var targetTransform : Transform;
switch (target) {
case 0:
// do something including assigning targetTransform
break;
case 1:
// do something including actually moving my object
return; // since I moved already, I want the function to terminate here
default:
// do something including assigning targetTransform
}
object.Move(targetTransform); // object is locally available
}
Now for whatever reason, the Compiler gives me a
Assets/Scripts/GameMaster.js(490,9): BCW0015: WARNING: Unreachable code detected.
The line is the one containing the switch.
From my previous research, I found many similar problems, but all of them had actually unreachable code, like for example break statements after the returns or a return at the end even though each and every case returned at some point. This is not the case here, I just want one of my cases to return out of the function altogether, while the others shall break out of the switch and go on from there.
Is there a way to get rid of this warning? What is causing it in the first place, is this just a bug?
If at all possible, I'd prefer not to use a boolean and check for it after the switch block... This just seems like overkill only to terminate one case early.
This bug exists at least since 2010. Although it's perfectly legal to use a return statement instead of a break, the compiler will complain about unreachable code.
You have basically two options
ignore the warning and keep your code nice and clean
work around the warning by replacing the return with a boolean + break and check for the boolean after the switch block
As far as I know you can't even disable or suppress the warning. It's possible in C# but UnityScript seems to lack this feature. So this would result in a third possible solution: convert your code to C# :-)

iPhone SDK: Please explain why "nil ==" is different than "== nil"

I have been programming iPhone SDK for around 6 months but am a bit confused about a couple of things...one of which I am asking here:
Why are the following considered different?
if (varOrObject == nil)
{
}
vs
if (nil == varOrObject)
{
}
Coming from a perl background this is confusing to me...
Can someone please explain why one of the two (the second) would be true whereas the first would not if the two routines are placed one after the other within code. varOrObject would not have changed between the two if statements.
There is no specific code this is happening in, just that I have read in a lot of places that the two statements are different, but not why.
Thanks in advance.
They are the same. What you have read is probably talking about if you mistakenly write == as =, the former will assign the value to the variable and the if condition will be false, while the latter would be a compile time error:
if (variable = nil) // assigns nil to variable, not an error.
if (nil = variable) // compile time error
The latter gives you the chance to correct the mistake at compile time.
They might be different if you are using Objective-C++ and you were overriding the '==' operator for the object.
They are exactly the same, it is just a style difference. One would never be true if the other is false.
if it's a recommendation that you use the latter, it's because the second is easier to catch if you accidentally type =. otherwise, they are identical and your book is wrong.
They can only be different if the "==" - Operator is overloaded.
Let's say someone redefines "==" for a list, so that the content of two lists is checked rather than the memory adress (like "equals() in Java). Now the same person could theoretically define that "emptyList == NULL".
Now (emptyList==NULL) would be true but (NULL==emptyList) would still be false.