Toutes les langues de programmation ont leurs défauts de conception simplement parce que pas une seule langue peut être parfaite, comme avec la plupart (toutes?) Autres choses. Cela de côté, quelle défaillance de design dans un langage de programmation vous a le plus agacé par votre histoire en tant que programmeur?
Notez que si une langue est "mauvaise" juste parce qu'elle n'est pas conçue pour une chose spécifique n'est pas une faille de conception, mais a fonctionnalité de la conception, alors ne répertoriez pas ces ennuis. Si une langue est malitée pour ce qu'elle est conçue pour, c'est bien sûr une faille dans la conception. La mise en œuvre des choses spécifiques et sous les choses à capot ne comptent pas non plus.
Une de mes grosses ennuis est la voie switch
cas dans les langues dérivées de C défaut de tomber au cas suivant si vous oubliez d'utiliser break
. Je comprends que cela est utile dans un code de niveau très bas (par exemple, Duff's Device ), mais il est généralement inapproprié pour le code de niveau d'application et constitue une source courante d'erreurs de codage.
Je me souviens vers 1995 quand je lisais sur les détails de Java pour la première fois, quand je suis arrivé à la partie de la déclaration switch
déclaration que j'étais très déçue qu'ils avaient retenu le comportement d'automne par défaut. Cela fait simplement switch
dans un _ glorifié goto
avec un autre nom.
Je n'ai jamais vraiment aimé l'utilisation de =
pour la mission et ==
Pour des tests d'égalité dans les langues dérivées de C. Le potentiel de confusion et d'erreurs est trop élevé. Et ne me fais même pas commencer sur ===
en JavaScript.
Mieux aurait été :=
pour la mission et =
Pour les tests d'égalité. La sémantique aurait pu être exactement la même possible qu'aujourd'hui, où une affectation est une expression qui produit également une valeur.
Le choix de +
dans JavaScript pour les deux Ajout et Cordon Concaténation était une terrible erreur. Étant donné que les valeurs sont non typées, cela conduit aux règles byzantines qui déterminent si +
ajoutera ou concaténera, en fonction du contenu exact de chaque opérande.
Il aurait été facile au début d'introduire un opérateur complètement nouveau tel que $
pour la concaténation de la chaîne.
Je trouve la valeur par défaut JavaScript à Global à un problème majeur et souvent source de bogues si vous n'utilisez pas JSLint ou similaire.
Le préprocesseur de C et C++ est un kilomètre massif, crée des abstractions qui fuient comme des tamis, encourage le code spaghetti via les nids de rat de #ifdef
déclarations et nécessite horriblement illisible ALL_CAPS
noms de travailler autour de ses limites. La racine de ces problèmes est qu'elle fonctionne au niveau textuel plutôt que le niveau syntaxique ou sémantique. Il aurait dû être remplacé par des fonctionnalités de langue réelle pour ses divers cas d'utilisation. Voici quelques exemples, bien que certes certains d'entre eux soient résolus en C++, C99 ou non officiel mais de facto Extensions standard:
#include
aurait dû être remplacé par un système de module réel.
Les fonctions en ligne et les modèles/génériques pourraient remplacer la plupart des cas d'utilisation d'appel de fonction.
Une sorte de fonctionnalité constante de temps manifeste/compilée pourrait être utilisée pour déclarer de telles constantes. Extensions d'Enum Très bien ici.
Les macros de niveau d'arborescence de la syntaxe réelles pourraient résoudre beaucoup de cas d'utilisation divers.
Mélangements à chaîne Pourriez être utilisé pour le cas d'utilisation d'injection de code.
static if
ou version
Les déclarations peuvent être utilisées pour la compilation conditionnelle.
On pourrait énumérer des centaines d'erreurs dans des centaines de langues, mais l'OMI n'est pas un exercice utile d'une perspective de conception linguistique.
Pourquoi?
Parce que quelque chose qui serait une erreur dans une seule langue ne serait pas une erreur dans une autre langue. Par exemple:
Il -sont leçons à apprendre, mais les leçons sont rarement claires, et de les comprendre que vous devez comprendre les compromis techniques ... et le contexte historique. (Par exemple, l'encombrant Java La mise en œuvre des génériques est une conséquence d'une exigence commerciale primordiale pour maintenir la compatibilité à l'envers.)
IMO, si vous êtes sérieux de concevoir une nouvelle langue, vous devez réellement tiliser une large gamme de langues existantes (et étudier les langues historiques) ... et faites votre propre esprit quelles sont les erreurs. Et vous devez garder à l'esprit que chacune de ces langues a été conçue dans un contexte historique particulier, pour combler un besoin particulier.
S'il y a des leçons générales à apprendre, ils sont au niveau "Meta":
C et C++: Tous ces types entiers qui ne sont pas n'importe quoi.
Surtout char
. Est-ce que c'est du texte ou est-ce un entier minuscule? Si c'est un texte, est-ce un caractère "ANSI" ou une unité de code UTF-8? Si c'est un entier, est-il signé ou non signé?
int
était destiné à être l'entier "natif", mais sur des systèmes 64 bits, ce n'est pas le cas.
long
peut être supérieur ou ne sera peut-être pas supérieur à int
. Il peut être ou non la taille d'un pointeur. C'est une décision arbitraire de la part des écrivains du compilateur s'il est 32 bits ou 64 bits.
Définitivement une langue des années 1970. Avant unicode. Avant les ordinateurs 64 bits.
null
.
Son inventeur, Tony Hoare, l'appelle la "erreur de milliards de dollars" .
Il a été introduit à Algol dans les années 60 et existe dans la plupart des langages de programmation couramment utilisés aujourd'hui.
La meilleure alternative, utilisée dans des langues comme Ocaml et Haskell, est le peut-être . L'idée générale est que les références d'objet ne peuvent être nuls/vides/inexistantes à moins d'une indication explicite qu'elles peuvent l'être.
(Bien que Tony soit génial dans sa modestie, je pense que presque tout le monde aurait commis la même erreur, et il vient d'être d'abord.)
J'ai le sentiment que les personnes qui ont conçu PHP n'ont pas utilisé de clavier normal, ils n'utilisent même pas de clavier Colemak, car ils auraient dû réaliser ce qu'ils faisaient.
Who::in::their::right::mind::would::do::this()
? L'opérateur ::
Nécessite de contenir le décalage, puis deux appuie sur la touche. Quel gaspillage d'énergie.
Bien que-> this-> est-> pas-> beaucoup-> mieux. Cela nécessite également trois presses clés avec le décalage entre les deux symboles.
$last = $we.$have.$the.$dumb.'$'.$character
. Le signe du dollar est utilisé une quantité énorme de fois et nécessite le prix étiré au sommet du clavier, plus une touche de décalage.
Pourquoi ne pourraient-ils pas concevoir PHP _ pour utiliser des clés qui sont beaucoup plus rapides à taper? Pourquoi ne pouvait pas we.do.this()
ou avoir varié de commencer par une touche qui nécessite une seule touches - ou non du tout (JavaScript) et simplement pré-définir tous les Vars (comme je dois quand même faire pour e_strict quand même)!
Je ne suis pas une typiste lente - mais c'est juste un choix de conception boiteux.
L'utilisation de bureau inspiré formulaires dans ASP.NET.
Il ressentait toujours un fudge et a eu du chemin ou de la façon dont la bande fonctionne réellement. Hergnément ASP.NET-MVC ne souffre pas de la même manière, bien que le crédit Ruby etc. pour cette inspiration.
Pour moi, c'est [~ # ~ ~] PHP [~ # ~] manque absolu de nommer et d'argument commandant des conventions dans sa bibliothèque standard.
Si [~ # ~ # ~] Jass [~ # ~] nécessité de nullifier des références après que l'objet référencé a été publié/supprimé (ou la référence fuit et plusieurs Les octets de mémoire seraient perdus) est plus grave, mais puisque Jass est une langue unique, ce n'est pas si critique.
La plus grande faille de conception que je fais face est que python n'a pas été conçu comme python 3.x pour commencer.
Decay de tablea en C et par conséquent C++.
Types primitifs en Java.
Ils brisent le principe que tout est un descendant de Java.lang.Object
, qui, d'un point de vue théorique conduisant à une complexité supplémentaire de la spécification linguistique, et d'une perspective pratique, ils utilisent des collections extrêmement fastidieuses.
L'autoboxage a permis d'atténuer les inconvénients pratiques, mais au coût de la spécification encore plus compliqué et d'introduire une grosse peau de banane gras: vous pouvez désormais obtenir une exception de pointeur NULL de ce qui ressemble à une simple opération arithmétique.
Je sais Perl mieux, alors je vais la choisir.
Perl a essayé de nombreuses idées. Certains étaient bons. Certains étaient mauvais. Certains étaient originaux et non largement copiés pour une bonne raison.
L'une est l'idée de contexte - Chaque appel de fonction a lieu dans la liste ou dans le contexte scalaire, et peut faire des choses totalement différentes dans chaque contexte. Comme je l'ai signalé à - http://use.perl.org/~bticully/journal/36756 Cela complique chaque API et conduit fréquemment à des problèmes de conception subtils au code PERL.
La prochaine est l'idée de lier la syntaxe et les types de données si complètement. Cela conduit à l'invention de la cravate pour permettre aux objets de masquerade comme d'autres types de données. (Vous pouvez également obtenir le même effet en utilisant la surcharge, mais la cravate est l'approche la plus courante de Perl.)
Une autre erreur commune, faite par de nombreuses langues, est de commencer par offrir un décor dynamique plutôt que lexical. Il est difficile de revenir sur cette décision de conception plus tard et conduit à des verrues durables. La description classique de ces verrues dans Perl est http://perl.plover.com/faqs/namespaces.html . Notez que cela a été écrit avant Perl ajouté our
variables et static
variables.
Les gens sont légitimement en désaccord sur la typographie statique par rapport à la dynamique. Personnellement, j'aime la dactylographie dynamique. Cependant, il est important d'avoir suffisamment de structure pour laisser les fautes de frappe. Perl 5 fait un bon travail avec strict. Mais Perl 1-4 a eu ce faux. Plusieurs autres langues ont des dames de peluche qui font la même chose que strict. Tant que vous êtes bon pour appliquer la vérification des peluches, cela est acceptable.
Si vous recherchez des idées plus mauvaises (beaucoup d'entre eux), apprenez PHP et étudiez son histoire. Mon erreur passée préférée (il y a longtemps fixé parce qu'il conduit à de nombreux trous de sécurité) permettant à quiconque de définir une variable en passant dans des paramètres de formulaire. Mais c'est loin de la seule erreur.
Je vais retourner à l'insensibilité de la Fortran et de l'espacement des espaces.
Il a envahi la spécification. La carte END
devait être définie comme une carte avec un "E", un "N", et un "D" dans cet ordre dans les colonnes 7-72, et aucune autre non blanche, plutôt qu'une carte avec "Fin" dans les colonnes appropriées et rien d'autre.
Il a conduit à une confusion syntaxique facile. DO 100 I = 1, 10
était une déclaration de contrôle de boucle, tandis que DO 100 I = 1. 10
était une déclaration qui a attribué la valeur 1.1 à une variable appelée DO10I
. (Le fait que les variables puissent être créées sans déclaration, leur type en fonction de leur première lettre, a contribué à cela.) Contrairement à d'autres langues, il n'y avait aucun moyen d'utiliser des espaces pour séparer les jetons pour permettre le désambimuation.
Il a également permis aux autres d'écrire un code vraiment déroutant. Il y a des raisons pour lesquelles cette caractéristique de Fortran n'a jamais été de nouveau dupliqué.
JavasCrips Ambiguït pour les blocs de code et les catégories d'objets.
{a:b}
pourrait être un bloc de code, où a
est une étiquette et b
est une expression; ou cela pourrait définir un objet, avec un attribut a
qui a la valeur b
L'un des problèmes les plus importants avec la base était l'absence de méthode bien définie pour étendre la langue au-delà de ses premiers environnements, ce qui entraîne un groupe de mises en œuvre totalement incompatibles (et une tentative de post-facto presque non négligeable à toute normalisation).
Presque n'importe quelle langue sera pliée dans un usage général d'un programmeur fou. Il est préférable de planifier cet usage général au début au cas où une idée folle s'envole.
Je crois aux DSLS (langages spécifiques au domaine) et une chose que j'apprécie dans une langue, c'est si cela me permet de définir une DSL sur le dessus.
Dans Lisp, il y a des macros - la plupart des gens considèrent cela une bonne chose, de même que moi.
En C et C++, il y a des macros - les gens se plaignent d'eux, mais j'ai pu les utiliser pour définir les DSL.
En Java, ils ont été laissés de côté (et donc en C #), et le manque d'entre eux a été déclaré être une vertu. Bien sûr, il vous permet d'avoir IntelliSense, mais pour moi, c'est juste une oeuvre. Pour faire mon DSL, je dois nous développer. C'est une douleur, et cela me fait ressembler à un mauvais programmeur, même si cela me permet de faire beaucoup plus avec des tonnes moins de code.
déclarations, dans chaque langue qui les a. Ils ne font rien que vous ne pouvez pas faire avec les expressions et vous empêcher de faire beaucoup de choses. L'existence d'un ?:
L'opérateur ternaire n'est qu'un exemple de devoir essayer de les contourner. En JavaScript, ils sont particulièrement ennuyeux:
// With statements:
node.listen(function(arg) {
var result;
if (arg) {
result = 'yes';
} else {
result = 'no';
}
return result;
})
// Without:
node.listen(function(arg) if (arg) 'yes' else 'no')
Pour moi, c'est le problème de conception qui plaie toutes les langues dérivées de C; nommément, le " pendling sinon ." Ce problème grammatical aurait dû être résolu en C++, mais il a été porté dans Java et C #.
Je pense que toutes les réponses jusqu'à présent pointent sur un seul échec de nombreuses langues ordinaires:
Il n'y a aucun moyen de changer la langue principale sans affecter la compatibilité en arrière.
Si cela est résolu, alors tous ces tests peuvent être résolus.
ÉDITER.
cela peut être résolu dans les bibliothèques en ayant des espaces de noms différents, et vous pourriez concevoir quelque chose de similaire pour la plupart du cœur d'une langue, bien que cela puisse alors signifier que vous devez prendre en charge plusieurs compilateurs/interprètes.
En fin de compte, je ne pense pas savoir comment le résoudre de manière totalement satisfaisante, mais cela ne signifie pas qu'une solution n'existe pas, ni plus que plus ne peut pas être fait
Entier silencieux de Java débordement arithmétique
Je me sens comme si je m'ouvrant pour me faire enflammer, mais je déteste vraiment la capacité de transmettre des types de données anciens simples par référence en C++. Je n'aime que légèrement être capable de passer des types complexes par référence. Si je regarde une fonction:
void foo()
{
int a = 8;
bar(a);
}
Du point d'appel, il n'ya aucun moyen de dire que bar
, qui peut être défini dans un fichier complètement différent, est la suivante:
void bar(int& a)
{
a++;
}
Certains pourraient affirmer que faire quelque chose comme ceci peut simplement être une mauvaise conception de logiciels et ne pas blâmer la langue, mais je n'aime pas que la langue vous permet de le faire en premier lieu. Utilisation d'un pointeur et d'appel
bar(&a);
est beaucoup plus lisible.
Le pire péché d'un langage de programmation n'est pas bien défini. Un cas que je me souviens est C++, qui, dans ses origines:
Comme je me souviens, il a fallu environ une décennie Pour que C++ soit défini assez bien pour le rendre aussi fiatant de manière professionnelle que C. C'est quelque chose qui ne devrait plus jamais se reproduire.
Quelque chose d'autre que je considère comme un péché (si cela devait aller dans une réponse différente?) Avoir plus d'un "meilleur" moyen de faire une tâche commune. C'est le cas de (encore) C++, Perl et Ruby.
Quand j'ai appris Cobol, la déclaration Alter était encore une partie de la norme. En un mot, cette déclaration vous permettrait de modifier les appels de procédure pendant l'exécution.
Le danger était que vous puissiez mettre cette déclaration dans une partie de la section obscure du code qui a été rarement accessible et cela avait le potentiel de changer complètement le flux du reste de votre programme. Avec de multiples déclarations alters, vous pouvez faire presque impossible de savoir ce que votre programme faisait à un moment donné.
Mon instructeur de l'université, très énergiquement, a déclaré que s'il avait déjà vu cette déclaration dans l'un de nos programmes, il nous enlèverait automatiquement.
Les classes en C++ sont une sorte de modèle de conception forcé dans la langue.
Il n'y a pratiquement aucune différence à l'heure d'exécution entre une structure et une classe, et elle est tellement déroutante de comprendre quel est le véritable avantage de la programmation de la "cachette d'information" que je veux y mettre là-bas.
Je vais être évité pour cela, mais de toute façon, les compilateurs C++ sont si difficiles à écrire que cette langue ressemble à un monstre.
Bien que chaque langue ait fait des fautes, aucune nuisance n'est une fois que vous savez à leur sujet. Sauf pour cette paire:
Syntaxe complexe couplée à une API Wordy
Ceci est particulièrement vrai d'une langue comme objectif-c. Non seulement la syntaxe est la syntaxe écrasante, mais l'API utilise des noms de fonction comme:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Je suis tout pour être explicite et non ambiguë, mais c'est ridicule. Chaque fois que je m'assieds avec Xcode, je me sens comme un N00b, et c'est vraiment frustrant.
L'aplatissement des listes de Perl ... Inversement, c'est aussi l'une de ses meilleures caractéristiques.
Dans Old Ultima Online/Sphere Server Scripting ... Il y avait sans division du tout ou des points décimaux, bien que le jeu lui-même les utilisait évidemment. Vous pourrait faire une fonction de fracture quelque peu brute mais à peine.
Il est difficile de dire à quel point une épave de train qu'une faille a rendu la langue entière extrêmement fastidieuse.
En non-Java comme des langues. Le concept de "goto" ou de sauter. Être capable de sauter autour du code de manière non linéaire est peut-être la caractéristique la plus mauvaise-logique de toute langue écrite.
Cela a été le concept le plus utilisé et non pertinent. Une fois que je vois l'un d'entre eux dans une fonction de 300 lignes, je sais que je suis dans une leçon de cuisson pour les spaghettis. L'exception est la manipulation des erreurs. C'est la seule utilisation acceptable du concept de saut
Il brise de bonnes pratiques de programmation modernes. Les goto ne sont acceptables que dans le but de piéger des erreurs. Pas une façon paresseuse de mettre fin à des boucles ou de sauter du code.
Le code d'écriture est une forme d'art qui devrait être orientée pour la lisibilité. L'exécution linéaire est parmi les nombreux aspects de la lisibilité. Un point d'entrée, une sortie pour n'importe quelle fonction, et il doit couler dans la page, aucun saut ou goto.
Non seulement cela rend le code plus lisible, il est également que très naturelle vous aide à écrire un code de qualité supérieure. Un piratage engage un autre et un autre. Vous constaterez généralement qu'une fois que Goto ait mal à jour, vous obtenez également plusieurs déclarations de sortie sur les fonctions. Les conditions de traçage et la logique pour les tests deviennent infiniment plus difficiles et réduisent immédiatement la robustesse de tout code que vous pouvez produire.
Je souhaite que les goto soient banalisés pour toujours, ils ont été utilisés dans le codage de montage il y a des années, et c'est là qu'ils devraient rester.
Array de grammage, liste et dictionnaire dans une abomination appelée "tableaux associatifs" de php ".
En C, et hérité par C++, Java et C #:
Vous ne pouvez pas analyser la langue sans construire une table de symboles. Parce que le code comme celui-ci:
Foo Bar();
pourrait être déclarer une variable Bar
de type Foo
et appeler le constructeur par défaut ou peut-être déclarer une fonction Bar
qui renvoie un Foo
et ne prend aucun argument . (En C++, de toute façon. Les autres ont des défauts similaires.)
Cela signifie que vous ne pouvez pas analyser ces langues sans construire une table de symboles, faire des outils d'analyse beaucoup plus difficiles à écrire.
(JavaScript et allez réussir à éviter ce problème.)
La macro macro m4 manque de construction de boucle. Au lieu de cela, la documentation vous recommande de créer votre propre utilisation de la récursivité. Cela m'a empêché de déranger avec la langue, à peu près pour toujours.
Probablement pas la plus grande faille de conception, mais une faille est néanmoins à mon avis ...
Le mot clé final dans le contexte des variables est Java.
Je souhaite qu'il y ait un non finale / mutable / Rassignable Mot-clé d'indiquer que la référence à une variable peut être modifiée.
Les bonnes pratiques suggèrent que vous devriez utiliser le mot-clé final libéralement dans tous les cas, en particulier lorsque vous écrivez des applications multi-threadées.
Je suis ce conseil et utilisez le dernier mot clé quand je peux. Il est très rare que j'ai besoin d'une variable pour être non finale. Cela rend mon code source beaucoup plus encombré et me force à taper plus que ce que je devrais vraiment avoir à.
La plus grande faille observée souvent dans de nombreuses langues de programmation est l'incapacité de "bootstrap" - souvent ce n'est pas possible ou pratique de mettre en œuvre la langue et ses bibliothèques en utilisant uniquement cette langue elle-même.
Lorsque tel est le cas, les concepteurs de langue (et les impléments) sautent la partie difficile de faire de la langue utile pour des tâches très intéressantes et difficiles.
C++ Fabrication de types de valeur d'objets à la place des types de référence, et ruinant ainsi la possibilité de mettre en œuvre une programmation orientée objet de manière saine. (L'héritage et le polymorphisme ne se mélangent tout simplement pas avec des structures de données de la valeur transparente statiquement allouées, de taille fixe.)
Java, PHP, C #, Delphi, Vala: Mélanger des "pointeurs vers des objets" par rapport à "des objets unis", ce qui est généralement appelé "références". En C++, et objet Pascal, vous pouvez créer des objets sous forme de variables statiques et d'objets sous forme de variables dynamiques, à l'aide de la syntaxe du pointeur.
Exemple (C++):
x = new XClass();
x->y = "something";
if (x == null) {
x->doSomething();
}
Exemple (Java/C #):
x = new XClass();
x.y = "something";
if (x == null) {
x.doSomething();
}
J'ai deux choses que je n'aime pas dans C++,
La conversion implicite à BOOL (ceci est aggravée par le fait que vous pouvez implémenter des opérateurs de conversion pour des types tels que operator int() const {...}
)
Paramètres par défaut, oui, il aide la compatibilité en arrière des interfaces lors de l'ajout de nouvelles choses, mais de la surcharge de la fois - alors pourquoi cela?
Maintenant, combinez les deux ensemble, vous avez une recette pour la catastrophe.
Comportement Clloop imbé de Coldfusion.
Manque de manutention pour les variables d'entrée dans SQL. Même lorsqu'un fournisseur de base de données a ajouté sur une fonctionnalité pour supporter cela (je vous regarde, SQL Server), il peut être mal conçu et gênant à utiliser.
L'omission de JavaScript de nombreuses fonctions de mise en forme et de manipulation de la date que presque toutes les autres langues (y compris la plupart des implémentations SQL) ont été une source de frustration pour moi récemment.
Paramaters facultatifs dans VB. Lorsque l'ajout de fonctionnalités au code est trop facile pour le faire sous forme de paramètre facultatif, puis un autre, puis un autre, vous vous retrouvez également avec tous ces paramètres qui ne sont utilisés que dans les nouveaux cas nouvellement ajoutés après l'écriture du code initial et probablement ne sont pas appelés du tout par le code plus âgé.
Heureusement, cela m'a été résolu en passant à C # et en utilisant des surcharges.
La décision de mettre en œuvre l'opérateur goto
in PHP 5.3.
[.____] quelle raison pourrait-il exister peut-être d'encourager de mauvaises pratiques de programmation qui ont été-elles non appliquées dans les versions précédentes?
Delphi/Pascal Langue Ne permettez pas de chaînes multilignes sans utiliser de concaténation.
Robocom , dont la langue de montage manque pour les opérations bitwises .
Bien que cela compte à peine comme une langue productive avec une valeur réelle autre que l'apprentissage et le divertissement, Robocom est un jeu dans lequel vous programmez des robots virtuels pour participer à une bataille de code. Les programmeurs doivent utiliser la plupart des cycles d'horloge pour faire leur déménagement avant leur adversaire.
Si une langue est malitée pour ce qu'elle est conçue pour, c'est bien sûr une faille dans la conception.
J'ai trouvé cela tout à fait Irritant pour une langue pour manque d'opérations bitwises, en particulier lorsque l'objectif du jeu est l'élimination par optimisation. Que dans mes livres, est une véritable défaut de conception, car de nombreuses optimisations peuvent être effectuées en utilisant des opérations biteux.
J'aimerais avoir contribué quelque chose de légèrement plus utile. :)