Todos los lenguajes de programación tienen sus defectos de diseño simplemente porque ni un solo lenguaje puede ser perfecto, al igual que con la mayoría (¿todo?) De otras cosas. Aparte de eso, ¿qué falla de diseño en un lenguaje de programación te ha molestado más a través de tu historia como programador?
Tenga en cuenta que si un idioma es "malo" solo porque no está diseñado para una cosa específica, no es una falla de diseño, sino una característica del diseño, así que no enumere tales molestias de idiomas. Si un lenguaje no es adecuado para lo que está diseñado, eso es, por supuesto, una falla en el diseño. Implementación de cosas específicas y, bajo el capó, las cosas tampoco cuentan.
Respuestas:
Una de mis grandes molestias es la forma
switch
en que los casos en lenguajes derivados de C pasan por defecto al siguiente caso si olvida usarlosbreak
. Entiendo que esto es útil en código de muy bajo nivel (por ejemplo, el dispositivo de Duff ), pero generalmente no es apropiado para el código de nivel de aplicación y es una fuente común de errores de codificación.Recuerdo que alrededor de 1995, cuando estaba leyendo sobre los detalles de Java por primera vez, cuando llegué a la parte sobre la
switch
declaración, estaba muy decepcionado de que hubieran conservado el comportamiento de incumplimiento predeterminado. Esto simplemente se convierteswitch
en un glorificadogoto
con otro nombre.fuente
switch
no tiene que funcionar de esa manera. Por ejemplo, la declaración caso / cuándo de Ada (equivalente a cambiar / caso) no tiene un comportamiento de caída.switch
declaraciones similares en lenguajes no relacionados con C no tienen que funcionar de esa manera. Pero si se utiliza el flujo de control tipo C ({
...}
,for (i = 0; i < N; ++i)
,return
, etc.), la inferencia lengua hará que la gente esperaswitch
que el trabajo como C, y dándole Ada / Pascal / personas como BASIC semántica habría confundido. C # requierebreak
en lasswitch
declaraciones por la misma razón, aunque lo hace menos propenso a errores al prohibir la caída silenciosa. (Pero desearía que pudieras escribir enfall;
lugar de lo feogoto case
.)switch
permita fallthrough. Es que la mayoría de los usos de fallthrough no son intencionales.Nunca me ha gustado mucho el uso de
=
para asignación y==
para pruebas de igualdad en lenguajes derivados de C. El potencial de confusión y errores es demasiado alto. Y ni siquiera me hagas comenzar con===
Javascript.Mejor hubiera sido
:=
por asignación y=
por pruebas de igualdad. La semántica podría haber sido exactamente la misma que en la actualidad, donde la asignación es una expresión que también produce un valor.fuente
x<-5
). Los programadores de C no tolerarían ese tipo de espacio en blanco requerido :):=
y==
porque sería demasiado fácil olvidarlo:
y no ser notificado como ya es el caso (aunque revertido) cuando olvidas un=
hoy. Estoy agradecido por las advertencias del compilador sobre esto ...=
y==
no está en la lectura, porque son símbolos distintos. Está por escrito y asegurándose de tener el correcto.La elección de
+
Javascript para la adición y la concatenación de cadenas fue un terrible error. Como los valores no están tipificados, esto lleva a reglas bizantinas que determinan si+
se agregarán o concatenarán, dependiendo del contenido exacto de cada operando.Hubiera sido fácil al principio introducir un operador completamente nuevo, como la
$
concatenación de cadenas.fuente
+
tiene mucho sentido como operador de concatenación de cadenas en un lenguaje fuertemente tipado. El problema es que Javascript lo usa pero no está fuertemente tipado.+
no tiene sentido para la concatenación, porque la concatenación definitivamente no es conmutativa. Es un abuso en lo que a mí respecta.*
operador?Encuentro Javascript predeterminado en global a un problema importante, y a menudo fuente de errores si no usa JSLint o similares
fuente
var
cuando declare una variable y está listo para comenzar. Y no me digas que es demasiado escribir porque Java te obliga a declarar todos los tipos dos veces y nadie se queja de que sea una elección de diseño de mierda.std::map<KEY, VALUE>::const_iterator
variables en C ++ lo suficienteauto
como para agregarlas a ese lenguaje."use strict"
directiva, agregada en es5, cambia las referencias no declaradas en un error.El preprocesador en C y C ++ es un error masivo, crea abstracciones que se filtran como tamices, fomenta el código de espagueti a través de nidos de
#ifdef
declaraciones de ratas y requiereALL_CAPS
nombres horriblemente ilegibles para solucionar sus limitaciones. La raíz de estos problemas es que opera a nivel textual más que a nivel sintáctico o semántico. Debería haber sido reemplazado con características de lenguaje real para sus diversos casos de uso. Estos son algunos ejemplos, aunque es cierto que algunos de estos se resuelven en C ++, C99 o extensiones estándar no oficiales pero de facto :#include
debería haber sido reemplazado por un sistema de módulo real.Las funciones en línea y las plantillas / genéricos podrían reemplazar la mayoría de los casos de uso de llamadas a funciones.
Se podría utilizar algún tipo de característica constante de tiempo de manifiesto / compilación para declarar tales constantes. Las extensiones de D de enum funcionan muy bien aquí.
Las macros de nivel de árbol de sintaxis real podrían resolver muchos casos de uso diversos.
Los mixins de cadena podrían usarse para el caso de uso de inyección de código.
static if
o lasversion
declaraciones podrían usarse para compilación condicional.fuente
#include
problema, pero el sistema de módulos fue inventado ... ¡luego! Y C y C ++ apuntan a un máximo de compatibilidad con versiones anteriores: /#include
pirateo basado en cpp .Uno podría enumerar cientos de errores en cientos de idiomas, pero en mi opinión, no es un ejercicio útil desde la perspectiva del diseño del lenguaje.
¿Por qué?
Porque algo que sería un error en un idioma no sería un error en otro idioma. Por ejemplo:
No son lecciones que aprender, pero las lecciones se cortan raramente clara, y para entenderlos hay que entender las ventajas y desventajas técnicas ... y el contexto histórico. (Por ejemplo, la engorrosa implementación de genéricos en Java es consecuencia de un requisito comercial primordial para mantener la compatibilidad con versiones anteriores).
En mi opinión, si te tomas en serio el diseño de un nuevo idioma, debes utilizar una amplia gama de idiomas existentes (y estudiar idiomas históricos) ... y decidir cuáles son los errores. Y debe tener en cuenta que cada uno de estos idiomas fue diseñado en un contexto histórico particular, para satisfacer una necesidad particular.
Si hay lecciones generales que aprender, están en el nivel "meta":
fuente
C y C ++ : todos esos tipos enteros que no significan nada.
Especialmente
char
. ¿Es texto o es un número entero pequeño? Si es texto, ¿es un carácter "ANSI" o una unidad de código UTF-8? Si es un entero, ¿está firmado o no?int
estaba destinado a ser el número entero "nativo", pero en los sistemas de 64 bits, no lo es.long
puede o no ser mayor queint
. Puede o no ser del tamaño de un puntero. Es casi una decisión arbitraria por parte de los escritores del compilador si es de 32 bits o de 64 bits.Definitivamente un lenguaje de los años setenta. Antes de Unicode. Antes de las computadoras de 64 bits.
fuente
null
.Su inventor, Tony Hoare, lo llama el "error de mil millones de dólares" .
Fue introducido en ALGOL en los años 60, y existe en la mayoría de los lenguajes de programación de uso común en la actualidad.
La mejor alternativa, utilizada en lenguajes como OCaml y Haskell, es quizás . La idea general es que las referencias a objetos no pueden ser nulas / vacías / inexistentes a menos que haya una indicación explícita de que pueden serlo.
(Aunque Tony es asombroso en su modestia, creo que casi cualquiera habría cometido el mismo error, y resultó ser el primero).
fuente
maybe
es una opción nula, mientras que la excepción nula es una opción nula. Por supuesto, hay algunas cosas que decir sobre la diferencia entre los errores de tiempo de ejecución y los errores de tiempo de compilación también, pero el hecho de que nulo es esencialmente un comportamiento de inyección es notable en sí mismo.Tengo la sensación de que las personas que diseñaron PHP no usaron un teclado normal, ni siquiera usan un teclado colemak, porque deberían haberse dado cuenta de lo que estaban haciendo.
Soy un desarrollador de PHP. PHP no es divertido de escribir.
Who::in::their::right::mind::would::do::this()
? El::
operador requiere mantener presionada la tecla shift y luego presionar dos teclas. Que desperdicio de energía.Aunque-> esto-> es-> no-> mucho-> mejor. Eso también requiere tres pulsaciones de teclas con el cambio entre los dos símbolos.
$last = $we.$have.$the.$dumb.'$'.$character
. El signo de dólar se usa una cantidad tremenda de veces y requiere que el premio se extienda hasta la parte superior del teclado más una tecla shift.¿Por qué no podrían diseñar PHP para usar teclas que son mucho más rápidas de escribir? ¿Por qué no podían
we.do.this()
o los vars comenzaban con una tecla que solo requería una sola pulsación de tecla, o ninguna (JavaScript) y simplemente predefinía todos los vars (como tengo que hacer para E_STRICT de todos modos)!No soy un mecanógrafo lento, pero esta es solo una elección de diseño poco convincente.
fuente
I::have::nothing::against::this->at.all()
El uso de formularios inspirados en el escritorio dentro de asp.net .
Siempre se sintió un dulce y se interpuso en el camino o cómo funciona realmente la web. Afortunadamente asp.net-mvc no sufre de la misma manera, aunque con crédito a Ruby, etc. por esa inspiración.
fuente
Para mí es la absoluta falta de convenciones de ordenamiento de nombres y argumentos de PHP en su biblioteca estándar.
Aunque la necesidad de JASS de anular referencias después de que el objeto referenciado fue liberado / eliminado (o la referencia se filtraría y se perderían varios bytes de memoria) es más grave, pero dado que JASS es un lenguaje de propósito único, no es tan crítico.
fuente
El mayor defecto de diseño que enfrento es que Python no fue diseñado como Python 3.x para empezar.
fuente
Array decaimiento en C y, en consecuencia, C ++.
fuente
delete
ydelete[]
.Tipos primitivos en Java.
Rompen el principio de que todo es un descendiente
java.lang.Object
, lo que desde un punto de vista teórico conduce a una complejidad adicional de la especificación del lenguaje, y desde una perspectiva práctica hacen que el uso de colecciones sea extremadamente tedioso.El autoboxing ayudó a aliviar los inconvenientes prácticos, pero a costa de hacer que la especificación sea aún más complicada e introducir una piel de plátano grande y gorda: ahora puede obtener una excepción de puntero nulo de lo que parece una operación aritmética simple.
fuente
Conozco a Perl mejor, así que lo elegiré.
Perl probó muchas ideas. Algunos fueron buenos. Algunos fueron malos. Algunos eran originales y no se copiaban ampliamente por una buena razón.
Una es la idea del contexto : cada llamada a una función tiene lugar en un contexto de lista o escalar, y puede hacer cosas completamente diferentes en cada contexto. Como señalé en http://use.perl.org/~btilly/journal/36756, esto complica cada API y con frecuencia conduce a problemas sutiles de diseño en el código Perl.
La siguiente es la idea de vincular completamente la sintaxis y los tipos de datos. Esto condujo a la invención de la vinculación para permitir que los objetos se enmascaren como otros tipos de datos. (También puede lograr el mismo efecto usando la sobrecarga, pero el empate es el enfoque más común en Perl).
Otro error común, cometido por muchos idiomas, es comenzar ofreciendo un alcance dinámico en lugar de léxico. Es difícil revertir esta decisión de diseño más tarde, y conduce a verrugas duraderas. La descripción clásica de esas verrugas en Perl es http://perl.plover.com/FAQs/Namespaces.html . Tenga en cuenta que esto se escribió antes de que Perl agregara
our
variables ystatic
variables.La gente está legítimamente en desacuerdo con la escritura estática versus la dinámica. Personalmente me gusta la escritura dinámica. Sin embargo, es importante tener una estructura suficiente para que los errores tipográficos sean detectados. Perl 5 hace un buen trabajo de esto con estricto. Pero Perl 1-4 se equivocó. Varios otros idiomas tienen correctores de pelusa que hacen lo mismo que estricto. Siempre que sea bueno para hacer cumplir la verificación de pelusas, eso es aceptable.
Si está buscando más ideas malas (muchas de ellas), aprenda PHP y estudie su historia. Mi error pasado favorito (solucionado hace mucho tiempo porque conducía a tantos agujeros de seguridad) fue dejar de permitir que cualquiera establezca cualquier variable pasando parámetros de formulario. Pero eso está lejos de ser el único error.
fuente
Ambigüedad de JavaScripts para bloques de código y literales de objeto.
podría ser un bloque de código, donde
a
es una etiqueta yb
es una expresión; o podría definir un objeto, con un atributoa
que tenga el valorb
fuente
a
.Voy a volver a FORTRAN y la insensibilidad a los espacios en blanco.
Permeó la especificación. La
END
tarjeta tenía que definirse como una tarjeta con una 'E', una 'N' y una 'D' en ese orden en las columnas 7-72, y no otros espacios en blanco, en lugar de una tarjeta con "FIN" en el columnas y nada más.Condujo a una fácil confusión sintáctica.
DO 100 I = 1, 10
era una declaración de control de bucle, mientras queDO 100 I = 1. 10
era una declaración que asignaba el valor 1.1 a una variable llamadaDO10I
. (El hecho de que las variables se pudieran crear sin declaración, su tipo dependiendo de su primera letra, contribuyó a esto). A diferencia de otros idiomas, no había forma de usar espacios para separar los tokens para permitir la desambiguación.También permitió a otras personas escribir código realmente confuso. Hay razones por las que esta característica de FORTRAN nunca se volvió a duplicar.
fuente
(test ? a : b)
, e) insisten sobre el uso**
, f) no puede manejar mayúsculas y minúsculas. La mayor parte de esto se debió a golpes de teclado en los años 50.Uno de los mayores problemas con BASIC fue la falta de un método bien definido para extender el lenguaje más allá de sus entornos iniciales, lo que condujo a un montón de implementaciones completamente incompatibles (y un intento post facto casi irrelevante de cualquier estandarización).
Casi cualquier lenguaje se doblará en el uso general por algún programador loco. Es mejor planificar para ese uso general al principio en caso de que la idea loca despegue.
fuente
Creo en los DSL (lenguajes específicos de dominio) y una cosa que valoro en un idioma es si me permite definir un DSL encima.
En Lisp hay macros, la mayoría de las personas consideran esto algo bueno, como yo.
En C y C ++ hay macros; las personas se quejan de ellas, pero pude usarlas para definir DSL.
En Java, se excluyeron (y, por lo tanto, en C #), y la falta de ellos se declaró una virtud. Claro que te permite tener inteligencia, pero para mí eso es solo una obra . Para hacer mi DSL, tengo que expandirme a mano. Es un dolor, y me hace ver como un mal programador, a pesar de que me permite hacer mucho más con toneladas de código.
fuente
cdr
de la lista y formaría un cierre lambda fuera de él (es decir, una continuación) y lo pasaría como un argumento alcar
de la lista. Eso se hizo recursivamente, por supuesto, y "haría lo correcto" para condicionales, bucles y llamadas a funciones. Entonces la función "elección" se convirtió en un bucle normal. No es bonito, pero era robusto. El problema es que hace que sea muy fácil crear bucles demasiado anidados.Declaraciones , en todos los idiomas que las tiene. No hacen nada que no puedas hacer con expresiones y te impiden hacer muchas cosas. La existencia de un
?:
operador ternario es solo un ejemplo de tener que tratar de sortearlos. En JavaScript, son particularmente molestos:fuente
unit
tipo (aka()
) en lugar de declaraciones tienen especial consideración para asegurarse de que no arrojen advertencias o se comporten de manera extraña.Para mí, es el problema del diseño el que afecta a todos los lenguajes derivados de C; a saber, el " colgar más ". Este problema gramatical debería haberse resuelto en C ++, pero se llevó a cabo en Java y C #.
fuente
Creo que todas las respuestas hasta ahora apuntan a un solo fallo de muchos idiomas principales:
No hay forma de cambiar el idioma principal sin afectar la compatibilidad con versiones anteriores.
Si esto se resuelve, entonces se pueden resolver casi todas esas otras quejas.
EDITAR.
Esto puede resolverse en bibliotecas al tener diferentes espacios de nombres, y podría concebir hacer algo similar para la mayor parte del núcleo de un lenguaje, aunque esto podría significar que necesita admitir múltiples compiladores / intérpretes.
En última instancia, no creo que sepa cómo resolverlo de una manera totalmente satisfactoria, pero eso no significa que no exista una solución o que no se pueda hacer más.
fuente
Desbordamiento aritmético de enteros silenciosos de Java
fuente
Tanto Java como C # tienen problemas molestos con sus sistemas de tipos debido al deseo de mantener la compatibilidad con versiones anteriores al agregar genéricos. A Java no le gusta mezclar genéricos y matrices; C # no permitirá algunas firmas útiles porque no puede usar tipos de valores como límites.
Como ejemplo de esto último, considere que
junto o reemplazando en laEnum
clase permitiría en lugar de lo tautológicotl; dr: piense en el polimorfismo paramétrico cuando comience a diseñar su sistema de tipos, no después de publicar la versión 1.
fuente
MyMethod<T>(T value) where T : struct, IComparable, IFormattable, IConvertible
Pero aún tiene que probar una enumeración y es un truco. Creo que la mayor falta en los genéricos de C # no es compatible con los tipos superiores, lo que realmente abriría el lenguaje a algunos conceptos geniales.Siento que me estoy abriendo para ser criticado, pero realmente odio la capacidad de pasar tipos de datos antiguos por referencia en C ++. Solo odio un poco poder pasar tipos complejos por referencia. Si estoy mirando una función:
Desde el punto de vista, no hay forma de saber que
bar
, que se puede definir en un archivo completamente diferente, es:Algunos podrían argumentar que hacer algo como esto puede ser un mal diseño de software y no culpar al lenguaje, pero no me gusta que el lenguaje te permita hacer esto en primer lugar. Usando un puntero y llamando
Es mucho más legible.
fuente
ALTERAR
Cuando aprendí COBOL, la declaración ALTER todavía era parte del estándar. En pocas palabras, esta declaración le permitiría modificar las llamadas a procedimientos durante el tiempo de ejecución.
El peligro era que podía poner esta declaración en una sección oscura del código a la que rara vez se accedía y tenía el potencial de cambiar completamente el flujo del resto de su programa. Con múltiples declaraciones ALTER, puede hacer que sea casi imposible saber qué estaba haciendo su programa en cualquier momento.
Mi instructor universitario, muy enfáticamente, declaró que si alguna vez veía esa declaración en alguno de nuestros programas, automáticamente nos rechazaría.
fuente
v() { if (not alreadyCalculatedResult) { result = long(operation); alreadyCalculatedResult = true; } result; }
, dicesv() { result = long(operation); v = () => result; result; }
El peor pecado de un lenguaje de programación no está bien definido. Un caso que recuerdo es C ++, que, en sus orígenes:
Como recuerdo, me llevó cerca de una década definir C ++ lo suficientemente bien como para que fuera tan profesionalmente confiable como C. Es algo que nunca debería volver a suceder.
Algo más que considero un pecado (¿debería ir en una respuesta diferente?) Es tener más de una "mejor" forma de hacer una tarea común. Es el caso de (nuevamente) C ++, Perl y Ruby.
fuente
Las clases en C ++ son algún tipo de patrón de diseño forzado en el lenguaje.
Prácticamente no hay diferencia en tiempo de ejecución entre una estructura y una clase, y es tan confuso entender cuál es la verdadera ventaja real de la programación de "ocultar información" que quiero ponerla allí.
Voy a ser rechazado por eso, pero de todos modos, los compiladores de C ++ son tan difíciles de escribir que este lenguaje se siente como un monstruo.
fuente
Aunque cada idioma tiene sus fallas, ninguna es una molestia una vez que las conoces. Excepto por este par:
Sintaxis compleja junto con una API de Wordy
Esto es particularmente cierto en un lenguaje como Objective-C. La sintaxis no solo es abrumadoramente compleja, sino que la API usa nombres de funciones como:
Estoy totalmente de ser explícito y no ambiguo, pero esto es ridículo. Cada vez que me siento con xcode, me siento como un n00b, y eso es realmente frustrante.
fuente
tableView:cellForRowAtIndexPath:
, que es muy descriptivo en mi opinión.fuente
(u)int_least8_t
). La firma tiene mucho sentido para los enteros pequeños, pero no tiene ningún sentido para los personajes.char*
... como una C-String, se confunden mucho.sbyte
,byte
ychar
tipos.