Programmation: De la philosophie des langages

person
avatar (floreal) floreal
access_time
samedi 09 janvier 2016 à 00h52
label
C Ruby

Il est deux langages que j’aime beaucoup pratiquer: C et Ruby.

D’un coté C est très performant, très strict, difficile à appréhender et dont la logique parait peu naturelle. De l’autre nous avons Ruby, très malléable, qui s’adresse davantage aux humains que C.

Explorons donc les différences de ces deux langages. Je ne m’attarderai pas sur le fait qu’un des langage implémente un paradigme objet et que l’autre non, ce n’est pas le sujet de ce billet.

Je vais simplement partir de la simple comparaison de deux bouts de code qui conduisent au même résultat.

En C:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main(int argc, char** argv)
{
  char name[] = "World";
  
  if (argc > 1) {
    name = argv[1];
  }

  printf("Hello %s !\n", name);
}

En Ruby:

1
puts "Hello #{ ARGV[0] || 'World' }!\n"

Dans les deux cas le programme adresse des salutations au nom donné en premier paramètre. Si celui ci n’est pas donné, il les adresse au monde entier.

Verbosité et expressivité

Le code en Ruby peut être très facilement transcrit en langage humain (ici en Français):

Afficher une chaîne de caractères “Hello” suivi du premier argument ou “World”. l’expression #{ ARGV[0] || 'World' } au sein de la chaîne de caractères permet d’inclure le résultat de l’expression. Ici le contenu de ARGV[0] ou 'World’ si ce dernier n’a pas de valeur.

Voici la transcription (un peu caricaturale) du code C:

  1. Je vais faire appel aux fonction de contrôle d’entrée-sortie.
  2. En suite je vais commencer mon programme auquel on passe un certain nombre (argc) de paramètres (argv) dont voici la liste.
  3. J’initialise une variable name de type tableau de caractères. Je lui assigne la valeur “World”.
  4. Si argc (mon nombre d’arguments1) est plus grand que 1 alors name prend la valeur du premier argument passé au programme (argv[1])
  5. J’affiche une chaîne de caractère formatée “Hello” complétée avec la valeur de la variable name

On voit donc clairement qu’en C il est nécessaire de faire de nombreuses (6) opérations pour faire quelque chose à première vue très simple. Le code C est très verbeux, il ne se comprend pas facilement, il est peu expressif.

En revanche en Ruby, la traduction est plus simple, le code est plus compact. Et il se comprend très facilement. Le code est donc à la fois peu verbeux, et pourtant très expressif.

On peut donc être amené à penser que La verbosité du C le rend moins expressif que le Ruby.

Compilation et Interprétation

Il existe une différence fondamentale entre ces deux Langages. C est un langage compilé, alors que Ruby est un langage interprété 2.

Pour exécuter le programme écrit en C, il est nécessaire de passer par une étape de compilation, qui transforme le code en un langage compréhensible par le processeur afin d’obtenir un exécutable qu’on peut lancer. Les erreurs de syntaxe et de « fonction / variable non définies » sont détectés pendant la phase de compilation. Alors que les erreurs d’exécution (accès à une zone mémoire non autorisée, division par zéro, etc.) se font pendant l’exécution

Du coté de Ruby, Il faut lancer son programme avec l’interpréteur éponyme. Et toutes les erreurs se traitent au moment de l’exécution du programme.

Encore une fois Ruby se montre plus simple d’utilisation que C.

La mémoire

Enfin, et pour aller plus loin que le coté trivial des bouts de code cités au début de ce billet, je voudrais un autre aspect qui distingue ces deux langages: la gestion de la mémoire.

En C, dès qu’on veut faire quelque chose d’un peu complexe, efficace, optimisé, on sera tôt ou tard confronté à cette problématique là. On commence à manipuler des pointeurs3, gérer l’espace mémoire qu’ils vont occuper: l’allouer ou le libérer, etc.

En Ruby, la mémoire est gérée automatiquement par la machine virtuelle, il n’est pas question de gérer des pointeurs, et on ne manipule au final que des références sur des objets, sans trop se soucier des mécanisme (pourtant intéressants) mis en œuvre derrière.

Encore un exemple démontrant l’accessibilité de Ruby par rapport au C. Aussi, lorsqu’on utilise ce dernier, on maîtrise mieux le comportement de son programme.

Conclusion

En considérant les éléments soulevés tout au long de cet article, vous pourriez croire que j’ai une nette préférence pour Ruby par rapport au C. En fait il n’en est rien, comme je l’ai écrit en introduction, j’aime les deux langages. Autant l’un que l’autre.

D’un coté Ruby a tous les avantages d’un langage facile d’accès; de l’autre C, parait rigide difficile à l’emploi, et parfois punitif.

Ruby permet de s’abstraire des problématiques bas-niveau afin que le développeur puisse se concentrer sur la logique derrière ses algorithmes, facilite l’écriture de programmes.

Il est intéressant également de voir que de nombreux langages sont écrits eux même en C. MRI, l’implémentation historique du cœur de Ruby est lui même écrit en C. D’autres langages, comme PHP, Python ou Perl également.

Au final, ce n’est bien sûr pas par masochisme que j’aime programmer en C. En réalité cela me permet d’apprendre et comprendre le fonctionnement de mon ordinateur, du système d’exploitation qui le fait marcher, et des contraintes techniques qui en découlent, de mieux les maîtriser. Cela me sert dans d’autres langages, dans lesquels un code qui me parait sain au premier abord n’a pas le comportement attendu.

  1. En Ruby comme en C, le premier élément d’un tableau est à l’index 0. Concernant la liste des arguments, en Ruby ARGV[0] Correspond au premier argument, alors qu’en C, argv[0], est le nom de l’exécutable appelé (comme dans la plupart des autres langages, en fait), le premier argument est donc argv[1]. 

  2. Je traiterai de la compilation et de l’interprétation dans un prochain billet, éventuellement. 

  3. On peut considérer un pointeur comme un indicateur vers une adresse (mémoire, périphériques, sous-programme, etc). En d’autre terme un pointeur permet de décider où lire et écrire une valeur. Cela permet par exemple au driver de votre carte graphique d’envoyer du code OpenGL à votre carte graphique, ou de lire les touches tapées sur votre clavier.