Allez, hop, j'arrive après la guerre et je répond, parce que je suis un vil
pythoneux qui ne supporte pas que l'on dise du mal du meilleur langage du
monde (Lisez tout de même la suite avant de moincer, j'ai essayé de mettre des
arguments)
* Le python n'est pas un langage compilé, j'aime bien les langages
compilés. Ça permet de faire des mini-pauses pendant la compilation, et on a
pas d'erreurs bêtes qui arrivent au milieu du programme (par exemple, une
concaténation entre un string et un nombre).
Pour les minis pauses, je suis tellement d'accord. Sauf qu'ici au boulot c'est
des pauses de 30 minutes chaque fois que l'on change un commentaire dans le
fichier .h qui contient le template de base du système...
Sinon, pour le coté erreurs en pleins milieu, les autres l'on déjà dis, tu
confond la compilation et le tapage statique. Java est aussi un langage
interprété et pourtant tu as des erreurs au milieu du programme.
Mais en pratique en C++ tu as aussi des erreurs en milieu du programme que la
*compilation* ne réglera jamais. Par contre l'interpréteur peut être plus
malin que ton CPU en te renvoyant une erreur plus précise (genre unbound acces
en lieu et place de segfault). Mais j'avoue qu'avec une utilisation correcte
de la STL, tu n'as plus de segfault (enfin presque). Mais cette utilisation
correcte de la STL revient à rendre C++ aussi lent (enfin presque) que
Python...
* Le python ne permet pas de gérer manuellement la mémoire. Le ramasse
miettes, je n'accroche pas du tout. Surtout qu'avec une bonne architecture
du programme, on ne rencontre pas beaucoup de problèmes de gestion mémoire
en C++.
Chacun ses goûts. Je suis en grande partie d'accord avec toi quand je fais de
la programmation qui se doit d'être *vraiment* (cf plus loin) le plus rapide
possible.
Mais dans 99.9% des cas (chiffre au pif), quel est le besoin de gérer
l'allocation mémoire ? Tout le monde ici programme des fusées (Et encore, je
ne métrais pas de C++ dans les fusées), Tout le monde ici fait de la synthèse
d'image temps réel ? (Et encore, on peut en faire en python). Bon, donc sauf
si j'ai raté la dernière révolution, la plupart des code développés n'ont PAS
besoin de performances dingues, et n'ont PAS besoin de gestion fine de la
mémoire. Dans le cas particulier de l'article que l'on commente, l'on parle de
conception d'interfaces graphiques. Ici, 99.9% (chiffre au pif, certainement
surévalué) du temps CPU se passe dans le code du toolkit graphique et celui-ci
doit certainement faire une bonne partie des allocations mémoires (voirs peut
être 99.9% de celles-ci). Je connais mal Qt mais du peu que j'en ai fais en
C++, je ne me rappel pas avoir passé la moitié de la journée à faire des
malloc.
Et puis, tu dis aimer gérer toi même la mémoire, mais combien de personnes
utilisent une malloc alternative, combien de personnes surchargent le
paramètre alloc des templates de la STL ? Combien de personnes surchargent
l'opérateur new de la STL ? Si tu ne fais pas cela, alors tu ne peux pas
prétendre aimer gérer la mémoire.
De son coté, le GC de python, son job est de faire un malloc (si nécessaire)
quand tu crée un objet et nettoyer la mémoire (si il juge cela pertinent)
quand tu n'as plus besoin de cet objet. Alors oui, l'on ne maîtrise rien, mais
maitrise-t-on moins qu'avant ? Que faut-t-il craindre du GC de python ? Il
fait un travail fastidieux à notre place, en faisant moins d'erreur et
potentiellement plus rapide (du fait du pool de mémoire qui est réutilisé). Il
faut juste savoir l'utiliser correctement (ne rien faire) et si l'on veut une
utilisation avancé, il est aussi possible de l'utiliser de façon avancé (en
désactivant le GC de recherche de références cyclique et en ne laissant que le
compteur de référence qui ne consomme virtuellement rien)
* Pas de typage explicite des variables. C'est super pénible de ne pas savoir
quelle est le type de la variable que l'on a à gérer.
Goût et couleurs... Personnellement je ne m'intéresse pas à la variable ni à
son type, mais à ses capacités. Note que rien ne t'empêches en python de faire
du typage static.
Tu peux par exemple "décorer" tes arguments de fonctions:
def tortue(a:int, b:float)->float
Ensuite libre à qui veut de faire ce qu'il veut avec cela (je m'en sert pour
documenter les valeurs). Mais avec cela, tu n'as aucun problème pour faire de
la vérification de type au run-time, ou, un peu plus dur, écrire un
vérificateur de type statique. J'avoue, dans certains cas cela sera un peu
sioux ;)
Mais le problème ici, c'est que l'on s'en fout car l'on vois les types
de façon différente, plus comme une interface implicite :
Prenons un exemple. Tu est le gérant d'un bar. Un blanc entre dans le bar, tu
as prévu d'ouvrir le bar aux blancs, donc tu lui verses sa bière.
Un black (Il faut dire black pour être non raciste aujourd'hui) entre dans le
bar. Tu avais prévu que les blancs, mince. Comme t'es pas raciste, tu changes
ta porte d'entrée pour laisser passer les "buveurs", et tu demandes à tes
clients de se faire référencer comme buveur. Tu peux donc tout Homme se
présentant comme un buveur.
Un alien entre dans ton bar, et te demande à boire. Il n'a pas l'interface
buveur (son vaisseau vient de s'écraser devant ton bar, personne sur terre ne
connais l'existence de cette race d'arien, donc personne n'a pensé à le
rajouter dans le fichier des espèces qui boivent... Mais il a soif et te
montre de façon insistance avec sa tentacule la bouteille de bière. Pas
d'interface buveur, il ne bois pas. C'est ainsi que commencera la première
guerre universel (A lire, universal war one, très bonne BD sur ce sujet, enfin
presque).
Alors oui, on pourrait dire que c'est préférable de l'empêcher de boire si
l'on ne sait pas si il peut boire (imagine, il se trompe et cela le tue...).
C'est deux façon de voir les choses et je préfère rendre responsable les
développeurs que de rendre responsable le code. Le résultat étant le même à la
fin, soit c'est bon et cela passe, soit cela te pète à la gueule (au runtime
ou à la vérification statique). D'un coté tu t'es embêté à écrire du code
complexe, de l'autre t'as mis en place une procédure pour que cela pète au
runtime chez toi et pas chez le client (des tests par exemple). Comprendra qui
veut (Personnellement je préfère ne pas m'embêter en codant et écrire des
tests, parce que les tests, j'aurais honte de fournir du code au client qui
n'est pas testé... Donc entre écrire des tests et m'embêter en codant, ou juste
écrire des tests (et en plus sans m'embêter à les écrire...), le choix est
vite fait)
Le problème ici c'est que python ne manque pas d'une fonctionnalité de typage,
c'est juste une façon différente de voir les choses.
* Le self comme argument dans les méthodes de classes, c'est vraiment très
très moche comme hack, et les messages d'erreurs sont faussés (quand il
manque des arguments, le nombre d'arguments comprend le self, alors que l'on
ne doit pas le préciser avec la syntaxe classique).
Problème de goût et erreur de compréhension. Personnellement je trouve que le
this implicite en C++ c'est très moche comme hack (mon dieu, il vient d'où ?).
Après pour l'histoire du self, il n'y a pas de message d'erreur faussés, juste
une habitude que tu as pris d'ignorer dans le compte des arguments l'instance
concerné
toto.doit(5)
pour moi c'est une fonction (C.doit) qui prend deux arguments, toto et 5. C
sera dynamiquement déduit du type de toto (en l'occurrence, toto.doit(5) est
juste un raccourci syntaxique pour:
toto.__class__.doit(toto, 5)
avec toto.__class__ = C
Et là ou le système de type est intéressant, c'est que la classe C est finalement
juste un gros namespace de fonction travaillant sur des objets equivalents,
mais rien ne t'empeches de faire:
titi = B() # b n'a RIEN a voir avec C dans l'arbre d'héritage
C.doit(titi, 5)
En C++, on appelle cela les templates... En python on appelle cela le
dynamisme, mais en pratique les deux langages font la même chose...
Personnellement, je n'ai jamais compris pourquoi les autres langage ne
faisaient pas comme cela (pour le self/this). Et même avant que je connaisse
python, je ne comprenais pas. Quand j'ai découvert python, j'ai bondi de joie
au plafond en hurlant "Mon dieu, enfin des gens logiques qui pensent comme
moi"... Donc loin d'un hack immonde, c'est encore une fois un problème de
façon de voir les choses (même si le hack immonde, il faut être fou pour ne
pas se rendre compte qu'il est dans le langage C++ ;)
D'ailleurs, on va pousser un peu. Supposons une classe A et une
classe fille B ayant tout les deux une méthode "blork", Dans B.blork tu veux
appeler le A.blork sur l'instance courante...
En java tu utiliseras "inherited", bon, ok, java n'as pas d'héritage multiple
(en bien ou en mal), donc cela fonctionne très bien (je trouve cela juste
dommage d'introduire un nouveau mot clé dans le langage pour cela...)
En C++, tu utilises l'opérateur de portée de classe:
void B::blork()
{
A::blork();
}
Donc ici de façon implicite, A::blork est appelée avec le contexte. Mais si tu
utilises A::blork() en dehors de la classe B, et bien cela risque de ne pas
fonctionner non ?
En python tu verras simplement A.blork(self) que tu sois DANS l'instance le
code de la classe B ou en dehors (sauf que en dehors tu n'écrira pas de
variable nommée self ;)
Autre exemple. Tu écris une fonction qui travaille sur un objet de classe A,
et qui fait un truc
def mafonction(something):
assert(is_instance(something, A))
#dosomething with something
Note qu'ici je vérifie le type, pour le sport.
Puis après, tu obtient le pouvoir d'intégrer ta fonction au sein de la classe
A. Et bien tu n'as rien à changé, le prototype reste le même (faut renommer
self en something partout pour que cela soit joli, mais sinon c'est la même
chose).
Je ne parle pas de simplicité pour le refactoring ou autre hein (en C++ c'est
presque aussi simple en C++), je parle de cohérence. En C++ ce n'est pas du
tout la même chose, en python c'est toujours une fonction, il n'y à rien de
changé. En c++ il y a des namespaces, des classe, des fonctions, des méthodes
statiques, des méthodes d'instance. En python l'on fait la même chose
simplement avec des namespaces et des méthodes.
* On ne peut pas modifier un caractère d'une chaîne de caractère, obligé de
* faire une copie.
C'est un choix qui semble logique de mon coté. Une chaîne de caractère tient
sa valeur de son contenu, tu changes le contenu, tu changes la chaîne. Mais
sincèrement, on s'en cogne pas un peu ? Je crois que je n'ai jamais changé
un caractère dans une chaîne... A la limite plusieurs, mais cela change
complètement l'algo derrière, et j'avoue être plutôt heureux que python me
l'interdise ;)
Et si vraiment tu n'est pas content, libre à toi d'écrire un type
mutablestring basé sur les listes voir même sur les chaînes. Cela prend 5
minutes. Mais je n'en vois pas l'intérêt.
Les exceptions pour les jeux de caractères, ça me gonfle.
Précise ta remarque ? Les exceptions que j'ai eu en python étaient toutes liés
à une erreur de ma part. Une fois que tu as compris qu'il faut toujours
travailler en unicode (ou str dans python3), sauf pour les entrées sorties ou
tu converties en str (ou bytes dans python3) ou les traitements qui n'ont pas
de valeur de chaîne de caractère, il n'y a plus de problème.
On parlait tout a l'heure de vérification à la compilation, du fait que le
typage apportait un lot de sécurité, bla bla bla... Et bien ici python
t'apporte le fait que si tu fais des bêtises avec ta chaîne de caractère, il
te hurle dessus pour éviter que tu ne vois pas que la sortie est remplie de
petits '?', certes très jolis. Python est ici plus sécurisé que le C++, sans
être embêtant...
De toute façon ici l'on ne peut pas comparer avec C++, la lib standard C++ ne
gère pas l'un code, donc de toute façon tu n'aurais jamais eu ses erreurs en
C++, mais ce n'est pas forcement pour une bonne raison. C++ 0x apportera un
vrai support des chaînes de caractère, donc rassurez vous, cet argument en
faveur de python ne sera plus dans quelques années, à en juger par
l'implémentation du C99 sur les grands compilateurs du marché, au moins 10 ans ;)
L'impression générale d'être limité à une utilisation en haut niveau.
Précise ? Oui tu ne feras jamais un OS en python (et encore, cela pourrait
être marrant), mais quelles sont tes contraintes bas niveau ?
Personnellement je fais de l'OpenGL/Cuda/OpenCL tous les jours avec, et je
trouve que c'est suffisamment bas niveau...
Maintenant oui, j'accepte cet assertion, cependant revenons au débat sur Qt,
personnellement je m'en fout de toucher mes registres à la main, de faire du
(S/M)IMD, de gérer ma gestion de lignes de cache du CPU, de savoir comment mes
pages mémoires sont swapées. ON fait de la GUI là... On est en 2010, combien
de personnes, à part les gens qui font du système ou de l'image ont besoin
d'autant de bas niveau ?
Alors oui, quand j'ai besoin de bas niveau (mon dieu, il y a quoi dans mon
cache L2 !!!) Je fais du C (et du C++ quand vraiment je fais un gros truc et
que j'ai besoin d'une syntaxe objet plus légère que celles possibles en C),
mais quand je fais une gui, avec C++ j'ai "l'impression générale d'être limité
à une utilisation de bas niveau".
Puis l'indentation obligatoire, c'est super pénible. Surtout quand on
* reprends le code d'une autre personne, ou que l'on a juste commenté une
* condition.
C'est personnel. Moi je ne supporte plus les accolades et points virgules et
bien que j'ai plus d'années d'expériences en C/C++ que python, n'oublies
encore pleins de ;, mais je n'oublies jamais d'intenter mon code...
Quand j'enseigne la programmation à la fac ou en école d'ingé Je passe les 3/4
de mes séances C/C++/Pascal à rajouter des {};begin/end... J'ai la chance
d'avoir quelques groupes d'enseignement en Python, et bien je n'ai jamais* eu
de problème avec l'indentation et la syntaxe du langage.
* Une fois un élève qui à changé la configuration de son éditeur de texte pour
l'indentation et qui est passé soudain de 4 espaces à un tab... Un beau
bordel, j'avoue. Mais une fois ce détail connu pour une utilisateur averti,
il suffit d'un peu de rigueur (et d'un éditeur bien configuré) et ce problème
devient un souvenir.
Pour les commentaires de conditions, j'avoue, c'est peu pratique (enfin en C
tu est aussi forcé de supprimé les accolades ouvrantes et fermantes, sauf si
tu acceptes la déclaration d'un nouveau bloc, ce qui, j'avoue, à peu
d'implications, sauf si il reste encore le else après et là t'es eu...
Personnellement, j'ai une macro $EDITOR pour chercher le if le plus proche, et
cycler entre:
if condition:
#TODO if condition:
if True:
#TODO if condition:
if False:
Et elle est adaptée d'une macro pour le C que j'avais avant qui faisait la
même chose, car je n'ai pas trouvé mieux (je suis preneur).
Ce que j'aime bien dans les langages compilés sinon, c'est l'optimisation
automatique du code (en python, on perd la documentation quand on veut
optimiser). Gcc va vraiment plus optimiser, et même en fonction de
l'architecture de la machine.
Avec un langage interprété, effectuer les mêmes optimisations serait possible,
mais ce serait aussi bien trop lent à exécuter.
La suppression de documentation n'optimise pas plus, elle réduit seulement la
taille du fichier. Tu as deux flag en python, -O et -OO pour optimiser. -O ne
fait pas grand chose (principalement, il supprime les assert et la variable
__debug__) et -OO supprime la documentation. Si tu veux optimiser, python
n'est vraiment pas la bonne solution.
Et là je vais revenir sur le débat de la mémoire. ON s'en COGNE des
optimisations. On fait de la GUI ici hein, de la GUI ! Le truc pour lequel le
toolkit bouffe 99.9% de ton temps CPU pour dessiner des fenêtres à l'écran. Le
truc ou l'élément limitant en terme de performances et de réactivité c'est
l'utilisateur, la carte graphique, le serveur d'affichage et le toolkit.
Et puis pour la plupart on fait de la GUI qui affiche les
résultats qui sortent d'une BDD, le truc qui va prendre un temps de fou pour
revenir, parce que une BDD c'est des milliers de cycle CPU pour ramener une
petite donnée, c'est comme cela. Et on fait de la gui qui va lire et charger
des fichiers Image, qui va prendre quelques milliers de cycle CPU pour
décompresser le jpeg. Tout cela est déjà écrit et est lent, et sera toujours
plus lent que 10 appels de fonction dans python pour connecter ton évènement
clique de bouton sur la fonction de décompression de JPEG.
Alors oui, python prendra quelques cycles CPU de plus que C++ dans la boucle
principale, cycles qui sont négligeables à cote de ceux nécessaire au toolkit
pour afficher ta fenêtre. Alors OUI, je ne ferais jamais un toolkit en python,
ou une librairie de décompression JPEG, (et encore... faut voir ;)), mais
quand l'on parle d'utilisation de librairies qui existent déjà.
Et puis l'on parle d'optimisation et de C++, j'en rigole tous les jours. Du
fait des mécanismes d'héritage virtuel, les appels de fonction en C++ sont
lents et ne peuvent être inlinés (on parlait d'optimisation par le compilateur
?).
Alors OUI, python n'est pas parfait, Oui il a des défauts, le plus gros étant
qu'il ne code pas à ma place, ainsi je suis obligé d'aller au boulot et de
coder (parce que sinon je coderais à la maison pour le plaisir, ou je ferais
de l'escalade, ou je jouerais à Ryzom). Je vous demande juste une chose, ne
pas critiquer python sur des goûts personnels (l'indentation, le self, ...) ou
sur des fausses idées (python est lent. Oui, mais lent à quel point ?), mais
faites le sur des vrais points techniques, je peux en citer pleins :
- Python sucks en multithreadé à cause du GIL (cela se discute, mais globalement c'est vrai
pour les calculs cpu-bound)
- Déployer une application écrite en python c'est plus chiant qu'un bon gros
binaire Qt linké en statique. Sous windows un bon gros binaire Qt linké en
statique marche tout seul, alors que la même application en pytoolkit doit
contenir plusieurs fichiers, et il faut installer python, pytoolkit, toolkit
et dépendances du toolkit + pydependances du toolkit (ceux qui font du pygtk
doivent sourire en ce moment...). Bon, ca j'avoue que c'est super lourd...
- Python n'est pas un langage normé ISO (bon, celle-la me fait toujours rire,
mais peu avoir de la valeur), ceci impliquant aussi le prochain point,
- Python à au moins 6 implémentations différentes (Cython, UnladenSwallow,
Jython, IronPython, Pypi, Stackless), ayant toutes des différences de
comportement et de librairies, donc python n'est pas portable entre ses
différentes implémentations (bon, le C/C++ c'est pareil, hormis le C(++)
ansi sans utiliser la STL, c'est pas portable d'un compilo à un autre. C'est
encore plus vrai pour les libraries qui ne fonctionnent pas de la même
manière d'un système à un autre (Apple, quand tu packages !!!) et c'est la
plaie des systèmes de build (Mais ou est donc pkg-config sous Windows ?)
- Python sucks pour d'interfacer avec du C++ (alors qu'avec du C c'est très
simple) et cela parce que C++ sucks sur le name mangling et autres bêtises.
(Les symboles exportées par le compilateur peuvent être différents d'un
compilateur à l'autre. J'avoue que je ne sais pas exactement qu'elle est le
statut des normes à ce sujet)
Bon, je vais me coucher, vous pouvez moinser... A non, faut que je relise
l'orthographe avant... (et merde...)
[^] # Re: Une vraie question
Posté par Guillaum (site web personnel) . En réponse au journal QML: le futur des interfaces graphiques. Évalué à 7.
pythoneux qui ne supporte pas que l'on dise du mal du meilleur langage du
monde (Lisez tout de même la suite avant de moincer, j'ai essayé de mettre des
arguments)
* Le python n'est pas un langage compilé, j'aime bien les langages
compilés. Ça permet de faire des mini-pauses pendant la compilation, et on a
pas d'erreurs bêtes qui arrivent au milieu du programme (par exemple, une
concaténation entre un string et un nombre).
Pour les minis pauses, je suis tellement d'accord. Sauf qu'ici au boulot c'est
des pauses de 30 minutes chaque fois que l'on change un commentaire dans le
fichier .h qui contient le template de base du système...
Sinon, pour le coté erreurs en pleins milieu, les autres l'on déjà dis, tu
confond la compilation et le tapage statique. Java est aussi un langage
interprété et pourtant tu as des erreurs au milieu du programme.
Mais en pratique en C++ tu as aussi des erreurs en milieu du programme que la
*compilation* ne réglera jamais. Par contre l'interpréteur peut être plus
malin que ton CPU en te renvoyant une erreur plus précise (genre unbound acces
en lieu et place de segfault). Mais j'avoue qu'avec une utilisation correcte
de la STL, tu n'as plus de segfault (enfin presque). Mais cette utilisation
correcte de la STL revient à rendre C++ aussi lent (enfin presque) que
Python...
* Le python ne permet pas de gérer manuellement la mémoire. Le ramasse
miettes, je n'accroche pas du tout. Surtout qu'avec une bonne architecture
du programme, on ne rencontre pas beaucoup de problèmes de gestion mémoire
en C++.
Chacun ses goûts. Je suis en grande partie d'accord avec toi quand je fais de
la programmation qui se doit d'être *vraiment* (cf plus loin) le plus rapide
possible.
Mais dans 99.9% des cas (chiffre au pif), quel est le besoin de gérer
l'allocation mémoire ? Tout le monde ici programme des fusées (Et encore, je
ne métrais pas de C++ dans les fusées), Tout le monde ici fait de la synthèse
d'image temps réel ? (Et encore, on peut en faire en python). Bon, donc sauf
si j'ai raté la dernière révolution, la plupart des code développés n'ont PAS
besoin de performances dingues, et n'ont PAS besoin de gestion fine de la
mémoire. Dans le cas particulier de l'article que l'on commente, l'on parle de
conception d'interfaces graphiques. Ici, 99.9% (chiffre au pif, certainement
surévalué) du temps CPU se passe dans le code du toolkit graphique et celui-ci
doit certainement faire une bonne partie des allocations mémoires (voirs peut
être 99.9% de celles-ci). Je connais mal Qt mais du peu que j'en ai fais en
C++, je ne me rappel pas avoir passé la moitié de la journée à faire des
malloc.
Et puis, tu dis aimer gérer toi même la mémoire, mais combien de personnes
utilisent une malloc alternative, combien de personnes surchargent le
paramètre alloc des templates de la STL ? Combien de personnes surchargent
l'opérateur new de la STL ? Si tu ne fais pas cela, alors tu ne peux pas
prétendre aimer gérer la mémoire.
De son coté, le GC de python, son job est de faire un malloc (si nécessaire)
quand tu crée un objet et nettoyer la mémoire (si il juge cela pertinent)
quand tu n'as plus besoin de cet objet. Alors oui, l'on ne maîtrise rien, mais
maitrise-t-on moins qu'avant ? Que faut-t-il craindre du GC de python ? Il
fait un travail fastidieux à notre place, en faisant moins d'erreur et
potentiellement plus rapide (du fait du pool de mémoire qui est réutilisé). Il
faut juste savoir l'utiliser correctement (ne rien faire) et si l'on veut une
utilisation avancé, il est aussi possible de l'utiliser de façon avancé (en
désactivant le GC de recherche de références cyclique et en ne laissant que le
compteur de référence qui ne consomme virtuellement rien)
* Pas de typage explicite des variables. C'est super pénible de ne pas savoir
quelle est le type de la variable que l'on a à gérer.
Goût et couleurs... Personnellement je ne m'intéresse pas à la variable ni à
son type, mais à ses capacités. Note que rien ne t'empêches en python de faire
du typage static.
Tu peux par exemple "décorer" tes arguments de fonctions:
def tortue(a:int, b:float)->float
Ensuite libre à qui veut de faire ce qu'il veut avec cela (je m'en sert pour
documenter les valeurs). Mais avec cela, tu n'as aucun problème pour faire de
la vérification de type au run-time, ou, un peu plus dur, écrire un
vérificateur de type statique. J'avoue, dans certains cas cela sera un peu
sioux ;)
Mais le problème ici, c'est que l'on s'en fout car l'on vois les types
de façon différente, plus comme une interface implicite :
Prenons un exemple. Tu est le gérant d'un bar. Un blanc entre dans le bar, tu
as prévu d'ouvrir le bar aux blancs, donc tu lui verses sa bière.
Un black (Il faut dire black pour être non raciste aujourd'hui) entre dans le
bar. Tu avais prévu que les blancs, mince. Comme t'es pas raciste, tu changes
ta porte d'entrée pour laisser passer les "buveurs", et tu demandes à tes
clients de se faire référencer comme buveur. Tu peux donc tout Homme se
présentant comme un buveur.
Un alien entre dans ton bar, et te demande à boire. Il n'a pas l'interface
buveur (son vaisseau vient de s'écraser devant ton bar, personne sur terre ne
connais l'existence de cette race d'arien, donc personne n'a pensé à le
rajouter dans le fichier des espèces qui boivent... Mais il a soif et te
montre de façon insistance avec sa tentacule la bouteille de bière. Pas
d'interface buveur, il ne bois pas. C'est ainsi que commencera la première
guerre universel (A lire, universal war one, très bonne BD sur ce sujet, enfin
presque).
Alors oui, on pourrait dire que c'est préférable de l'empêcher de boire si
l'on ne sait pas si il peut boire (imagine, il se trompe et cela le tue...).
C'est deux façon de voir les choses et je préfère rendre responsable les
développeurs que de rendre responsable le code. Le résultat étant le même à la
fin, soit c'est bon et cela passe, soit cela te pète à la gueule (au runtime
ou à la vérification statique). D'un coté tu t'es embêté à écrire du code
complexe, de l'autre t'as mis en place une procédure pour que cela pète au
runtime chez toi et pas chez le client (des tests par exemple). Comprendra qui
veut (Personnellement je préfère ne pas m'embêter en codant et écrire des
tests, parce que les tests, j'aurais honte de fournir du code au client qui
n'est pas testé... Donc entre écrire des tests et m'embêter en codant, ou juste
écrire des tests (et en plus sans m'embêter à les écrire...), le choix est
vite fait)
Le problème ici c'est que python ne manque pas d'une fonctionnalité de typage,
c'est juste une façon différente de voir les choses.
* Le self comme argument dans les méthodes de classes, c'est vraiment très
très moche comme hack, et les messages d'erreurs sont faussés (quand il
manque des arguments, le nombre d'arguments comprend le self, alors que l'on
ne doit pas le préciser avec la syntaxe classique).
Problème de goût et erreur de compréhension. Personnellement je trouve que le
this implicite en C++ c'est très moche comme hack (mon dieu, il vient d'où ?).
Après pour l'histoire du self, il n'y a pas de message d'erreur faussés, juste
une habitude que tu as pris d'ignorer dans le compte des arguments l'instance
concerné
toto.doit(5)
pour moi c'est une fonction (C.doit) qui prend deux arguments, toto et 5. C
sera dynamiquement déduit du type de toto (en l'occurrence, toto.doit(5) est
juste un raccourci syntaxique pour:
toto.__class__.doit(toto, 5)
avec toto.__class__ = C
Et là ou le système de type est intéressant, c'est que la classe C est finalement
juste un gros namespace de fonction travaillant sur des objets equivalents,
mais rien ne t'empeches de faire:
titi = B() # b n'a RIEN a voir avec C dans l'arbre d'héritage
C.doit(titi, 5)
En C++, on appelle cela les templates... En python on appelle cela le
dynamisme, mais en pratique les deux langages font la même chose...
Personnellement, je n'ai jamais compris pourquoi les autres langage ne
faisaient pas comme cela (pour le self/this). Et même avant que je connaisse
python, je ne comprenais pas. Quand j'ai découvert python, j'ai bondi de joie
au plafond en hurlant "Mon dieu, enfin des gens logiques qui pensent comme
moi"... Donc loin d'un hack immonde, c'est encore une fois un problème de
façon de voir les choses (même si le hack immonde, il faut être fou pour ne
pas se rendre compte qu'il est dans le langage C++ ;)
D'ailleurs, on va pousser un peu. Supposons une classe A et une
classe fille B ayant tout les deux une méthode "blork", Dans B.blork tu veux
appeler le A.blork sur l'instance courante...
En java tu utiliseras "inherited", bon, ok, java n'as pas d'héritage multiple
(en bien ou en mal), donc cela fonctionne très bien (je trouve cela juste
dommage d'introduire un nouveau mot clé dans le langage pour cela...)
En C++, tu utilises l'opérateur de portée de classe:
void B::blork()
{
A::blork();
}
Donc ici de façon implicite, A::blork est appelée avec le contexte. Mais si tu
utilises A::blork() en dehors de la classe B, et bien cela risque de ne pas
fonctionner non ?
En python tu verras simplement A.blork(self) que tu sois DANS l'instance le
code de la classe B ou en dehors (sauf que en dehors tu n'écrira pas de
variable nommée self ;)
Autre exemple. Tu écris une fonction qui travaille sur un objet de classe A,
et qui fait un truc
def mafonction(something):
assert(is_instance(something, A))
#dosomething with something
Note qu'ici je vérifie le type, pour le sport.
Puis après, tu obtient le pouvoir d'intégrer ta fonction au sein de la classe
A. Et bien tu n'as rien à changé, le prototype reste le même (faut renommer
self en something partout pour que cela soit joli, mais sinon c'est la même
chose).
Je ne parle pas de simplicité pour le refactoring ou autre hein (en C++ c'est
presque aussi simple en C++), je parle de cohérence. En C++ ce n'est pas du
tout la même chose, en python c'est toujours une fonction, il n'y à rien de
changé. En c++ il y a des namespaces, des classe, des fonctions, des méthodes
statiques, des méthodes d'instance. En python l'on fait la même chose
simplement avec des namespaces et des méthodes.
* On ne peut pas modifier un caractère d'une chaîne de caractère, obligé de
* faire une copie.
C'est un choix qui semble logique de mon coté. Une chaîne de caractère tient
sa valeur de son contenu, tu changes le contenu, tu changes la chaîne. Mais
sincèrement, on s'en cogne pas un peu ? Je crois que je n'ai jamais changé
un caractère dans une chaîne... A la limite plusieurs, mais cela change
complètement l'algo derrière, et j'avoue être plutôt heureux que python me
l'interdise ;)
Et si vraiment tu n'est pas content, libre à toi d'écrire un type
mutablestring basé sur les listes voir même sur les chaînes. Cela prend 5
minutes. Mais je n'en vois pas l'intérêt.
Les exceptions pour les jeux de caractères, ça me gonfle.
Précise ta remarque ? Les exceptions que j'ai eu en python étaient toutes liés
à une erreur de ma part. Une fois que tu as compris qu'il faut toujours
travailler en unicode (ou str dans python3), sauf pour les entrées sorties ou
tu converties en str (ou bytes dans python3) ou les traitements qui n'ont pas
de valeur de chaîne de caractère, il n'y a plus de problème.
On parlait tout a l'heure de vérification à la compilation, du fait que le
typage apportait un lot de sécurité, bla bla bla... Et bien ici python
t'apporte le fait que si tu fais des bêtises avec ta chaîne de caractère, il
te hurle dessus pour éviter que tu ne vois pas que la sortie est remplie de
petits '?', certes très jolis. Python est ici plus sécurisé que le C++, sans
être embêtant...
De toute façon ici l'on ne peut pas comparer avec C++, la lib standard C++ ne
gère pas l'un code, donc de toute façon tu n'aurais jamais eu ses erreurs en
C++, mais ce n'est pas forcement pour une bonne raison. C++ 0x apportera un
vrai support des chaînes de caractère, donc rassurez vous, cet argument en
faveur de python ne sera plus dans quelques années, à en juger par
l'implémentation du C99 sur les grands compilateurs du marché, au moins 10 ans ;)
L'impression générale d'être limité à une utilisation en haut niveau.
Précise ? Oui tu ne feras jamais un OS en python (et encore, cela pourrait
être marrant), mais quelles sont tes contraintes bas niveau ?
Personnellement je fais de l'OpenGL/Cuda/OpenCL tous les jours avec, et je
trouve que c'est suffisamment bas niveau...
Maintenant oui, j'accepte cet assertion, cependant revenons au débat sur Qt,
personnellement je m'en fout de toucher mes registres à la main, de faire du
(S/M)IMD, de gérer ma gestion de lignes de cache du CPU, de savoir comment mes
pages mémoires sont swapées. ON fait de la GUI là... On est en 2010, combien
de personnes, à part les gens qui font du système ou de l'image ont besoin
d'autant de bas niveau ?
Alors oui, quand j'ai besoin de bas niveau (mon dieu, il y a quoi dans mon
cache L2 !!!) Je fais du C (et du C++ quand vraiment je fais un gros truc et
que j'ai besoin d'une syntaxe objet plus légère que celles possibles en C),
mais quand je fais une gui, avec C++ j'ai "l'impression générale d'être limité
à une utilisation de bas niveau".
Puis l'indentation obligatoire, c'est super pénible. Surtout quand on
* reprends le code d'une autre personne, ou que l'on a juste commenté une
* condition.
C'est personnel. Moi je ne supporte plus les accolades et points virgules et
bien que j'ai plus d'années d'expériences en C/C++ que python, n'oublies
encore pleins de ;, mais je n'oublies jamais d'intenter mon code...
Quand j'enseigne la programmation à la fac ou en école d'ingé Je passe les 3/4
de mes séances C/C++/Pascal à rajouter des {};begin/end... J'ai la chance
d'avoir quelques groupes d'enseignement en Python, et bien je n'ai jamais* eu
de problème avec l'indentation et la syntaxe du langage.
* Une fois un élève qui à changé la configuration de son éditeur de texte pour
l'indentation et qui est passé soudain de 4 espaces à un tab... Un beau
bordel, j'avoue. Mais une fois ce détail connu pour une utilisateur averti,
il suffit d'un peu de rigueur (et d'un éditeur bien configuré) et ce problème
devient un souvenir.
Pour les commentaires de conditions, j'avoue, c'est peu pratique (enfin en C
tu est aussi forcé de supprimé les accolades ouvrantes et fermantes, sauf si
tu acceptes la déclaration d'un nouveau bloc, ce qui, j'avoue, à peu
d'implications, sauf si il reste encore le else après et là t'es eu...
Personnellement, j'ai une macro $EDITOR pour chercher le if le plus proche, et
cycler entre:
if condition:
#TODO if condition:
if True:
#TODO if condition:
if False:
Et elle est adaptée d'une macro pour le C que j'avais avant qui faisait la
même chose, car je n'ai pas trouvé mieux (je suis preneur).
Ce que j'aime bien dans les langages compilés sinon, c'est l'optimisation
automatique du code (en python, on perd la documentation quand on veut
optimiser). Gcc va vraiment plus optimiser, et même en fonction de
l'architecture de la machine.
Avec un langage interprété, effectuer les mêmes optimisations serait possible,
mais ce serait aussi bien trop lent à exécuter.
La suppression de documentation n'optimise pas plus, elle réduit seulement la
taille du fichier. Tu as deux flag en python, -O et -OO pour optimiser. -O ne
fait pas grand chose (principalement, il supprime les assert et la variable
__debug__) et -OO supprime la documentation. Si tu veux optimiser, python
n'est vraiment pas la bonne solution.
Et là je vais revenir sur le débat de la mémoire. ON s'en COGNE des
optimisations. On fait de la GUI ici hein, de la GUI ! Le truc pour lequel le
toolkit bouffe 99.9% de ton temps CPU pour dessiner des fenêtres à l'écran. Le
truc ou l'élément limitant en terme de performances et de réactivité c'est
l'utilisateur, la carte graphique, le serveur d'affichage et le toolkit.
Et puis pour la plupart on fait de la GUI qui affiche les
résultats qui sortent d'une BDD, le truc qui va prendre un temps de fou pour
revenir, parce que une BDD c'est des milliers de cycle CPU pour ramener une
petite donnée, c'est comme cela. Et on fait de la gui qui va lire et charger
des fichiers Image, qui va prendre quelques milliers de cycle CPU pour
décompresser le jpeg. Tout cela est déjà écrit et est lent, et sera toujours
plus lent que 10 appels de fonction dans python pour connecter ton évènement
clique de bouton sur la fonction de décompression de JPEG.
Alors oui, python prendra quelques cycles CPU de plus que C++ dans la boucle
principale, cycles qui sont négligeables à cote de ceux nécessaire au toolkit
pour afficher ta fenêtre. Alors OUI, je ne ferais jamais un toolkit en python,
ou une librairie de décompression JPEG, (et encore... faut voir ;)), mais
quand l'on parle d'utilisation de librairies qui existent déjà.
Et puis l'on parle d'optimisation et de C++, j'en rigole tous les jours. Du
fait des mécanismes d'héritage virtuel, les appels de fonction en C++ sont
lents et ne peuvent être inlinés (on parlait d'optimisation par le compilateur
?).
Alors OUI, python n'est pas parfait, Oui il a des défauts, le plus gros étant
qu'il ne code pas à ma place, ainsi je suis obligé d'aller au boulot et de
coder (parce que sinon je coderais à la maison pour le plaisir, ou je ferais
de l'escalade, ou je jouerais à Ryzom). Je vous demande juste une chose, ne
pas critiquer python sur des goûts personnels (l'indentation, le self, ...) ou
sur des fausses idées (python est lent. Oui, mais lent à quel point ?), mais
faites le sur des vrais points techniques, je peux en citer pleins :
- Python sucks en multithreadé à cause du GIL (cela se discute, mais globalement c'est vrai
pour les calculs cpu-bound)
- Déployer une application écrite en python c'est plus chiant qu'un bon gros
binaire Qt linké en statique. Sous windows un bon gros binaire Qt linké en
statique marche tout seul, alors que la même application en pytoolkit doit
contenir plusieurs fichiers, et il faut installer python, pytoolkit, toolkit
et dépendances du toolkit + pydependances du toolkit (ceux qui font du pygtk
doivent sourire en ce moment...). Bon, ca j'avoue que c'est super lourd...
- Python n'est pas un langage normé ISO (bon, celle-la me fait toujours rire,
mais peu avoir de la valeur), ceci impliquant aussi le prochain point,
- Python à au moins 6 implémentations différentes (Cython, UnladenSwallow,
Jython, IronPython, Pypi, Stackless), ayant toutes des différences de
comportement et de librairies, donc python n'est pas portable entre ses
différentes implémentations (bon, le C/C++ c'est pareil, hormis le C(++)
ansi sans utiliser la STL, c'est pas portable d'un compilo à un autre. C'est
encore plus vrai pour les libraries qui ne fonctionnent pas de la même
manière d'un système à un autre (Apple, quand tu packages !!!) et c'est la
plaie des systèmes de build (Mais ou est donc pkg-config sous Windows ?)
- Python sucks pour d'interfacer avec du C++ (alors qu'avec du C c'est très
simple) et cela parce que C++ sucks sur le name mangling et autres bêtises.
(Les symboles exportées par le compilateur peuvent être différents d'un
compilateur à l'autre. J'avoue que je ne sais pas exactement qu'elle est le
statut des normes à ce sujet)
Bon, je vais me coucher, vous pouvez moinser... A non, faut que je relise
l'orthographe avant... (et merde...)