In some languages other than swift, a variable or a constant, can or cannot have a value. So a variable or a constant, can be null, if no value was assigned to them, or if set to null.
What the swift programming language did, is to turn the table. So instead of guessing, if a value, was, or was not, assigned to a variable, or to a constant, the swift programming language, made it as a requirement, that by default, all variables and constants, must have a value assigned to them, so in other words, they can never be nil .
var i :Int = -9223372036854775808; /* i must have a value between Int.min and Int.max inclusive .*/ var b :Bool = true /* b must either have, a true, or a false value .*/
This being said, under certain circumstances, a variable or a constant, might not have, a valid value, so what was still needed, is a way to represent this possibility , hence swift came out, with the optional type. In other words, an optional might have a value, or might have no value, and the absence of value, is indicated with a nil.
This being said, there are two ways to declare an optional, either you follow the type, with an interrogation mark, ?
, or you can use Optional<Type>
.
var i :Int? let b :Optional<Bool>
Concerning Optional<Type>
, an optional is actually an enum, which can have one of two values, nil, or the actual data.
Things being declarative, meaning i know beforehand, if a variable might be shady, and if so, i declare it as being optional, the question to ask is, how should i deal with these shady values, so in other words, how to get a value, out of these shady values.
One way of protecting ourselves, from these shady values, is why not provide a default value, if the optional is nil.
var b:Bool? if b ?? true { print ("b is nil , true is returned , if succeeds , this is printed " )} // b is nil , true is returned , if succeeds , this is printed b = false /* Set b to false .*/ if b ?? true { print ("b is false, false is returned, this is not printed" )} else{ print ("b is false, false is returned, this is printed" )} // b is false, false is returned, this is printed let value_1 :Int? = nil let value_2 :Int? = nil; let value_3 :Int? = nil; let seed = value_1 ?? value_2 ?? value_3 ?? 100 print ( "seed is \(seed)" ) // seed is 100
– bad names ?
– Sure, why not!
– The ??
is called the nil coalescing operator.
In all cases, let us not get stuck with bad names, what if we don’t want, to actually provide a default value. What if, based on if this shady value, containing or not, a legit value, we have two courses of actions, that we want to undertake.
– okay! okay! you might say.
– okay! okay! So what we mean by that, that if the value is actually valid, you might want to do something, and if the value is actually invalid, you might want to do something.
– okay! okay!
– okay, so what we have at this stage, is using an if
, or a guard
. if
, when you want to do something, if the value is valid, and guard
if you want to do something, when a value is invalid.
extension String :Error {} // Quick way to allow throwing string errors var s :String? if let str = s { print ("s is nil, so this code is not executed , and \(str) is never printed" )} print ("str is only defined within the if block" ) // str is only defined within the if block s = "hello world" guard let str = s else { throw "s is invalid" /* The guard block is executed, if and only if, the optional value is nil. If the optional value is not nil, then the code after the guard block, is executed, and the variable or constant, defined in the head of the guard block, and now having a value, will be accessible to the code after the guard block. This means that the guard block, must not allow a fall through, to the code after it, hence and for example, if inside a function, it can just return , or why not throw an error .*/ /* Since s is not nil, this guard block, is never executed .*/ } print ("s is not nil, hence: '\(str)'"); //s is not nil, hence: 'hello world' let x :Int? = 1; var y :Int? = nil if var tx = x , var ty = y{ print ("This will never be printed" ) /* You can specify more than one optional, in an if, or a guard. For an if, the body is executed, if and only if, the optionals contain valid values. This is done sequentially, and on first error, stops .*/ } let optString :String? = "a" guard let boolStr = optString , let b = Bool(boolStr ) else { throw "This error is thrown" /* In this guard statement, first we are trying to get a value, out of an optional string. If succesful, we are trying to get a boolean value, out of the gotten string. Bool(boolStr ) returns an optional, so this is why, it is being done in the guard statement. b will have a nil value, since boolStr does not actually contain a boolean description, hence the body of the guard is executed. */ /* This block is executed */ }
– okay, but i am sure!
– of what?
– of an optional having a value!
– we need the example, but yes do not worry, we have it covered. So let us say, you have a function, and this function can return bad values, depending on the input you provide. So for bad input, nil values, for good input good values.
– And let us say, that we are pretty sure of our input, and as such, we do not want to use any of the earlier options, as in providing a default value, or doing an if, or a guard check, so what is the way?
– yes?
let i :Int? = 1 print ("i is \(i!)") /* If you are sure that an optional has a value, then you can get its value, by simply using ! after the optional name, so at this stage, you are not doing any check .*/ //i is 1 func dummy (x :Int ) -> String?{ if x < 0 { return nil } return "Valid data" } /* The dummy function, returns an optional, since if the input is not valid, it might return an invalid output .*/ var trusty :String! = dummy (x: 0 ) var str :String = trusty; /*str is assigned the value of trusty, It was not necessary to use the !, or ??, or let , or guard . This is because trusty was declared with its type followed by ! */ print ("trusty handed me this : \(str)" ) // trusty handed me this : Valid data trusty = dummy (x: -1 ); /* trusty can still be nil, so you need to pay attention, that a variable or a constant, declared with its type followed by a !, might still hold nil values .*/ /* str_1 = str trusty is being assigned to str, trusty is nil, str can never be nil, this will cause an error . So you need to pay attention, for trusty, as such you can use ?? or if , or guard with trusty as usual .*/
– yeh, but you know what? i have something, which does not fall into any of the categories, you have described so far !
– okay as in ?
– i have this variable or constant, which i want to call its method, or access its property, and this variable or constant, is an optional.
– Yes , i see, correct, do you want maybe to nest this call ?
var dict = ["a": ["b": "hello world" ]] let word = dict ["a" ]?.first?.value /* ? can be used to access a method, or a property, of an optional, and this can be nested . If any is nil, then this will return a nil, hence the return type of ? is also an optional . word will be of type String? and it will contain the value hello world .*/ let letters_count = dict ["a" ]?.removeValue(forKey: "b")?.count /* letters_count will be of type Int?, and will contain the count of the string hello world */ print ("\(word!) has a length of \(letters_count!)") // hello world has a length of 11
– yeh, but you have talked about everything, and you forgot about one thing!
– which is ?
– how to assign a value to an optional.
– well, we have seen this, it is just like any other variable, or constant.
– comparing ?
– Ah, don’t fuss about it.
var x :Optional<Int> = nil var y :Int? = Optional<Int>(1 ) if x != y && x == nil { /* Optionals can be compared using == and != */ x = y y = nil print ("Hip hip hourray!") } // Hip hip hourray!
– naming?
– what is that?
– an inside one !
– share ?