\part{Programmation orientée objet}
\chapter{Concept de classe}
L'idée de base de la programmation orientée objet est de rassembler dans une même entité les données et les traitements qui s'y appliquent. Dans cette partie, nous allons voir comment Nit permet de développer en objet.

Une classe est le support de l'encapsulation : c'est un ensemble de données et de fonction regroupées dans une même entité. Une classe est une description abstraite d'un objet. Les fonctions qui opèrent sur les données sont appelées des méthodes. Les données en elles-mêmes sont appelées des attributs. Les attributs et les méthodes représentent les propriétés de la classe. Instancier une classe consiste à créer un objet sur son modèle.

Rappelons qu'en Nit absolument TOUT est objet.

Pour accéder à une classe il faut en déclarer une instance ou objet.

Une classe se compose en deux parties : un en-tête et un corps. Le corps peut être divisé en deux sections : la déclaration de ses propriétés (attributs et la définition des méthodes. Les méthodes et les données sont pourvues d'attributs de visibilité qui gère leur accessibilité par les composants hors de la classe.

Une classe comporte donc sa déclaration, des attributs et la définition de ses méthodes.

En Nit, toutes les classes héritent forcément de la classe |Object|. Cette relation d'héritage est implicite, c'est à dire qu'il n'y a pas besoin de la déclarer.

\section{Syntaxe et déclaration d'une classe}
La syntaxe de déclaration d'un classe est la suivante :
\begin{lstlisting}[language=Nit]
    [redef][abstract] class nomDeClasse [super classeMere...]
        ...
    end
\end{lstlisting}

Les modificateurs de classe sont :
\begin{description}
    \item[abstract] Une classe abstraite est une classe contenant une ou plusieurs méthodes abstraites, qui n'ont pas de déclaration explicite. Une classe déclarée |abstract| ne peut pas être instanciée : il faut définir une classe qui hérite de cette classe et qui implémente les méthodes nécessaires pour ne plus être abstraite (voir section~\ref{classes-abstraites} \nameref{classes-abstraites}).
    \item[redef] Ce modificateur permet de raffiner une classe pour y ajouter ou modifier des propriétés (voir section~\ref{redef} \nameref{redef}).
\end{description}

Le mot clé |super| permet de spécifier une ou des superclasses éventuelles : ce mot clé permet de préciser une classe mère dans une relation d'héritage. Nit supporte l'héritage multiple, il est donc possible d'utiliser plusieurs fois |super| sur la même classe (voir chapitre~\ref{heritage} \nameref{heritage}).

L'ordre des méthodes dans une classe n'a pas d'importance. Si dans une classe, on rencontre d'abord la méthode A puis la méthode B, B peut être appelée sans problème dans A.

\chapter{Objets}
La classe est la description d'un objet. Un objet est une instance d'une classe. Pour chaque instance d'une classe, le code est le même, seules les données (valeurs des attributs) sont différentes à chaque objet.

\section{Instancier une classe : créer un objet}
L'opérateur |new| se charge de créer une nouvelle instance d'une classe et de l'associer à une variable.

Exemple :
\lstinputlisting[language=Nit]{./poo/listings/new1_s.nit}

Cela n'est pas obligatoire grâce au typage adaptatif (voir chapitre~\ref{typage-adaptatif} \nameref{typage-adaptatif}) mais on peut aussi préciser le type sur la variable qui va recevoir l'instance :
\lstinputlisting[language=Nit]{./poo/listings/new2_s.nit}

En Nit, toutes les classes sont instanciées par allocation dynamique à part les types universels (voir chapitre~\ref{universal} \nameref{universal}). Dans l'exemple précédent, la variable |instance| contient une référence sur la classe instanciée (contient l'adresse de l'objet qu'elle désigne : attention toutefois, il n'est pas possible de manipuler ou d'effectuer des opérations directement sur cette adresse comme en C).

\lstinputlisting[language=Nit]{./poo/listings/new3_s.nit}

L'opérateur |new|, lorsqu'il instancie la classe, appelle une méthode particulière de cet objet : le constructeur (voir chapitre~\ref{constructeurs} \nameref{constructeurs}).

\section{Durée de vie d'un objet}
La durée de vie d'un objet ne correspond pas forcément à la durée de vie du programme.

La durée de vie d'un objet passe par trois étapes :
\begin{description}
    \item[La création] de l'objet grâce à l'opérateur d'instanciation |new|.
    \item[L'utilisation] de l'objet en appelant ses méthodes.
    \item[La destruction] de l'objet, c'est à dire la libération de la mémoire qu'occupe l'objet. En Nit, la libération de la mémoire est automatiquement effectuée par le ramasse miette (garbage collector). Quand le ramasse miette découvre un objet qui ne sera plus utilisé dans le programme alors il va automatiquement le supprimer. Il n'existe pas d'instruction \lstinline[language=C++]{delete} comme en C++.
\end{description}

\section{Références et comparaison d'objets}
Les variables de  type objet que l'on déclare ne contiennent pas un objet mais une référence vers cet objet. Lorsque l'on écrit |instance1 = instance2|, on copie la référence |instance1| dans |instance2| : |instance1| et |instance2| pointent sur le même objet. Par défaut, l'opérateur |==| permet de comparer ces références. Deux objets avec des propriétés identiques sont deux objets distincts.

\lstinputlisting[language=Nit]{./poo/listings/comparaison1_s.nit}
Si on souhaite comparer deux objets en se basant sur la valeur de leurs attributs, il est possible de redéfinir l'opérateur |==| dans leur classe (voir section~\ref{redef-operateur} \nameref{redef-operateur}).

Par exemple, l'opérateur |==| a été redéfinit pour la classe String il est donc possible de comparer deux String en se basant sur leurs valeurs :
\lstinputlisting[language=Nit, linerange=1-5]{./poo/listings/comparaison2_c.nit}

Il est possible de comparer le type de deux objets, c'est à dire de vérifier si deux objets sont de la même classe ou non. Pour cela nous allons utiliser la méthode |is_same_type(o:Object)|. Cette méthode est introduite dans la classe |Object|, comme toutes les classes en héritent implicitement, elle est disponible dans toutes les classes.

\lstinputlisting[language=Nit, linerange=8-9, firstnumber=last]{./poo/listings/comparaison2_c.nit}

Pour vérifier que deux variables sont en fait des références vers le même objet, il est possible d'utiliser le mot-clé |is| :
\lstinputlisting[language=Nit, linerange=6, firstnumber=last]{./poo/listings/comparaison2_c.nit}

\section{Objet null}
En Nit, il existe une particularité pour l'objet |null|. Contrairement à Java il ne peut pas être utilisé à la place de n'importe où. En effet, Nit propose un mécanisme permettant de limiter statiquement les erreurs fréquentes de type |nullPointerException|.

Pour qu'une variable puisse prendre la valeur |null|, elle doit avoir été déclarée explicitement avec le type |nullable| :
\lstinputlisting[language=Nit]{./poo/listings/nullable1_c.nit}
Dans l'exemple précédent, si on omet de préciser le type comme |nullable|, le compilateur Nit lèvera une erreur au moment de la compilation.

\chapter{Modificateurs d'accès}
Les modificateurs d'accès assurent le contrôle des conditions d'héritage, d'accès aux éléments et de modification de données par les autres classes. Ils s'appliquent aussi bien aux classes, qu'aux méthodes et attributs.

\section{Visibilité des entités}
De nombreux langages orientés objet introduisent des attributs de visibilité pour réglementer l'accès aux classes et aux objets, aux méthodes et aux données.

Il existe 2 modificateurs qui peuvent être utilisés pour définir les attributs de visibilité des entités (classes, méthodes ou attributs) : |private| et |protected|. Leur utilisation permet de définir des niveaux de protection différents (présentés dans un ordre croissant de niveau de protection offert) :

%TODO reformuler
\begin{description}
    \item[Par défaut : public] Il n'existe pas de mot clé pour définir ce niveau, qui est le niveau par défaut lorsqu'aucun modificateur n'est précisé. Un attribut ou une méthode déclaré public est visible par tous les autres objets. Dans la philosophie orientée objet aucun attribut ne devrait être déclaré public : il est préférable d'écrire des méthodes pour le consulter et le modifier.
    \item[protected] Si un attribut ou une méthode est déclarée |protected|, seules les méthodes de ses sous classes pourront y accéder.
    \item[private] C'est le niveau de protection le plus fort. Les composants ne sont visibles qu'à l'intérieur du fichier où est définie la classe.
\end{description}

Ces modificateurs d'accès sont mutuellement exclusifs.

\section{Classes abstraites}
\label{classes-abstraites}

Le mot clé |abstract| peut être appliqué à une classe qui ne doit pas être instanciée. Cela permet de créer une classe qui sera une sorte de moule : toutes les classes dérivées pourront profiter des méthodes héritées.

\lstinputlisting[language=Nit]{./poo/listings/abstract1_c.nit}

Essayer d'instancier une classe abstraite générera une erreur de compilation.

\chapter{Méthodes}
Les méthodes sont des fonctions qui implémentent les traitements de la classe.

\section{Syntaxe et déclaration}
La syntaxe de la déclaration d'une méthode est :
\begin{lstlisting}[language=Nit]
    [redef] [protected|private] fun nom_de_méthode[( arg1:Type, ... )][:Type_retourné] do
        ...
    end
\end{lstlisting}

\section{Types retournés}
Le type retourné correspond au type de l'objet qui est renvoyé par la méthode. Si la méthode ne retourne rien, alors on ne précise pas le type retourné.

La valeur de retour de la méthode doit être transmise par l'instruction |return|. Elle indique la valeur que prend la méthode et termine celle ci : toutes les instructions qui suivent |return| ne seront pas exécutées. Si des instructions sont placées après le mot clé |return|, une erreur |unreachable statement| sera levée lors de la compilation.

\lstinputlisting[language=Nit]{./poo/listings/methode1_c.nit}

Il est possible d'inclure une instruction |return| dans une méthode sensée ne rien retourner : cela permet de quitter la méthode.

\section{Passage de paramètres}
Les paramètres des méthodes sont déclarés entre parenthèses et séparés par des virgules. Le type et le nombre de paramètres déclarés doivent correspondre au type et au nombre de paramètres transmis. Si un méthode n'accepte pas de paramètres, il suffit de ne pas indiquer de parenthèses :
\lstinputlisting[language=Nit]{./poo/listings/methode2_c.nit}

Si plusieurs paramètres ont le même type, il est possible de le factoriser :
\lstinputlisting[language=Nit]{./poo/listings/methode7_c.nit}

Il n'est pas possible d'indiquer des valeurs par défaut dans les paramètres. 

Lorsqu'un objet est passé comme paramètre à une méthode, cette dernière reçoit une référence qui désigne son emplacement mémoire d'origine et qui est une copie de la variable. Il est possible de modifier l'objet grâce à ces méthodes mais il n'est pas possible de remplacer la référence contenue dans la variable passée en paramètre : ce changement n'aura lieu que localement à la méthode.

\section{Envoi de message}
Un message est émis lorsqu'on demande à un objet d'exécuter l'une de ses méthodes.
La syntaxe d'appel d'une méthode est : |objet.methode(paramètre, ...)|

Si la méthode appelée ne contient aucun paramètre, il n'est pas nécessaire de mettre les parenthèses.

\lstinputlisting[language=Nit]{./poo/listings/methode4_s.nit}

Quand l'appel de méthode se fait en dehors d'une expression et qu'elle n'accepte qu'un seul paramètre, il est possible de ne pas utiliser les parenthèses :
\lstinputlisting[language=Nit]{./poo/listings/methode8_c.nit}

\section{Nombre variable de paramètres}
Il est possible d'indiquer qu'une méthode peut recevoir un nombre variable de paramètre grâce à l'opérateur |...|. Le paramètre sera alors considéré comme un tableau du type spécifié. L'envoi de message pourra alors contenir aucun, un ou plusieurs arguments pour le paramètre ainsi déclaré.

\lstinputlisting[language=Nit]{./poo/listings/methode9_c.nit}

Seulement un seul paramètre variable est autorisé dans une signature.

\section{Enchaînement de références}
Il est possible d'enchaîner les envois de messages aux retours des méthodes :
\lstinputlisting[language=Nit]{./poo/listings/methode5_c.nit}

Ici on appelle la méthode to\_upper de l'objet retourné par la méthode substring de l'objet "abcd".

\section{Mot-clé self}

Le mot-clé |self| est l'équivalent du |this| en Java. Il permet de pointer sur le receveur courant :
\lstinputlisting[language=Nit]{./poo/listings/self_c.nit}

\section{Redéfinition d'opérateurs}
\label{redef-operateur}

Avec Nit il est possible de définir ou redéfinir des opérateurs arithmétiques (|+|, |-|, |*|...) pour chacune de nos classes en suivant la même déclaration que pour une méthode normale :
\lstinputlisting[language=Nit]{./poo/listings/methode6_c.nit}

La seule restriction est que la méthode doit forcément prendre un et un seul paramètre et retourner quelque chose.

\section{Surcharge statique de méthode}
Pour des raisons liées à l'héritage, Nit ne permet pas la surcharge statique des méthodes. Il n'est donc pas possible de définir plusieurs fois une même méthode avec des types de paramètres différents.

\section{Méthodes abstraites}
Une méthode abstraite est une méthode déclarée avec le modificateur |is abstract| et sans corps. Elle correspond à une méthode dont on veut forcer l'implémentation dans une sous classe. 

La syntaxe de la déclaration d'une méthode abstraite est :
\begin{lstlisting}[language=Nit]
    [redef] [protected|private] fun nom_de_méthode[( arg1:Type, ... )][:Type_retourné] is abstract
\end{lstlisting}

\lstinputlisting[language=Nit, linerange=1-3]{./poo/listings/abstract2_c.nit}

Pour pouvoir utiliser la méthode, il faut la redéfinir dans une sous classe grâce au mot clé |redef| (voir section~\ref{redef} \nameref{redef}) :
\lstinputlisting[language=Nit, linerange=5-11, firstnumber=last]{./poo/listings/abstract2_c.nit}

Contrairement à d'autres langages, une classe n'est pas automatiquement abstraite dès lors qu'une de ses méthodes est déclarée abstraite. Cela est lié au concept de raffinement de classe que nous aborderons un peu plus tard (voir section~\ref{raffinement-classe} \nameref{raffinement-classe}).

Un appel à une méthode abstraite n'est pas décelé au moment de la compilation (toujours à cause du raffinement de classe) mais au moment de l'exécution.

\chapter{Attributs}
Les données d'une classe sont contenues dans des variables nommées attributs. 

\section{Déclaration des attributs}
Le mot-clé |var| permet aussi de déclarer un attribut dans le corps de la classe. En Nit, tous les attributs doivent avoir un type explicite.

\lstinputlisting[language=Nit]{./poo/listings/attribut1_c.nit}

Chaque instance de la classe a accès à sa propre occurrence de l'attribut.

Il est possible de définir des valeurs par défaut pour chaque attribut :
\lstinputlisting[language=Nit]{./poo/listings/attribut2_c.nit}

\section{Accesseurs}
L'encapsulation permet de sécuriser l'accès aux données d'une classe, la bonne pratique consiste donc à créer des méthodes permettant d'accéder indirectement à ces données : les accesseurs. Nit applique à la lettre cette bonne pratique en empêchant systématiquement tout accès direct à l'attribut. En effet, pour chaque attribut déclaré dans une classe, Nit va généré un accesseur automatiquement pour en permettre l'accès.

Un accesseur est une méthode qui donne l'accès à une variable d'instance. Pour une variable d'instance, il peut ne pas y avoir d'accesseur, un accesseur en lecture (getter) et/ou un accesseur en écriture (setter). 

Il reste tout de même possible de définir ses propres accesseurs :
\lstinputlisting[language=Nit]{./poo/listings/accesseurs1_c.nit}

Les accesseurs manuels sont tout a fait comme des méthodes et acceptent de ce fait les modificateurs d'accès de visibilité. Pour les accesseurs automatiques, le principe est différent.

Pour les getters, c'est la visibilité de l'attribut qui va déterminer la visibilité de la méthode :
\begin{description}
    \item[par défaut (public)] Le getter automatique sera généré avec la visibilité public.
    \item[protected] Le getter automatique sera généré avec la visibilité |protected|.
    \item[private] Le getter automatique sera généré avec la visibilité |private|.
\end{description}

Voici un exemple d'utilisation des getters automatiques :
\lstinputlisting[language=Nit]{./poo/listings/accesseurs2_c.nit}

Pour les setters, ils sont toujours générés comme étant |private|. Pour changer cette visibilité, il est nécessaire de préciser l'attribut comme |writable| en lui rajoutant la visibilité souhaitée :
\begin{description}
    \item[writable] Le setter automatique sera généré avec la visibilité public.
    \item[protected writable] Le setter automatique sera généré avec la visibilité |protected|.
    \item[private writable] Le setter automatique sera généré avec la visibilité |private| (c'est le comportement par défaut).
\end{description}

Voici un exemple d'utilisation des setters automatiques :
\lstinputlisting[language=Nit]{./poo/listings/accesseurs3_c.nit}

\section{Redéfinition d'attributs}
Les accesseurs automatiques sont des considérés comme des méthodes normales, ils peuvent donc être hérités et redéfinis. De plus les accesseurs automatiques peuvent être utilisés pour redéfinir des accesseurs manuels. |redef var| permet de préciser une redéfinition du getter alors que |redef writable| permet de redéfinir le setter :
\lstinputlisting[language=Nit]{./poo/listings/accesseurs4_c.nit}

\section{Opérateur isset}

Pour vérifier si un opérateur a été initialisée, on peut utiliser l'opérateur |isset| :
\lstinputlisting[language=Nit,]{./poo/listings/isset_c.nit}

\chapter{Constructeurs}
\label{constructeurs}

\section{Constructeurs standards}
L'instanciation d'un objet est suivie d'une sorte d'initialisation par le moyen d'une méthode particulière appelée constructeur pour que les variables aient une valeur de départ. Elle n'est systématiquement invoquée que lors de la création d'un objet.

La syntaxe de la déclaration d'une constructeur est :
\begin{lstlisting}[language=Nit]
    [redef] [protected|private] init [nom][( arg1:Type, ... )] do
        ...
    end
\end{lstlisting}

Un constructeur ne possède pas de type de retour. 

\lstinputlisting[language=Nit]{./poo/listings/constructeur1_c.nit}

La définition d'un constructeur est facultative. Si aucun constructeur n'est explicitement défini dans la classe, le compilateur va créer un constructeur par défaut en fonction des attributs définis dans la classe :
\lstinputlisting[language=Nit]{./poo/listings/constructeur2_c.nit}

Bien sûr, il est possible de forcer un constructeur en le déclarant explicitement afin de créer un constructeur différent que celui qui serait généré par défaut:
\lstinputlisting[language=Nit]{./poo/listings/constructeur3_c.nit}

\section{Constructeurs nommés}
En Nit, il n'est pas possible de surcharger un constructeur. En revanche, il est possible de nommer les constructeurs :
\lstinputlisting[language=Nit]{./poo/listings/constructeur4_c.nit}

\section{Constructeurs abstraits}
Les constructeurs peuvent être déclarés comme abstrait avec la syntaxe suivante :
\begin{lstlisting}[language=Nit]
    [redef] [protected|private] init [nom][( arg1:Type, ... )] is abstract
\end{lstlisting}

\chapter{Héritage}
\label{heritage}
L'héritage est un mécanisme qui facilite la réutilisation du code et la gestion de son évolution. Elle définit une relation entre deux classes :
\begin{itemize}
  \item une classe mère ou super classe
  \item une classe fille ou sous classe qui hérite de sa classe mère
\end{itemize}

\section{Principes de l'héritage}
Grâce à l'héritage, les objets d'une classe fille ont accès aux données et aux méthodes des classes parentes et peuvent les étendre. Les sous classes peuvent redéfinir les attributs et les méthodes héritées. 

L'héritage successif de classes permet de définir une hiérarchie de classe qui se compose de super classes et de sous classes. Une classe qui hérite d'une autre est une sous classe et celle dont elle hérite est une super classe. Une classe peut avoir plusieurs sous classes et plusieurs classes mères. |Object| est la classe parente de toutes les classes en Nit. Tous les attributs et méthodes contenues dans |Object| sont accessibles à partir de n'importe quelle classe car par héritages successifs toutes les classes héritent d'|Object|.

\section{Mise en \oe{}uvre}
On utilise le mot clé |super| pour indiquer qu'une classe hérite d'une autre. En l'absence de ce mot réservé associé à une classe, le compilateur considère la classe |Object| comme classe mère.
\lstinputlisting[language=Nit]{./poo/listings/heritage1_s.nit}

Pour invoquer une méthode d'une classe parent, il suffit d'utiliser le mot-clé |super|. Les paramètres seront transmis automatiquement :
\lstinputlisting[language=Nit]{./poo/listings/super1_c.nit}

En Nit, il est obligatoire dans un constructeur d'une classe fille de faire appel explicitement ou implicitement au constructeur de la classe mère. 

Si rien n'est précisé alors l'appel sera fait implicitement, le constructeur de la classe mère sera appelé avant le constructeur de la classe fille :
\lstinputlisting[language=Nit]{./poo/listings/super2_c.nit}

Si |super| est utilisé, alors l'appel sera fait à l'endroit précisé :
\lstinputlisting[language=Nit, linerange=8-19]{./poo/listings/super3_c.nit}

\section{Accès aux propriétés héritées}
Les variables et méthodes définies avec le modificateur d'accès par défaut (public) restent publiques à travers l'héritage et toutes les autres classes.
Une variable d'instance définie avec le modificateur |private| est bien héritée mais elle n'est pas accessible directement mais via les méthodes héritées (mise à part dans le fichier où est définie la classe).

Si l'on veut conserver pour une propriété une protection semblable à celle assurée par le modificateur |private|, il faut utiliser le modificateur |protected|. La propriété ainsi définie sera héritée dans toutes les classes descendantes qui pourront y accéder en utilisant le mot-clé |self| mais ne sera pas accessible sur tout autre receveur.

\section{Redéfinition de méthodes}
\label{redef}
La redéfinition d'une méthode héritée doit impérativement conserver la déclaration de la méthode parent (type et nombre de paramètres et la valeur de retour doivent être identiques). Si la signature de la méthode change, ce n'est plus une redéfinition mais une surcharge (et rappelez-vous : ce n'est pas autorisé en Nit !).

Pour redéfinir une méthode, il suffit d'utiliser le mot-clé |redef| :
\lstinputlisting[language=Nit]{./poo/listings/redef1_c.nit}

Lors de la redéfinition d'une méthode avec le mot-clé |redef|, il n'est pas nécessaire de préciser à nouveau le prototype de la méthode :
\lstinputlisting[language=Nit]{./poo/listings/redef4_c.nit}

%\section{Redéfinition de constructeurs}

%\subsubsection{Redéfinition de constructeurs automatiques}

%Les constructeurs automatiques ou manuel sont transmis de la classe mère à la classe fille par héritage. Il est possible de redéfinir un constructeur automatique sans utiliser le mot-clé |redef| comme ceci :
%\lstinputlisting[language=Nit]{./poo/listings/redef5_c.nit}

\section{Polymorphisme}
Le polymorphisme est la capacité, pour un même message de correspondre à plusieurs formes de traitements selon l'objet auquel ce message est adressé. La gestion du polymorphisme est assurée dynamiquement à l'exécution.

L'idée est de partir d'un type et de le modifier. Par exemple, on peut créer une classe de base, puis faire des classes dérivées :
\lstinputlisting[language=Nit]{./poo/listings/polymorphisme_c.nit}

On peut ensuite traiter les objets de la même manière quelques soit leur type dynamique :
\lstinputlisting[language=Nit, linerange=39-43, firstnumber=last]{./poo/listings/polymorphisme_c.nit}

L'héritage définit un sous-typage implicite de la classe fille vers la classe mère : on peut affecter à une référence d'une classe n'importe quel objet d'une de ses sous classes.

\section{Coercition}
La coercition (conversion de type) peut être utilisé dans le cadre d'un cast standard grâce au mot-clé |as| :
\lstinputlisting[language=Nit]{./poo/listings/coercition1_c.nit}

L'inconvénient de cette méthode est que si l'objet n'avait pas été dynamiquement typé en tant que Vache, une erreur d'exécution serait survenue lors du cast puisque celui-ci aurait échoué.

Nit propose une méthode plus sûre permettant de changer temporairement le type statique d'une variable au mot-clé |isa| :
\lstinputlisting[language=Nit,firstnumber=last]{./poo/listings/coercition2_s.nit}

\section{Interfaces}
Une interface est un ensemble de déclarations de méthodes correspondant un peu à une classe abstraite. C'est une sorte de standard auquel une classe peut répondre. Tous les objets qui se conforment à cette interface (qui implémentent cette interface) possèdent donc les méthodes déclarées dans celle-ci. Plusieurs interfaces peuvent être implémentées par une même classe.

Les interfaces se comportent donc comme des classes un peu spéciales :
\begin{itemize}
    \item Une interface ne peut étendre qu'une interface ;
    \item Une interface ne peut pas avoir de constructeur (méthode init) ;
    \item Une interface ne peut donc pas être instanciée ;
    \item Une interface ne peut pas avoir d'attributs ;
\end{itemize}

En Nit, il est possible d'implémenter le corps des méthodes directement dans l'interface, celui-ci sera alors transmis par héritage.

Voici la syntaxe d'une interface :
\begin{lstlisting}[language=Nit]
    interface nom_interface [special interface_mere...]
        ...
    end
\end{lstlisting}

Un exemple de déclaration d'une interface :
\lstinputlisting[language=Nit]{./poo/listings/interface_c.nit}

Les interfaces sont ensuite intégrées aux autres classes avec le mot-clé |super| :
\lstinputlisting[language=Nit, linerange=5-22, firstnumber=last]{./poo/listings/interface_c.nit}

\chapter{Types universels}
\label{universal}

Les types universels sont déclarés à l'aide du mot-clé |universal|. Il s'agit d'éléments qui ne peuvent pas être spécialisés, qui ne peuvent spécialiser que des interfaces, n'ont pas d'attributs et pas de constructeurs.

Les types universels peuvent avoir des instances mais elles ne sont pas initialisées par le développeur, c'est à dire qu'il est impossible d'utiliser le mot-clé |new| avec un type universel.

Int et Bool sont deux exemples de types universels.

\chapter{Généricité et types virtuels}

\section{Généricité}
Le principe de la généricité est de factoriser les méthodes pouvant s'appliquer à n'importe quelle variable quelque soit sont type en évitant les problèmes de coercition.

\subsection{Généricité simple}
Prenons un exemple de classe non générique :
\lstinputlisting[language=Nit]{./poo/listings/gen1_c.nit}

Si nous souhaitons pouvoir utiliser cette classe avec d'autres objets que des |String|, il serait possible de se baser sur le type le plus haut dans la hiérarchie Nit, c'est à dire |Object| :
\lstinputlisting[language=Nit, linerange=1-3]{./poo/listings/gen2_c.nit}

Voyons maintenant ce qu'il se passe quand nous utilisons cette classe avec des |Int| :
\lstinputlisting[language=Nit, linerange=5-7, firstnumber=last]{./poo/listings/gen2_c.nit}

Vous remarquerez qu'il est nécessaire d'utiliser un cast pour utiliser le retour du |getter| de l'attribut |valeur| puisque celui-ci est de type |Object|. Ce n'est pas pratique et potentiellement dangereux pour la stabilité du programme puisque le risque d'erreur d'exécution sur un cast qui a échoué augmente.

Dans ce cas, la généricité apporte une solution fiable et robuste. Elle permet de paramétrer des méthodes avec un type de données joker qui sera résolu dynamiquement au moment de l'instanciation de l'objet.

Voici le code de la classe déclarée comme générique :
\lstinputlisting[language=Nit, linerange=1-3]{./poo/listings/gen3_c.nit}

Dans cette classe, le T n'est pas encore défini, cela se fera à l'instanciation. Par contre, une fois instancié avec un type, l'objet ne pourra travailler qu'avec le type de données spécifié à l'instanciation.

La déclaration d'une classe générique se fait en utilisant précisant le type joker (représenté par n'importe quel mot) entre crochet |[T]|. Il suffit ensuite d'implémenter les méthodes comme nous le ferions habituellement mais en remplaçant les types par le joker que nous avons défini dans la déclaration de la classe.

Voyons comment utiliser notre classe générique avec des entiers :
\lstinputlisting[language=Nit, linerange=5-6, firstnumber=last]{./poo/listings/gen3_c.nit}

Ou encore avec des chaînes de caractères :
\lstinputlisting[language=Nit, linerange=8-9, firstnumber=last]{./poo/listings/gen3_c.nit}

\subsection{Généricité bornée}
Dans certains cas, il peut être utile de limiter la portée de la généricité à un certain nombre de types ayant la même intention. Pour cela nous pouvons utiliser l'héritage afin de n'autoriser que les sous-types d'une certaine classe. C'est le principe de la généricité bornée.

Imaginons cette fois que la classe Solo n'a de sens que si elle est utilisée avec un objet de type Animal ou l'un de ses sous-type. Nous allons pouvoir préciser la borne sur notre joker dans la définition de la classe générique :
\lstinputlisting[language=Nit, linerange=1-3]{./poo/listings/gen4_s.nit}

Il n'est maintenant plus possible d'utiliser cette classe avec autre chose que le type Animal ou l'un de ses sous-type.

En réalité, toute classe utilisant la généricité sans borne apparente est bornée implicitement sur |[T: nullable Object]|.

\subsection{Généricité et héritage}
Nit, contrairement à d'autres langages, supporte la covariance des variables dans le cas des classes génériques.

L'exemple suivant est donc tout à fait valable en Nit :
\lstinputlisting[language=Nit, linerange=5-8, firstnumber=last]{./poo/listings/gen4_s.nit}

\subsection{Généricité multiple}
Nit supporte aussi la généricité multiple comme le montre l'exemple suivant :
\lstinputlisting[language=Nit]{./poo/listings/gen5_c.nit}

\section{Types virtuels}
Les types virtuels permettent définir au sein d'une classe un champ qui va contenir un type plutôt d'un objet. Ce champ peut ensuite être utilisé pour typer les paramètres et les types de retour des méthodes. Sa valeur sera exploitée à la compilation pour définir quel est le type à utiliser.

Exemple d'utilisation d'un type virtuel :
\lstinputlisting[language=Nit]{./poo/listings/type1_c.nit}

A quoi peuvent servir les types virtuels ?

Prenons un exemple très simplifié qui n'utilise pas les types virtuels :
\lstinputlisting[language=Nit]{./poo/listings/type2_c.nit}

Nous souhaitons maintenant étendre cette classe pour représenter un XMLDocument comprenant des XMLNode :
\lstinputlisting[language=Nit,firstnumber=last]{./poo/listings/type3_s.nit}

Jusque là tout va bien. Essayons maintenant de manipuler cette classe :
\lstinputlisting[language=Nit,firstnumber=last]{./poo/listings/type4_s.nit}

Pour forcer l'utilisation de la méthode add\_node de XMLDocument avec un paramètre de type XMLNode, nous voilà obligé de redéfinir entièrement la classe Node :
\lstinputlisting[language=Nit]{./poo/listings/type5_s.nit}

Nous aurions pu éviter cela en utilisant les types virtuels :
\lstinputlisting[language=Nit]{./poo/listings/type6_s.nit}

\chapter{Modules}
En Nit, il existe un moyen de regrouper des classes voisines ou qui couvrent un même domaine : ce sont les modules.

\section{Définition d'un module}
En Nit, la convention est de regrouper les classes qui doivent faire partie du même module dans un même fichier. Le nom du module doit correspondre au nom du fichier sans l'extension .nit.

Pour spécifier le nom du moule, il suffit de rajouter la directive |module nom_du_module| au début du fichier :
\lstinputlisting[language=Nit]{./poo/listings/package1_c.nit}

Le mot-clé |module| doit être la première instruction dans un fichier source et il ne doit être présent qu'une seule fois dans le fichier source (une classe ne peut pas appartenir à plusieurs modules).

\section{Utilisation d'un module}

\subsection{Import standard}
Pour utiliser ensuite le module ainsi créé, on l'importe dans le fichier grâce à l'instruction :
\begin{lstlisting}[language=Nit]
    [intrude|private] import nom_du_module
\end{lstlisting}
\lstinputlisting[language=Nit]{./poo/listings/import1_c.nit}

Si le nom du module diffère du nom du fichier, le compilateur ne sera pas capable de lier le module est retournera une erreur à la compilation : no ressource found for module nom\_du\_module.

Pour l'instant il n'est pas possible d'importer des modules se trouvant dans un autre répertoire que celui où se trouvent les fichiers sources.

\subsection{Import privé}
Si on utilise le mot-clé |private| devant le |import|, le module sera importé dans le module courant comme privé. C'est à dire que tous les modules qui importeront le module courant ne verrons pas les classes et les propriétés importées.

\subsection{Import intrusif}
L'utilisation du mot-clé |intrude| avant l'import d'un module permet d'importer le module en mode intrusif, c'est à dire d'ignorer toutes les restrictions liées à la visibilité. Ainsi les méthodes déclarées |private| seront considérées comme publiques.

Cette fonctionnalité est à utiliser avec beaucoup de précautions, elle est même déconseillée dans la plupart des cas.

\section{Raffinement de classe}
\label{raffinement-classe}
Nit permet de redéfinir des classes depuis une autre module pour en modifier les méthodes ou en rajouter, c'est le raffinement de classe.

Pour modifier une classe déjà déclarée il faut utiliser le mot-clé |redef| :
\lstinputlisting[language=Nit]{./poo/listings/redef2_c.nit}

Ici, nous venons de raffiner la classe Object pour lui ajouter la méthode coucou. Maintenant Object et toutes ses sous classes possèdent la méthode coucou. Par exemple nous appelons la méthode coucou sur l'objet de type Int.

Il est aussi possible de redéfinir les méthodes déjà existantes :
\lstinputlisting[language=Nit]{./poo/listings/redef3_c.nit}

Dans cet exemple nous avons redéfini la méthode to\_s de la classe String afin de retourner toutes les chaines en majuscules.

\chapter{Importation de la bibliothèque standard}
Il faut noter que les modules de la bibliothèque standard sont toujours importés implicitement lors de la compilation si aucun import n'a été spécifié. Par exemple il n'est pas nécessaire d'importer le module string pour utiliser la classe String.