Je trouve globalement Zig très rafraîchissant et bourré de bonnes idées.
Typiquement l'intégration d'un compilo C capable de cross-compilation dans quelques dizaines de Mo. Ça donne même des idées pour les logiciels ayant besoin d'embarquer un compilo pour faire du JIT.
Bref j'en arrive à ma question: mais pourquoi donc des gens aussi compétents refusent de mettre du RAII (c'est à dire des fonctions destructeur appelées automatiquement quand un objet se fait free ou bien est enlevé de la stack) ?
De ce que je comprends l'argument avancé c'est:
1 - c'est pour qu'il n'y ait rien de caché
2 - c'est plus lisible car c'est explicite
Pour le premier point on peut objecter que nos CPU modernes ne se privent pas pour faire toute sorte de magie noire avec notre code (out-of-order, processeur super-scalaires).
L'OS de sont côté décide arbitrairement du scheduling des threads, déclenches des interruptions quand ça lui chante et fait semblant d’allouer de la mémoire quand on fait un malloc pour finalement tuer notre process sur un out-of-memory quand il a été trop optimiste...
Bref des choses cachées quand on un impact sur notre programme c'est pas ça qui manque dans un ordinateur moderne !
Le second point me semble encore plus incompréhensible: on se retrouve avec un pattern consistant à systématiquement devoir écrire var foo = init(); defer foo.destroy();.
- Si on oublie le defer on a fait un bug
- Donc faut faire gaffe à ça en code review
- Et faut des outils pour détecter ce type d'erreurs
- Et ça peut être plein de classes de bug: memory leak, resource leak (e.g. on ne ferme pas un fichier), deadlock (e.g. la ressource représente la prise de mutex)
En règle générale avoir un langage qui permet d'exprimer des structures ne pouvant pas représenter un état invalide est un gain énorme (exemple typique: en Rust un mutex contient l'objet qu'il protège, de fait il est impossible d'accéder à ce dernier sans avoir pris le mutex).
Et si on veut pinailler, defer est déjà quelque de magique vu qu'on n'est pas explicite sur l'endroit où sera fait l'appel de fonction (j'imagine que personne n'est assez fou pour défendre l'utilisation de free sans defer ni RAII comme en C ).
De fait plutôt qu'un defer, j'aurai plutôt vu un mot clé permettant d'indiquer qu'une fonction retournait un object avec destructor.
Quitte à devoir explicitement fournir le destructeur dans la fonction d'initialisation si on veut rester plus explicite, par exemple:
var foo = raii foo_factory() -> foo_destructor; // pseudo syntax, On peut même obliger les variables raii à avoir un nom particulier (genre avec un symbole en préfixe) étant donné que la variable peut survivre à la fonction l'ayant créée (typiquement en la retournant à l'appelant), ce qui était moins utile pour le defer car il s'exécute uniquement dans la fonction d'où il est déclaré.
Bref, de ma fenêtre le RAII apporte des avantages monstrueux comparés à ses "inconvénients" théorique (et ça semble plutôt simple de faire un defer sous stéroïde qui garde le meilleurs des deux mondes). Et du coup je n'arrive à comprendre le raisonnement des devs de Zig (qui, je le rappelle sont des mecs sacrément brillants !)
Dernier point: on n'est pas vendredi, ce post n'est pas un troll (ni un flim sur le cyclimse). Il est bien possible que j'ai fait un homme de paille sans le vouloir avec les arguments pour l'absence de RAII, si c'est le cas merci de me corriger dans la joie et la bonne humeur ;-)
# Mais pourquoi diantre pas de RAII ?
Posté par G.bleu (site web personnel) . En réponse à la dépêche De Zig et des zags. Évalué à 10.
Merci beaucoup pour cette dépêche très sympa ;-)
Je trouve globalement Zig très rafraîchissant et bourré de bonnes idées.
Typiquement l'intégration d'un compilo C capable de cross-compilation dans quelques dizaines de Mo. Ça donne même des idées pour les logiciels ayant besoin d'embarquer un compilo pour faire du JIT.
Bref j'en arrive à ma question: mais pourquoi donc des gens aussi compétents refusent de mettre du RAII (c'est à dire des fonctions destructeur appelées automatiquement quand un objet se fait free ou bien est enlevé de la stack) ?
De ce que je comprends l'argument avancé c'est:
1 - c'est pour qu'il n'y ait rien de caché
2 - c'est plus lisible car c'est explicite
Pour le premier point on peut objecter que nos CPU modernes ne se privent pas pour faire toute sorte de magie noire avec notre code (out-of-order, processeur super-scalaires).
L'OS de sont côté décide arbitrairement du scheduling des threads, déclenches des interruptions quand ça lui chante et fait semblant d’allouer de la mémoire quand on fait un malloc pour finalement tuer notre process sur un out-of-memory quand il a été trop optimiste...
Bref des choses cachées quand on un impact sur notre programme c'est pas ça qui manque dans un ordinateur moderne !
Le second point me semble encore plus incompréhensible: on se retrouve avec un pattern consistant à systématiquement devoir écrire
var foo = init(); defer foo.destroy();.- Si on oublie le defer on a fait un bug
- Donc faut faire gaffe à ça en code review
- Et faut des outils pour détecter ce type d'erreurs
- Et ça peut être plein de classes de bug: memory leak, resource leak (e.g. on ne ferme pas un fichier), deadlock (e.g. la ressource représente la prise de mutex)
En règle générale avoir un langage qui permet d'exprimer des structures ne pouvant pas représenter un état invalide est un gain énorme (exemple typique: en Rust un mutex contient l'objet qu'il protège, de fait il est impossible d'accéder à ce dernier sans avoir pris le mutex).
Et si on veut pinailler,
deferest déjà quelque de magique vu qu'on n'est pas explicite sur l'endroit où sera fait l'appel de fonction (j'imagine que personne n'est assez fou pour défendre l'utilisation de free sans defer ni RAII comme en C ).De fait plutôt qu'un
defer, j'aurai plutôt vu un mot clé permettant d'indiquer qu'une fonction retournait un object avec destructor.Quitte à devoir explicitement fournir le destructeur dans la fonction d'initialisation si on veut rester plus explicite, par exemple:
On peut même obliger les variables raii à avoir un nom particulier (genre avec un symbole en préfixe) étant donné que la variable peut survivre à la fonction l'ayant créée (typiquement en la retournant à l'appelant), ce qui était moins utile pour le defer car il s'exécute uniquement dans la fonction d'où il est déclaré.var foo = raii foo_factory() -> foo_destructor; // pseudo syntax,
Bref, de ma fenêtre le RAII apporte des avantages monstrueux comparés à ses "inconvénients" théorique (et ça semble plutôt simple de faire un defer sous stéroïde qui garde le meilleurs des deux mondes). Et du coup je n'arrive à comprendre le raisonnement des devs de Zig (qui, je le rappelle sont des mecs sacrément brillants !)
Dernier point: on n'est pas vendredi, ce post n'est pas un troll (ni un flim sur le cyclimse). Il est bien possible que j'ai fait un homme de paille sans le vouloir avec les arguments pour l'absence de RAII, si c'est le cas merci de me corriger dans la joie et la bonne humeur ;-)