1

Les variables et types conditionnels

Bonjour les codeurs du mercredi ! Vous est-il déjà arrivé de douter, comme quand on vous a parlé pour la première fois de physique quantique ? Eh bien en Swift aussi on peut être incertain, et je parle du point de vue du code. Peut-on vraiment connaître le contenu d’une variable avant de l’avoir lue ? Qu’arrive-t-il si une fonction ne parvient pas à calculer un résultat ? Si aucune donnée n’est lue ? Aujourd’hui on va s’amuser un peu à subodorer des valeurs de types ambigus, alors faites le plein de quantas d’énergie, on s’aventure dans le monde chaotique des variables conditionnelles !

Le chat de Schrödinger se nourrit de votre incompréhension ! Crédit : Leo Amaral

Attends, quoi ?

Comment ça “incertain” ? Alors pour bien comprendre on va devoir utiliser un tableau, par exemple un tableau d’entiers vide :

1
let tableau: [Int] = []

Si plus loin dans notre code nous demandons à lire le premier élément du tableau, Xcode va nous laisser faire tranquillement, en tout cas jusqu’a ce que l’on appuie sur play :

1
2
let tableau: [Int] = []
print(tableau[0])

Une fois le programme lancé (ou dans un playground), Xcode va nous afficher une erreur assez effrayante et difficilement lisible :
error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).. Pour comprendre ce qu’il s’est passé, il faut ouvrir la console de déboggage qui nous indique plus clairement :

1
Fatal error: Index out of range

Bon évidemment une erreur avec Fatal comme premier mot ça ne peut pas être quelque chose de bon, mais le plus important c’est que ce type d’erreur aboutie à un plantage immédiat de tout le programme. En l’occurence car nous avons voulu lire une valeur qui n’existait pas. En réalité ce qu’il se passe c’est que l’endroit de la RAM qui devait stocker la valeur ne correspond pas à une donnée cohérente (pas le bon type par exemple).

“Pourquoi est-ce si important ?”, vous entend-je déjà demander en buvant votre café . En effet, il suffit de faire attention à ce que ce genre de scénarios ne se produisent pas dans notre code, c’est pour ça que nous sommes des bon programmeurs. Mais ça ne suffit pas, trop souvent les tableaux vont avoir des longueurs variables (et c’est bien là leur utilité) et ce n’est pas le seul problème.

Assez tergiversé

Il existe un mot-clé pour définir ce qui n’a pas de valeur en swift : nil qui est l’abréviation de null souvent utilisé dans les autres langages. Littéralement : nul dans le sens qui n’existe pas, qui se réduit à rien. On va pouvoir attribuer ce mot-clé en valeur d’une variable pour indiquer que justement la variable n’a pas de valeur. Alors essayons un peu :

1
let variable:Int = nil

Nous allons fissa nous faire remballer par notre propre outil de développement (se rebelle-t-il ?) : ‘nil’ cannot initialize specified type ‘Int’, cela pour nous rappeler que “rien” n’est pas un nombre. Mais ce n’est pas tout, il nous propose de corriger lui-même le problème avec une solution curieuse, ajouter un point d’interrogation à la suite du type et ainsi le transformer en type optionnel.

1
let variable:Int? = nil

Alors que vient-il de se passer, nous venons en réalité de modifier le type de notre variable qui est simplement le type Int mais pouvant accepter de ne pas avoir de valeur (donc d’avoir nil pour valeur). En ce faisant, nous utilisons un type différent que Int, un entier optionnel.

Si on tente de s’en servir d’une manière “classique” on va se heurter à des problèmes :

1
2
3
4
let nombre: Int = 28
let variable:Int? = nil

print(nombre + variable)

Value of optional type ‘Int?’ must be unwrapped to a value of type ‘Int’

Comme le type Int est différent de Int?, ce dernier ne convient pas pour être utilisé par exemple pour une addition de deux entiers. Et il s’agit bien ici d’une erreur de compilation, ce n’est pas comme tout à l’heure lors de l’exécution qui nous induisait un crash complet du programme. Cela permet par conséquent d’interdire tout simplement de créer de potentielles erreurs dans le code lorsque des valeurs ne sont pas disponibles. C’est très utilisé dès lors qu’il y a une entrée utilisateur, des données à lire / écrire / échanger, de manière générale lorsque qu’une donnée est générée par le programme et pas écrite par le développeur (oui, vous !). Autant dire que c’est indispensable.

Un p’tit wrap !

Ce qui se cache derrière le terme “unwrapped” (dans l’erreur de compilation) c’est faire en sorte que le type de la variable redevienne non-nul. Il y a principalement deux moyens pour parvenir à cela, le plus simple mais aussi le plus dangereux est d’ajouter un point d’exclamation après le nom de la variable. De cette façon la variable sera considérée comme non-nulle lors de la compilation mais si une valeur nulle est trouvée lors de l’exécution alors nous retrouverons notre erreur fatale du début.

1
2
3
4
let nombre: Int = 28
let variable:Int? = 5

print(nombre + variable!)

C’est comme dire à Xcode que l’on sait ce que l’on fait et que la variable aura toujours une valeur lors de sa lecture, cela arrive notamment lorsque une variable n’est lue qu’après l’exécution de la fonction qui la détermine (qui lui donne sa valeur). Néanmoins il vaut mieux éviter d’en mettre trop souvent, même si cela devient vite tentant.

La deuxième option est d’effectuer un simple test conditionnel simple de création d’une variable de type non-nul. Ce que ça veut dire c’est que l’on va essayer de créer une variable non nulle à partir de la valeur dans une condition if :

1
2
3
4
5
6
7
8
9
10
11
let nombre: Int = 28
let variable:Int? = nil

if let variableNonNulle = variable {
    print(nombre + variableNonNulle)
}

// --------- OU ----------
if variable != nil {
    print(nombre + variable!)
}

Dans le deuxième exemple on peut facilement forcer la désoptionnalisation (est-ce un vrai mot ?) de la variable étant donné que l’on teste qu’elle ne soit pas nulle

Avoir la classe

Dans une classe, on peut définir le type d’une variable sur son type optionnel dès sa déclaration ce qui nous évitera d’avoir à lui attribuer une valeur dans le init(). Ensuite on peut s’en servir comme de n’importe quelle autre variable dans la classe, tant qu’on n’oublie pas d’y juxtaposer un point d’exclamation lorsque le type se doit d’être non-nul :

1
2
3
4
5
6
7
8
9
10
11
12
13
class Classe {
   
    var nombre: Int?
   
    init() {
       
    }
   
    func ajouter(_ ajout: Int) {
        print(nombre! + ajout)
    }
   
}

C’est bien juste après le nom de la variable que l’on doit positionner le point d’exclamation

Je vois qu’il vous reste encore un petit peu de café, courage on a encore deux choses à voir ! Si on est certain qu’une variable aura toujours une valeur mais qu’en même temps elle puisse être nulle (ne me regardez pas comme ça, ca arrive vraiment) on peut alors directement la déclarer avec le point d’exclamation dans la classe, ce qui indiquera au compilateur d’Xcode de la traiter comme une variable non-nulle :

1
2
3
4
5
6
7
8
9
10
11
12
13
class Classe {
   
    var nombre: Int!
   
    init() {
       
    }
   
    func ajouter(_ ajout: Int) {
        print(nombre + ajout)
    }
   
}

Dernière chose, il y a un raccourci pour accéder aux méthodes d’un type optionnel, n’oublions pas qu’il s’agit d’une classe avant tout. Si par exemple on stocke notre classe dans une variable optionnelle :

1
var variable: Classe? = Classe()

Eh bien si on tente d’exécuter la fonction de la classe depuis la variable optionnelle, il nous suffit d’ajouter notre point d’interrogation pour que le compilateur ne demande pas l’exécution de la fonction si la valeur est nulle (ouch). Bon bon bon, si jamais on fait ça :

1
2
var variable: Classe? = Classe()
variable?.ajout(3)

Alors si la valeur est non-nulle lors de l’exécution la fonction s’exécutera normalement, si la valeur est nulle alors la fonction ne sera pas exécutée et aucun crash n’aura lieu. C’est comme si la ligne de code elle-même était optionnelle…

 

STOP ! Ca suffit pour aujourd’hui je croit, il est grand temps de faire une pause. Bravo à tous ceux qui ont lu en entier, félicitations à ceux qui ont compris et merci à ceux qui n’ont pas compris et me le diront 😉

Suite du tutoriel Apprendre le swift

En cours de rédaction...

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *