Compilé, Interprété et POO ? C++ ou Python ?
Dans cet article, on va essayer de s'attaquer un petit peu à ce qui diffère entre le Python et le C++.
Une grande partie de ce que vous pourrez lire dans cet article est suffisamment générique pour vous servir même en dehors de ces deux langages.
En bref…
Le Python est un langage interprété, le C++ un langage compilé et ils sont tous les deux orientés objets.
Compilé, interprété et orienté objet ?
Il faut sûrement revenir sur ce qu'est un langage interprété, un langage compilé et un langage orienté objets (très souvent abrégé POO ou OOP en anglais). Je m'excuse d'avance auprès de ceux pour qui sont déjà super rôdé à ce niveau, mais c'est important de bien fixer ces notions.
Pour faire tourner un programme développé dans un langage compilé, il est nécessaire de passer par une étape qu'on appelle la compilation. C'est ce qu'on appelle un compilateur qui s'en occupera. De façon générale, un compilateur va s'occuper de transformer un code source écrit dans un langage de programmation précis vers un autre langage exploitable par la machine cible. Dans le cas du C++, ça sera donc vers le langage assembleur qui est lui-même une traduction directe du langage machine (la traduction de l'assembleur vers le langage machine est appelé « l'assemblage », c'est une opération extrêmement simple à effectuer puisqu'une instruction d'assembleur est équivalent à une instruction précise du processeur).
L'avantage, c'est que le processeur lit le langage machine sans aucun effort. Le soucis, c'est qu'il y a différents langages machine (ça dépend des processeurs). Mais ce n'est pas tellement notre problème, puisque ce qui nous intéresse c'est le C++, et la traduction, c'est le travail du compilateur.
Pour faire tourner un programme développé dans un langage interprété, il est cette fois nécessaire de passer par ce qui s'appelle un interpréteur. L'interpréteur est un programme généralement disponible en langage machine (parce qu'il faut bien que le processeur puisse comprendre à un moment donné) et qui va s'occuper de lire le code source pour, en quelque sorte, remplacer le processeur. C'est une sorte sur-couche, qui permet une certaine flexibilité, mais par contre votre programme sera automatiquement plus lent.
Il faut néanmoins un peu nuancer. Dans le cas de Python par exemple, nous ne sommes pas exactement en présence d'un langage interprété, mais plutôt un langage semi-interprété.
Le code source est en fait traduit dans un langage intermédiaire (que l'on appelle bytecode dans le cas de Python) et c'est ce langage qui sera interprété.
Il est en fait techniquement parfaitement possible de compiler le langage intermédiaire en langage assembleur / machine (pour ceux qui connaissent, en C, le compilateur gcc génère des fichiers .o qui sont en fait des fichiers de « code objet », un langage intermédiaire avant la traduction en assembleur).
Il existe d'ailleurs des moyens de compiler du code Python (cf Cython), mais pour avoir essayé, je peux vous dire que c'est pas tellement commode.
Maintenant, qu'est-ce qu'un langage orienté objet ?
Là ça va être plus difficile à expliquer en quelque lignes. Il est possible que le concept reste un peu flou, mais vous ne tarderez pas à comprendre avec un peu de pratique.
Tout d'abord, qu'est-ce qu'un programme. Pour simplifier, nous allons dire que :
Programme = Données + Algorithmes
Ce modèle nous permet de considérer deux choix dans la conception d'un programme :
- Se concentrer sur les algorithmes d'abord, puis les appliquer sur des données. C'est à dire qu'on va adapter les données aux algorithmes.
- Se concentrer sur les données et développer des algorithmes pour ces données.
Le premier cas a l'avantage d'être intuitif et facile à appliquer sur des problèmes de petite taille.
Le soucis, c'est que le code est souvent assez difficile à ré-utiliser, on a souvent besoin d'adapter ses données pour utiliser du code externe (librairies, …), le code est plus difficile à faire évoluer dans le temps.
Or on dit souvent que l'évolution d'un logiciel représente 70% de son cycle de vie, et la majorité des modifications concernent plutôt les données que les algorithmes. D'où cette difficulté de gérer l'évolution d'un programme en utilisant uniquement une méthodologie ultra centrée sur les algorithmes.
C'est là qu'intervient la programmation orientée objet, qui met davantage l'emphase sur les données.
On défini les données et ensuite on développe les algorithmes pour manipuler ces données.
L'association entre les données et les algorithmes adaptés mène à ce qu'on appelle des « Objets ». On peut visualiser un objet comme étant une boîte contenant des données et des boutons qui permettent d'effectuer des traitements (cette image n'est d'ailleurs pas un hasard, comme on aura l'occasion de le voir en particulier avec le C++).
Il reste encore beaucoup à dire sur la programmation orientée objet (notamment parler des 4 piliers qui sont « l'abstraction », « l'encapsulation », « l'héritage » et le « polymorphisme » si ça vous intéresse) , mais ce cours commence déjà à devenir sérieusement long alors que l'on n'est même pas encore rentrés dans le vif du sujet.
Peut-être que je déplacerai cette partie dans un cours dédié plus tard.
Revenons-en au C++ et au Python
De façon générale, un programme en Python tourne plus lentement qu'un programme C++ (les différences peuvent être énooormes selon ce que vous faites).
Maintenant que vous connaissez la différence entre un langage compilé et un langage interprété, vous vous doutez sûrement en partie de la raison.
Cependant, le fait de passer par un interpréteur n'est pas la seule raison pour laquelle Python est plus lent.
En fait, Python est également plus lent que Java (qui fonctionne pourtant à peu près sur le même modèle, compilation en langage intermédiaire, le bytecode java dont l'extension de fichier est .class).
C'est notamment dû au typage de Python qui est différent du typage du Java et du C++.
Je vais simplifier la notion de « typage » pour le moment.
Dans la plupart des langages de programmation, on trouve ce qui s'appelle des variables (en fait je n'en connaît aucun qui n'en a pas).
Du point de vue du programmeur, une variable est une sorte d'étiquette qui correspond à un certain emplacement dans la mémoire de l'ordinateur contenant une certaine quantité de données.
Voici comment l'on va déclarer des variables en C++ :
int anInteger;
anInteger = 5;
// peut aussi s'écrire en une seule ligne :
int anotherInteger = 5;
Ici, int
est le type de la variable (abréviation de integer qui signifie « entier ») et anInteger
son nom.
À la deuxième ligne, on affecte la valeur 5 qui est de type int
à la variable anInteger
qui est aussi de type int
.
En Python :
anInteger = 5
Donc on remarque déjà qu'en Python, même pas besoin de déclarer la variable, ni même de préciser son type.
Mais cela va encore plus loin.
Voici un autre exemple.
En C++ :
int anInteger = 5;
anInteger = "Hello!"; // aïe, aïe, ça ne va pas compiler !
Voilà ce qui se passe : à la première ligne, on déclare que la variable anInteger
est de type int
.
Et à la deuxième ligne, on veut lui affecter une valeur qui est une chaîne de caractères (du texte)
(note pour ceux qui ont déjà fait du C : le type est alors char*
).
Comme les deux types ne sont pas identiques, le compilateur va râler.
Il paraît logique qu'un entier ne puisse pas être du texte, non ?
En Python :
anInteger = 5
anInteger = "Hello!" # Aucun problème.
En Python, une variable peut parfaitement changer de type à la volée.
C'est pour cela que l'on dit que le typage du Python est « dynamique ». Maintenant la variable « anInteger » est une chaîne de caractères.
Nous allons aussi jeter un rapide coup d'œil à la façon dont on déclare une fonction dans les deux langages. Je ne vous demande pas de tout comprendre immédiatement, je veux juste vous montrer à quel point le C++ permet d'être minutieux et le Python permissif.
En C++ :
void printHelloWorld(void) { /* code */ }
int max(int a, int b) { /* code */ }
Purée moulinex(const Patate& patate) { /* code */ }
- Première fonction : on sait que la fonction ne renvoie aucune valeur et ne prend aucun paramètres.
- Deuxième fonction : on sait que la fonction renvoie un entier et prend en paramètres deux entiers.
- Troisième fonction : on sait que la fonction renvoie un objet de type Purée et prend en paramètre une référence constante (non modifiable) sur un objet de type Patate (pour en faire de la bonne purée bon dieu).
En Python :
def printHelloWorld():
# code
def max(a, b):
# code
def moulinex(patate):
# code
- Première fonction : on sait que la fonction ne prend aucun paramètres.
- Deuxième fonction : on sait que la fonction prend deux paramètres.
- Troisième fonction : on sait que la fonction prend un paramètre.
Il est important de proposer de la documentation aussi bien en C++ qu'en Python, mais en Python il arrive que sans documentation on ne puisse tout simplement pas comprendre quel genre d'arguments une fonction attend sans regarder le code
(je passe aussi sur le fait qu'une fonction en Python peut renvoyer des données de plusieurs types différents, contrairement au C++ où une fonction ne peut que renvoyer une donnée correspondant strictement au type indiqué).
La première remarque que l'on peut faire à ce stade, c'est qu'à terme, on peut facilement se retrouver à avoir des problèmes de consistance si l'on n'a pas été extrêmement rigoureux : des variables qui n'ont pas le type attendu au bon moment par exemple.
Un programme peut devenir complexe et prendre de la taille et il faut bien veiller à ne pas faire n'importe quoi, car l'interpréteur ne vous dira pas que votre code a un problème jusqu'à ce que ça plante pendant l'exécution du programme (on peut même imaginer des situations où votre programme ne plante pas systématiquement, bonne chance pour trouver le problème dans ce cas).
Voilà pourquoi je pense qu'il est plus compliqué de gérer un gros projet en Python (néanmoins pas impossible, ce genre de projets existent).
Pour des programmes de taille modeste, en général ça ne pose aucun problème.
L'autre remarque, c'est qu'au niveau de l'interpréteur, du côté de Python, lorsque par exemple on va se retrouver à effectuer des opérations comme tout simplement a + b, il va déjà falloir vérifier que a et b peuvent être additionnés.
En C++, si ça compile, c'est qu'à priori, on peut bien faire cette addition. La vérification est effectuée au moment de la compilation en se basant sur les types des variables et le code machine s'exécutera sans avoir à re-effectuer cette vérification.
Par contre, il est vrai que l'on peut se retrouver à écrire facilement 5 fois plus de code en C++ pour obtenir un programme équivalent et qu'il est beaucoup plus simple d'écrire du code Python rapidement.
En fait, Python brille plutôt dans un rôle de « super glue », de contrôleur « haut niveau », qui s'occupe de relier divers composants « bas niveau » (comprenez « proche de la machine ») écrits par exemple en C++.
Je dirais même qu'utiliser un langage haut niveau et un langage bas niveau de cette façon donne une excellente combinaison.
Il existe de nombreuses librairies écrites en C++ pouvant être utilisées en Python.
Et c'est notamment toutes ces librairies qui font la force de Python.
On va pouvoir faire du calcul scientifique en utilisant la bonne librairie écrite en C++ qui fait les dits calculs plus rapidement.
On va pouvoir faire des jeux vidéo en utilisant une libraire qui s'occupera de gérer le matériel pour nous, ou qui nous fournira un moteur physique (par contre, dès que vous allez vouloir faire votre propre moteur physique en Python, il vaudra mieux que ça reste modeste…).
L'autre avantage de Python, c'est qu'il est certainement plus rapide à apprendre que le C++.
Mais je trouve que l'on apprend davantage de choses en C++ (choses qui servent toujours même en Python bien que l'on ne s'en rende pas compte).
On pourrait encore continuer longtemps à analyser les différences entre les deux langages, mais je pense que l'on a vu les différences principales.
Je vous invite à lire cette page wikipédia sur le typage fort si vous vous sentez d'aller un peu plus loin en ce qui concerne le typage dont j'ai brièvement parlé plus haut (je ne suis pas passé sur la différence entre typage fort et typage faible) :
https://fr.wikipedia.org/wiki/Typage_fortVoilà, désolé, c'était peut-être un peu long… je ne sais pas ce que vous en pensez ?
J'espère avoir été clair dans tout ce que j'ai pu raconter.
Si vous avez des remarques, des retours, des questions
ou des lettres d'amour, n'hésitez pas à poster une réponse !