Optionals in swift a tutorial

 

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 ?