Lundi 01 février 2016 à 00:00
Cette discussion est en relation avec le billet suivant :
Syssonj'ai encore du tomber sur "l'exception" mal designée dans le language.Je ne trouve pas ça du tout mal désigné : si j'ai besoin du bas niveau, j'utilise une lib bas niveau, si j'ai besoin de haut niveau, j'utilise une lib de haut niveau. Au moins, j'ai le choix, et le passage de l'un à l'autre (pour l'échange des données) est simple dans le cas présent.
Sysson Haut niveau vs bas niveau vraiment la question ne devrait pas se poser.Au contraire, et c'est un des points forts de la librairie Python, c'est d'avoir justement la possibilité d'utiliser l'outil adapté à ce que tu dois faire, avec la verbosité et le niveau de détails que tu veux. Tu as la richesse de la librairie standard, comme en Java (même davantage), la possibilité de travailler à bas niveau, sans avoir l'encombrement explicite par "couches" de java.
SyssonT'as deux trucs core qui partagent des fonctions de même nom et qui ne fournissent pas la même interface pour travailler avec.C'est pour ça qu'on les met dans des modules séparés.
SyssonLe truc qui me dérange vraiment avec Python c'est le travail inutilement désagréable de maintenir les applis Python.Je n'ai jamais eu de souci. Tu peux détailler ?
SyssonPython n'a tellement pas de problèmes de conception que ses versions ne sont pas backward compatibleTu vas devoir expliciter un peu. Si tu parles de Python 2 et Python 3, ce sont deux branches parallèles (Python 3 existe depuis un peu moins de 10 ans maintenant, et Python 2 sera encore maintenu jusqu'en 2020).
Sysson, et t'es obligé d'avoir des saleté de venv pour survivre avec les dépendances.Et tu fais comment dans les autres langages ? Peux-tu détailler ?
Sysson C'est chiant à maintenir, étant adminsys je veux m'assurer que mes machines soient à jour et l'ajout d'un venv pour une appli c'est un truc en plus à monitorer et à updater.Tu n'as aucune obligation d'utiliser un environnement virtuel par application. L'environnement virtuel te permet de faire cohabiter simplement des applications dont les dépendances sont en conflits. Je n'ai pas connaissance d'approches plus efficaces pour ce problème dans d'autres langages (ni de langages où ce problème ne se pose pas).
SyssonLa seule façon de gagner est de ne pas jouer!Tu peux expliquer en quoi c'est la seule façon ?
Guybrush dont la sémantique du core est cohérente (ce qui est loin d'être le cas de Java, C#, VB, php, .Tu peux élaborer stp ? Je comprends pas la remarque (pour C# en tout cas, les autres je ne connais pas assez)
def f(x = 1):
return x
Si tu initialises une liste au lieu d'un entier : def f(x = []):
x.append(1)
return x
Tu te retrouves avec quelque chose de bizarre :>>> f()
[1]
>>> f()
[1, 1]
Ici, par exemple, c'est parce que la liste []
est évaluée, et donc l'objet est partagé entre chaque appel où tu ne passes pas explicitement un paramètre. Ce comportement, bien que potentiellement piégeant (cela dit, c'est bien un des seuls en Python) est tout à fait normal (et même parfois souhaitable, sauf quand on débute ) et s'explique par le fait que []
est une expression à part entière, comme si tu avais fait un appel à une autre fonction :def g():
print('Coucou')
def f(x = g()):
print('Bye')
Si tu importes ce morceau de code, dès l'import tu auras "Coucou" qui va s'afficher car g()
est évalué. C'est cohérent, mais ça peut surprendre.'' == '0' // false
0 == '' // true
0 == '0' // true
false == 'false' // false
false == '0' // true
false == undefined // false
false == null // false
null == undefined // true
" \t\r\n" == 0 // true
En Java, tu as typiquement toutes les astuces liées à l'autoBoxing/autoUnboxing qui rendent potentiellement les choses délicates à expliquer (même si ça reste toujours parfaitement explicable, je ne dis pas le contraire : le langage est déterministe, hein ^^). Si tu lis "Sun Certified Programmer for Java 6 Study Guide" (un livre "officiel" pour passer la certification Sun), tu te rends vite compte du nombres de cas particuliers qu'il faut mémoriser pour utiliser Java (de mémoire, j'ai en tête les cas spécifiques des modificateurs de visibilité, et certaines astuces quand à l'utilisation du polymorphisme pour déterminer la méthode à appeler dans une hiérarchie d'héritage). object f1 = new Fraction { Numerator = 1; Denominator = 2};
object f2 = new Fraction { Numerator = 1; Denominator = 2};
Si tu fais f1 == f2
, ça te retourne un joli false, parce que l'opération ==
est appelée sur object
, et non sur Fraction
. Ok, un tel code est plutôt "rare" dans le sens où t'as explicitement écrit object f1
et object f2
, mais parfois c'est plus subtil, et tu manipules deux-trois instances d'une hiérarchie à deux niveaux seulement, et tu as déjà ces soucis. GuybrushEn C#, les types nullables sont parfois assez capricieux, où on ne comprend pas bien pourquoi ça compile (et ça finit par crasher au runtime). Genre l'addition de deux éléments nullables, dont l'un est null, alors que l'addition n'est pas autorisée sur un null (si ma mémoire est bonne).Si, c'est autorisé
void Main()
{
int? a = null;
int? b = 42;
var c = a + b;
c.Dump();
(42 + null).Dump();
}
Ça compile, et ça renvoie null dans les 2 cas.GuybrushDans le même ordre d'idées, les propriétés "readonly" qui te donnent l'impression (comme en Java) que rien de méchant ne peut arriver, mais ça ne concerne que la référence de l'objet (et donc il est nécessaire de savoir quels sont les objets mutables et ceux qui ne le sont pas). Au final, cette sécurité n'est qu'une apparente sécurité, et on tombe vite dans les border cases où ça te saute à la tête au runtime.Là je suis d'accord, mais ça va être "corrigé" dans C#7.0, qui va introduire le mot clé immutable (je ne sais plus où, mais je l'ai lu la semaine passée...)
GuybrushUn truc qui m'avait posé souci quand j'avais fait du C# (pour Windows Mobile, ça date !), c'était sa manière bizarre de définir quelles opérations étaient appelées sur quels objets. Je reprends un exemple googlé :Mais là, c'est explicite, tu as volontairement casté ton objet en `object`. Je ne vois pas comment ça pourrait être gênant, tu es supposé connaître le type de ton objet en tout temps (et si tu as un doute, tu peux tjs le caster)
object f1 = new Fraction { Numerator = 1; Denominator = 2};object f2 = new Fraction { Numerator = 1; Denominator = 2};
Si tu fais f1 == f2, ça te retourne un joli false, parce que l'opération == est appelée sur object, et non sur Fraction. Ok, un tel code est plutôt "rare" dans le sens où t'as explicitement écrit object f1 et object f2, mais parfois c'est plus subtil, et tu manipules deux-trois instances d'une hiérarchie à deux niveaux seulement, et tu as déjà ces soucis.
MerleMais là, c'est explicite, tu as volontairement casté ton objet en `object`.Si c'est un struct, il va te faire un .Equals sur les valeurs, si c'est un objet, il va faire un .Equals sur la référence de l'objet (si tu n'as pas fait un override Equals explicite).
MerleMais là, c'est explicite, tu as volontairement casté ton objet en `object`. Je ne vois pas comment ça pourrait être gênant, tu es supposé connaître le type de ton objet en tout temps (et si tu as un doute, tu peux tjs le caster)Je ne l'ai pas casté, j'ai juste stocker la référence de mes
Fraction
dans un Object
. Je m'attendrais à ce que ce soit la méthode de ma fraction qui soit appelée. Cela me permettrait de stocker des sous-types d'une classe dans des références de cette classe, sans avoir à me soucier de ce que je mets dedans, mais en ayant toujours accès à la bonne implémentation spécialisée.Guybrushe ne l'ai pas casté, j'ai juste stocker la référence de mes Fraction dans un Object. Je m'attendrais à ce que ce soit la méthode de ma fraction qui soit appelée. Cela me permettrait de stocker des sous-types d'une classe dans des références de cette classe, sans avoir à me soucier de ce que je mets dedans, mais en ayant toujours accès à la bonne implémentation spécialisée.Casté n'est effectivement pas le bon terme, c'est un-boxé ? Ce que je voulais dire, c'est que vu que ton objet est commu comme étant un 'object' il n'a accès qu'aux méthodes définies dans `object`, comme avec les interfaces:
void Main()
{
A a = new A();
a.Test();
a.Test2();
IA a2 = new A();
a2.Test();
a2.Test2(); // Erreur à la compilation ici
}
public interface IA
{
void Test();
}
public class A : IA
{
public void Test() { Console.WriteLine("test"); }
public void Test2() { Console.WriteLine("test2"); }
}
En fait, (et je ne suis pas du tout un bon théoricien), je ne vois pas ce qui est gênant là dedans, c'est typiquement le comportement auquel je m'attends en faisant ça... (mais je suis biaisé, ça fait 10 ans que je fais du .Net quasi exclusivement...)
Ce message a été modifié 1 fois.
Dernière modification : 8 février 2016
à 17:28 par
Merle.
1996-2024 — Lexpage v4 — GPLv3 (sources)
page générée le 23 décembre 2024 à 19:43:59