Swift assignments inside conditions - swift

I was wondering what this code does:
var something: String = "Hi"
if something = "Hello world!" {
// Will this be executed?
}
Will it assign to something variable and do the if body? Or will it set the value of that variable only for the if body and outside it will not change? Or has it anything to do with nil?

Assignments are not expressions that return booleans, so cannot be used inside an if like this. So this won’t compile.
(though you will get a misleading compiler message)

This pattern only works for assignments that can fail — that is, if you're assigning the result of an expression that returns an Optional value. And in that case, you use if let, not just if.

we can't use assignment operator for if condition, you would you if let suppose if you are working with optional types
Here are some operators that helps you get clarity to differentiate from assignment operator
= assignment operator
== is equal to
=== is identical to

Related

Unwrapping Optionals (Swift Playground)

Simple question for you folks about unwrapping optionals.
I've read and seen the multiple examples of unwrapping like the following
var strArray: [String]?
strArray = ["John", "Stacy", "Stephanie" ]
if let forSureNames = strArray{
for name in forSureNames{
print("\(name)")
}
} else{
print("Failed unwrapping")
}
However, My question is for if let forSureNames = strArray{...
When typing syntax similar to C++ (and from some swift examples), adding parenthesis
if (let forSureNames = strArray){
Gives the error codes:
'()' is not convertible to 'Bool'
error: MyPlayground.playground:13:4: error: expected expression in list of expressions
if(let forSureName = strArrays){
^
error: MyPlayground.playground:13:4: error: expected '{' after 'if' condition
if(let forSureName = strArrays){
^
Can anyone help explain the difference?
Edit
First time I asked a question on Stack overflow and feedback is awesome. I was trying to use a similar coding style to C++ due to my familiarity for an easy transition. However, you guys made it clear that it’s an incorrect approach. Thank you for a new and technical perspective towards unwrapping. Cheers!
As you know, () can be used to surround an expression and it will have no effect on the evaluation of that expression, and you are asking "why can't I do the same to let forSureNames = strArray?" Right?
This is because let forSureNames = strArray is not an expression. You are parsing this statement wrong. The word let is part of the if let statement.
You are confusing if let statements with C-style if statements, where after the if, there is always an expression that evaluates to Bool. if let simply does not work like that. It takes the form:
if let <identifier> = <expression> { }
where expression must evaluate to an optional type. So putting () around let <identifier> = <expression> makes little sense. You could put () around strArray because that is an expression, but I don't see the point of that.
if (let forSureNames = strArray) {
... this is trying to use optional binding. Optional binding allows you to safely unwrap some optional constant/variable which can be nil. If this value is assigned, it satisfies the if statement with this unwrapped (non-optional) constant/variable.
But, it doesn't work with parentheses, since values coming from parentheses have to be of type Bool. An optional binding doesn't return a Bool value directly, it just attempts to assign the constant/variable and implicitly returns a boolean based on whether the assignment occurred.
if (true) {...} // works
if (let value = optional) {...} // doesn't work
So, you have to remove these parentheses
if let forSureNames = strArray {...}
Unlike other languages, conditions in Swift don't have to be inside parentheses and it is recommended not to use them if they aren't required.
Swift is vastly different from C++, so you shouldn't be surprised that C++ syntax doesn't work in Swift.
There are two type of if statements in Swift: the type that takes an expression (if foo.bar), and the type that does pattern matching (if let foo = bar, if case .some(let foo) = bar, etc).
Because Swift supports parenthesized expressions, if foo.bar works the same as if (foo.bar): in the first case, the condition is foo.bar, and in the second case, the condition is (foo.bar). In other words, the parentheses here are part of the condition expression, not part of the if statement. This contrasts with C++, where the parentheses are part of the if statement. In both cases, however, you can add as many parentheses as you want: if (((((((((foo.bar))))))))), though silly, is superficially valid in both languages.
Recall that you can wrap arbitrary expressions in parentheses, but you can't just wrap anything in parentheses. You wouldn't write (if foo.bar) in Swift or C++, because you know that if isn't an expression. Then, the same applies to let foo = bar. It's not an expression either, so you can't wrap it in parentheses. if let foo = bar is fine, but if (let foo = bar) isn't.
C++ supports a similar syntax in some cases:
if (auto foo = make_unique<int>(3)) { ... } else { ... }
This syntax declares foo and tests it (using its operator bool()), and then branches the program appropriately. Since the condition is a declaration statement, not an expression, it can't be wrapped in more parentheses either: if ((auto foo = make_unique<int>(3))) is a compile-time error, just like if (let foo = bar) in Swift.
Can anyone help explain the difference?
The difference is that Swift is not C++. Although they are similar in many ways, they have different grammars. The grammar defines (in part) the language's syntax.
In C++, an if statement is part of the selection-statement production in the grammar:
selection-statement:
if ( condition ) statement
if ( condition ) statement else statement
switch ( condition ) statement
So the parentheses around the condition of the if statement are part of the if statement, and not part of the condition.
In Swift, an if statement is the only production of the if-statement production in the grammar:
if-statement → if condition-list code-block else-clauseopt
Note that there are no parentheses directly in the if-statement's production. So if there are to be parentheses, they must be part of the condition-list production. Here's how condition-list is defined:
condition-list → condition | condition , condition-list
condition → expression | availability-condition | case-condition | optional-binding-condition
So a condition-list is one or more conditions, separated by commas. If you click through each of the four alternatives in condition, you'll find that availability-condition must start with the token #availability, case-condition must start with the token case, and optional-binding-condition must start with either the token let or the token var. None of those three productions can start with a parenthesis token.
The only production of condition that can start with the token ( is the expression production, and an expression production cannot have the token let after the token (.

how to make sense of pattern matching of optionals in for loop in swift

in a practice problem I was asked to print out all elements that are not nil in an array of string, and I realize
for case let name? in names{
print(name)
}
would do the job. But isn't it counter-intuitive?
In the snippet, I read it as "for every element (with actual value or nil)that is in names", but in fact it should be "for every element (actual value)that is in names".
Can anyone help me to make sense of the snippet?
You want to know why this code:
let names = ["b", nil, "x"]
for case let name? in names {
print(name)
}
Produces this output:
b
x
You are wondering what happens to the nil.
The answer is the "Optional Pattern" found in the Language Reference:
The optional pattern provides a convenient way to iterate over an
array of optional values in a for-in statement, executing the body of
the loop only for non-nil elements.
The case keyword is vital. It changes the nature of the for loop significantly. As you can see from this complier error, name? inside the loop is not an optional at all.
Think of the ? as an operator that removes the optionality of name. If the assignment would result in nil, that iteration of the loop does not happen, and the next iteration starts.
Notice that without the case you do not get the same behavior at all.
This:
for name in names {
print(name)
}
Will get this output:
Optional("b")
nil
Optional("x")
And that neither of these work at all.
You can use filter with conditional and then print the result like this:
let nameNotNil = names.filter{$0 != nil} //filter all values diferent nil
print(nameNotNil) // can be nil if any didnt has strings

Why can you assign non-optional values to optional types in Swift?

Why do assignments involving Swift optionals type check?
For example in,
var foo : Int? = 0
foo = foo!
foo and foo! do not have the same type. Shouldn't you need to wrap the unwrapped value to assign it to an optional type?
This is part of the syntactic sugar behind optionals. Assigning a non-optional value is how you wrap it in the optional type.
Since an optional indicates the presence or absence of a value, you shouldn't have to do anything special to indicate the presence of a value other than provide one. For example, in a function:
func gimmeSomethingMaybe() -> String? {
if arc4random_uniform(10) > 7 {
return "something"
} else {
return nil
}
}
Imagine if every time you wanted to return a real value from a function that's capable of returning nil, you had to write return Optional(value). That'd get old pretty fast, right? Optionals are an important feature of the language — even though they're actually implemented by the standard library, the syntactic sugar / automatic wrapping is there to keep it from being tedious to use them.
Edit: just to go a bit further into this... the sugar also helps to enforce the notion that a real value should not be optional. For example:
let one = 1
one? // error (in Swift 1.2, allowed but meaningless in Swift 1.1)
"two"? // error (ditto)
You can create an optional wrapping a real value with the Optional(one) initializer, but that has little semantic meaning on its own, so you almost never need to.
Optionals should come into play when there's "mystery" as to whether a value is present or absent — that is, when whether one part of a program receives a value (or no value) depends on state unknown to that part of the program. If you know you have a real value, there's no mystery... instead, you let the unknown come into play at the boundary between the code that knows the value and the code that doesn't know — that is, the function/method/property definition that hands that value off to somewhere.
After reading rickster's answer, I came up with a simple laymen terms answer. To me the whole whole gist of his answer is
Since an optional indicates the presence or absence of a value, you
shouldn't have to do anything special to indicate the presence of a
value other than provide one
An optional is an enum. Which has 2 cases a or b.
String?
|
An enum with 2 cases
|
a b
| |
Set notSet
| |
any value like "hi" nil
So you could do either of the things when you want to assign to an optional.
Say the value is either:
a: it's set to "hi"
b: it's not set, so it's nil
c: it just equals to another enum ie another optional
code:
var str : String?
var anotherOptional : String?
str = nil // nil <-- this is like case b
str = "hi" // "hi" <-- this is like case a
str = anotherOptional // nil <-- this is like case c
anotherOptional = "hi again"
str = anotherOptional // "hi again" <-- this is like case c

Assign conditional expression in Swift?

Is there a way in Swift to assign conditional expressions similar to this
let foo = if (bar == 2) {
100
} else {
120
}
(or with a switch case).
(Don't want to have to use ternary operator for this).
This kind of assignement is good for functional style / immutability. The expressions have a return value in this case.
Note: it's a general question, this is just simplified example, imagine e.g. a switch case with a lot of values, pattern matching, etc. You can't do that with ternary operator.
Btw also note that there are languages that don't support ternary operator because if else returns a value, so it's not necessary, see e.g. Scala.
You can use a closure to initialize an immutable:
let foo: Int = {
if bar == 2 {
return 100
} else {
return 120
}
}()
The advantage of using a closure is that it's a function, so you can use any complex logic inside, implemented in a clean way and not through nested ternary operators. It can be a switch statement, it can be obtained as the return value of a function followed by some calculations, it can be a pattern matching case, it can be a combination of them all, etc.
Said in other words, it's the same as initializing with the return value of a function, but the difference is that the function is inline and not somewhere else, with readability benefits.
Just for completeness, if the variable is mutable, you can use deferred initialization:
var foo: Int
// Any statement here
if bar == 2 {
foo = 100
} else {
foo = 120
}
// Other statements here
myFunc(foo)
so you can declare a mutable variable, and initialize it anywhere in the same scope, but before using it the variable must be initialized.
Update: Since Swift 2.0, deferred initialization also works with immutables.

It it okay to access an optional variable with question mark without exclamation mark?

I know that an optional constant or variable with a question mark needs an exclamation mark to access its value. then, I tried to exam it with the following code.
var aaa:String? = "3"
println("aaa = \(aaa!)")
Yes. It was okay. It printed "3" on Console Output. and next exam I tried like that
var aaa:String? = "3"
println("aaa = \(aaa)")
It also printed "3" without any error message. It worked well.
I learned about Forced Unwrapping that en exclamation mark is needed to access to a value of Optional. But, I could access it without the mark. Is it right? I wonder what is wrong. Am I misunderstanding Optional?
You are correctly understanding Optionals and Forced Unwrapping. The reason that you can print the optional variable is that the type Optional can also be printed. If you print an Optional instead of the real value, it will either print the value if it has one, or "nil" if it doesn't.
Also, just in case you don't realize it. Forced Unwrapping will cause the whole program to crash if the optional is nil at the time. To be safer, you should use Optional Binding:
var aaa: String? = "3"
if let actualString = aaa {
// actualString becomes a non-optional version of aaa
// if aaa were nil, this block would not be run at all
println(actualString)
}
Also, some extra information about the printing of instances. Printing uses the protocol Printable which defines a description property. Anything that implements this protocol can customize the way they print out. Optional has its own implementation of this protocol which is how it decides to either print "nil" or the description of the actual value.
Println() will print the value if it has any otherwise it will print nil. Just to understand things better just try to assign value of aaa to another string variable. It will throw error that value of optional type not unwrapped.
var aString:NSString? = "Hello"
var bString = aString // Compiler allows, as you are assigning to optional type again.
var cString:NSString = aString // Compiler throws error. You cannot assign optional type without unwrapping.
So to answer your question you need to use ! to get the value.
Edit:
var foo:Bool?
foo = false
if foo { // This always evaluates to `True`
...
}
if foo! { // This condition will now fail
...
}
The reason foo evaluated to True is because it was not unwrapped. Since its not unwrapped its just checking whether it has a value or not(true or false does not matter).
When foo was unwrapped it returned a value False hence the second if condition failed.
The println function is a special case. It automatically unwraps the variable for you. If the variable were nil, it would print nil. In other contexts, you do need to unwrap the variable yourself.