language-agnostic programming-languages

language agnostic - La característica más extraña del lenguaje



language-agnostic programming-languages (30)

Citando a Neil Fraser (mira el final de esa página),

try { return true; } finally { return false; }

(en Java, pero el comportamiento es aparentemente el mismo en JavaScript y Python). El resultado se deja como ejercicio al lector.

EDITADO: Mientras estemos en el tema consideremos también esto:

try { throw new AssertionError(); } finally { return false; }

¿Cuál es, en su opinión, la característica de lenguaje más sorprendente, rara, extraña o realmente "WTF" que ha encontrado?

Por favor, solo una característica por respuesta.


Diversión con el boxeo automático y el caché de enteros en Java:

Integer foo = 1000; Integer bar = 1000; foo <= bar; // true foo >= bar; // true foo == bar; // false //However, if the values of foo and bar are between 127 and -128 (inclusive) //the behaviour changes: Integer foo = 42; Integer bar = 42; foo <= bar; // true foo >= bar; // true foo == bar; // true

Explicación

Un vistazo rápido al código fuente de Java mostrará lo siguiente:

/** * Returns a <tt>Integer</tt> instance representing the specified * <tt>int</tt> value. * If a new <tt>Integer</tt> instance is not required, this method * should generally be used in preference to the constructor * {@link #Integer(int)}, as this method is likely to yield * significantly better space and time performance by caching * frequently requested values. * * @param i an <code>int</code> value. * @return a <tt>Integer</tt> instance representing <tt>i</tt>. * @since 1.5 */ public static Integer valueOf(int i) { if (i >= -128 && i <= IntegerCache.high) return IntegerCache.cache[i + 128]; else return new Integer(i); }

Nota: El IntegerCache.high predeterminado de IntegerCache.high es 127 menos que lo establezca una propiedad.

Lo que sucede con el boxeo automático es que tanto foo como bar el mismo objeto entero recuperado de la memoria caché a menos que se cree explícitamente: por ejemplo, foo = new Integer(42) , por lo tanto, al comparar la igualdad de referencia, serán verdaderos en lugar de falsos. La forma correcta de comparar el valor Integer es usando .equals;


En C, los arreglos pueden ser indexados de la siguiente manera:

a[10]

lo cual es muy común.

Sin embargo, la forma menos conocida (¡que realmente funciona!) Es:

10[a]

lo que significa lo mismo que el anterior.


En Java:

int[] numbers() { return null; }

Se puede escribir como:

int numbers() [] { return null; }


En JavaScript, la siguiente construcción

return { id : 1234, title : ''Tony the Pony'' };

devuelve undefined es un error de sintaxis debido a la inserción implícita de punto y coma implícita en la nueva línea después del return . Las siguientes obras funcionan como cabría esperar

return { id : 1234, title : ''Tony the Pony'' };

Peor aún, este también funciona (al menos en Chrome):

return /* */{ id : 1234, title : ''Tony the Pony'' };

Aquí hay una variante del mismo problema que no produce un error de sintaxis, simplemente falla silenciosamente:

return 2 + 2;


En JavaScript:

2 == [2] // Even stranger 2 == [[[2]]] // And down-right nutty var a = { "abc" : 1 }; a[[[["abc"]]]] === a["abc"]; // this is also true

Afortunadamente, la gente amable de .com me explicó todo esto: ¿Por qué 2 == [2] en JavaScript?


En JavaScript:

''5'' + 3 gives ''53''

Mientras

''5'' - 3 gives 2


En Python:

>>> x=5 >>> 1<x<10 True >>> 1<x<3 False

No es un WTF, pero una característica útil.


La ''característica'' de conversión octal de JavaScript es una buena información sobre:

parseInt(''06'') // 6 parseInt(''07'') // 7 parseInt(''08'') // 0 parseInt(''09'') // 0 parseInt(''10'') // 10

Más detalles here .


Las muchas variables incorporadas de Perl:

  • $# - no es un comentario!
  • $0 , $$ y $? - Al igual que las variables de shell con el mismo nombre
  • , $& , y $'' - variables de coincidencia extrañas
  • $" y $, - variables extrañas para los separadores de campo de salida y lista
  • $! - me gusta errno como un número pero strerror(errno) como una cadena
  • $_ - la variable sigilosa, siempre usada y nunca vista
  • $#_ - número de índice del último argumento de subrutina ... tal vez
  • @_ - los nombres (no) de la función actual ... tal vez
  • $@ - la última excepción planteada
  • %:: - la tabla de símbolos
  • $: $^ , $~ , $- y $= - algo que ver con los formatos de salida
  • $. y $% - número de línea de entrada, número de página de salida
  • $/ y $/ - separadores de registros de entrada y salida
  • $| - controlador de búfer de salida
  • $[ : Cambie su base de arreglo de 0 basado en 1 basado en 42: WHEEE!
  • $} - nada en absoluto, por extraño que parezca!
  • $< , $> , $( , $) - UID y GID reales y efectivos
  • @ISA - nombres de las superclases directas del paquete actual
  • $^T - tiempo de inicio de script en la época segundos
  • $^O - nombre del sistema operativo actual
  • $^V - ¿Qué versión de Perl es esta?

Hay mucho más de donde vinieron. Lea la lista completa here .


Las plantillas de C ++ para cosas raras se pueden utilizar, lo que se demuestra mejor con "Literales analógicos multidimensionales" que utilizan plantillas para calcular el área de las formas "dibujadas". El siguiente código es válido en C ++ para un rectángulo de 3x3.

#include"analogliterals.hpp" using namespace analog_literals::symbols; unsigned int c = ( o-----o | ! ! ! ! ! o-----o ).area;

O, otro ejemplo con un cubo 3D:

assert( ( o-------------o |L / | L / | L / | o-------------o | ! ! ! ! ! o | ! L | ! L | ! L| ! o-------------o ).volume == ( o-------------o | ! ! ! ! ! o-------------o ).area * int(I-------------I) );


Los muchos espacios de nombres de C:

typedef int i; void foo() { struct i {i i;} i; i: i.i = 3; printf( "%i/n", i.i); }

O con personajes:

typedef char c; void foo() { struct c {c c;} c; c: c.c = ''c''; printf( "%c/n", c.c); }


No es realmente una característica del lenguaje, sino un defecto de implementación: algunos compiladores tempranos de Fortran implementaron constantes mediante el uso de un conjunto constante. Todos los parámetros fueron pasados ​​por referencia. Si llamaste a una función, por ejemplo

f(1)

El compilador pasaría la dirección de la constante 1 en el conjunto de constantes a la función. Si asignó un valor al parámetro en la función, cambiaría el valor (en este caso el valor de 1) globalmente en el programa. Causó un rasguño en la cabeza.


No sé si se puede considerar una función de lenguaje, pero en C ++ casi todos los errores de compilación relacionados con las plantillas ofrecen una cantidad considerable de WTF a muchos programadores de C ++ en todo el mundo a diario :)


Paso de Algol por nombre (ilustrado usando la sintaxis de C):

int a[3] = { 1, 2, 3 }; int i = 1; void f(int j) { int k; k = j; // k = 2 i = 0; k = j; // k = 1 (!?!) } int main() { f(a[i]); }


Tabla de verdad de JavaScript:

'''' == ''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

Fuente: Doug Crockford


Tengamos un voto para todos los idiomas (como PL / I) que intentaron eliminar las palabras reservadas.

¿Dónde más podrías legalmente escribir expresiones tan divertidas como:

IF IF THEN THEN = ELSE ELSE ELSE = THEN

( IF , THEN , ELSE son nombres de variables)

o

IF IF THEN THEN ELSE ELSE

( IF es una variable, THEN y ELSE son subrutinas)


Trigrafías en C y C ++.

int main() { printf("LOL??!"); }

Esto imprimirá LOL| , porque el trigraph ??! se convierte a | .



El dispositivo de Duff en C!

En C se puede entrelazar un do / while con una instrucción switch. Aquí un ejemplo de un memcpy usando este método:

void duff_memcpy( char* to, char* from, size_t count ) { size_t n = (count+7)/8; switch( count%8 ) { case 0: do{ *to++ = *from++; case 7: *to++ = *from++; case 6: *to++ = *from++; case 5: *to++ = *from++; case 4: *to++ = *from++; case 3: *to++ = *from++; case 2: *to++ = *from++; case 1: *to++ = *from++; }while(--n>0); } }


INTERCAL es probablemente el mejor compendio de características de lenguaje más extrañas. Mi favorito personal es la declaración COMEFROM que es (casi) lo opuesto a GOTO.

COMEFROM es aproximadamente lo contrario de GOTO en que puede tomar el estado de ejecución de cualquier punto arbitrario en el código a una declaración COMEFROM. El punto en el código donde ocurre la transferencia de estado generalmente se da como un parámetro a COMEFROM. Si la transferencia se realiza antes o después de la instrucción en el punto de transferencia especificado, depende del idioma utilizado. Según el idioma utilizado, las COMEFROM múltiples que hacen referencia al mismo punto de partida pueden no ser válidas, ser no deterministas, ejecutarse en algún tipo de prioridad definida, o incluso inducir una ejecución paralela o concurrente, como se ve en Threaded Intercal. Un ejemplo simple de una declaración "COMEFROM x" es una etiqueta x (que no necesita estar ubicada físicamente en ningún lugar cerca de su COMEFROM correspondiente) que actúa como una "puerta trampa". Cuando la ejecución del código alcanza la etiqueta, el control pasa a la instrucción que sigue a COMEFROM. El efecto de esto es principalmente hacer que la depuración (y la comprensión del flujo de control del programa) sea extremadamente difícil, ya que no hay ninguna indicación cerca de la etiqueta de que el control saltará misteriosamente a otro punto del programa.


Manejo de PHP de valores numéricos en cadenas . Vea esta respuesta anterior a una pregunta diferente para obtener todos los detalles, pero, en resumen:

"01a4" != "001a4"

Si tiene dos cadenas que contienen un número diferente de caracteres, no se pueden considerar iguales. Los ceros iniciales son importantes porque son cadenas y no números.

"01e4" == "001e4"

PHP no le gustan las cadenas. Está buscando cualquier excusa que pueda encontrar para tratar sus valores como números. Cambie ligeramente los caracteres hexadecimales en esas cadenas y, de repente, PHP decide que ya no son cadenas, son números en notación científica (a PHP no le importa que haya comillas) y son equivalentes porque los ceros a la izquierda no se tienen en cuenta para los números. Para reforzar este punto, encontrará que PHP también evalúa "01e4" == "10000" como verdadero porque estos son números con valores equivalentes. Esto es un comportamiento documentado, simplemente no es muy sensible.


Luché un poco sobre esto:

1;

En perl, los módulos necesitan devolver algo verdadero .


Siempre me pregunté por qué el programa más simple era:

class HelloWorldApp { public static void main(String[] args) { System.out.println("Hello World!"); } }

Mientras que podría ser:

print "Hello World!"

Tal vez esto es para asustar a los estudiantes de informática en primer lugar ...


powerbasic (www.powerbasic.com) incluye la directiva del compilador:

# BLOAT {bloatsize}

esto aumenta el tamaño del ejecutable compilado por <bloatsize>bytes. esto se colocó en el compilador en caso de que a las personas que crean el ejecutable no les guste el tamaño pequeño del ejecutable generado. hace que el EXE parezca más grande para competir con lenguajes de programación inflados :)


JavaScript está orientado a objetos, ¿verdad? Así que los métodos de ejecución en cadenas y números literales deberían funcionar. Al igual que "hello".toUpperCase()y 3.toString(). Resulta que el segundo es un error de sintaxis, ¿por qué? Debido a que el analizador espera que un número seguido de un punto sea un literal de punto flotante. Ese no es el WTF, el WTF es que solo tiene que agregar otro punto para que funcione:

3..toString()

La razón es que el literal 3.se interpreta como 3.0, y 3.0.toString()funciona bien.


Me sorprende que nadie haya mencionado las 7 construcciones de bucle de Visual Basic .

For i As Integer = 1 to 10 ... Next While True ... End While Do While True ... Loop Do Until True ... Loop Do ... Loop While True Do ... Loop Until True While True ... Wend

Porque pegando un! en frente de su condicional se forma demasiado complicado!


Mi característica más odiada es la sintaxis de cualquier archivo de configuración que incluya lógica condicional. Este tipo de cosas abunda en el mundo Java (Ant, Maven, etc. ¡Sabes quién eres!).

Acaba de terminar la programación en lenguaje ac ** p, con depuración limitada y soporte de editor limitado.

Si necesita lógica en su configuración, el enfoque "Pythonic" de codificar la configuración en un lenguaje real es mucho mejor.


Para aquellos que no saben, bces un "lenguaje de calculadora de precisión arbitraria", y lo uso muy a menudo para cálculos rápidos, especialmente cuando los números involucrados son grandes ( $es el indicador):

$ bc -lq 12^345 20774466823273785598434446955827049735727869127052322369317059031795/ 19704325276892191015329301807037794598378537132233994613616420526484/ 93077727371807711237016056649272805971389591721704273857856298577322/ 13812114239610682963085721433938547031679267799296826048444696211521/ 30457090778409728703018428147734622401526422774317612081074841839507/ 864189781700150115308454681772032

bcHa sido un comando estándar de Unix durante mucho tiempo.

Ahora para la "característica WTF". Esto es de man bc(énfasis mío):

quit : cuando se lee la instrucción quit, se termina el procesador bc, independientemente de dónde se encuentre la instrucción quit. Por ejemplo, "if (0 == 1) quit" hará que bc termine.

detener : la instrucción de detención (una extensión) es una instrucción ejecutada que hace que el procesador bc se cierre solo cuando se ejecuta. Por ejemplo, "if (0 == 1) halt" no hará que bc termine porque no se ejecuta el halt.


Yo diría que todo lo relacionado con los espacios en blanco de Python es mi mejor característica WTF. Es cierto, más o menos te acostumbras después de un tiempo y los editores modernos hacen que sea más fácil tratar con ellos, pero incluso después del desarrollo de Python en su mayoría a tiempo completo durante el año pasado, todavía estoy convencido de que fue una mala idea. He leído todo el razonamiento detrás de él pero, honestamente, se interpone en el camino de mi productividad. No por mucho, pero sigue siendo una rebaba debajo de la silla de montar.

Edición: a juzgar por los comentarios, algunas personas parecen pensar que no me gusta sangrar mi código. Esa es una evaluación incorrecta. Siempre he sangrado mi código sin importar el idioma y si estoy obligado a hacerlo o no. Lo que no me gusta es que es la sangría que define en qué bloque se encuentra una línea de código. Prefiero los delimitadores explícitos para eso. Entre otras razones, encuentro que los delimitadores explícitos hacen que sea más fácil cortar y pegar el código.

Por ejemplo, si tengo un bloque con sangría de 4 espacios y lo pego al final de un bloque que tiene sangría de 8 espacios, mi editor (¿todos los editores?) No tienen idea de si el código pegado pertenece al bloque de 8 espacios o al exterior bloquear. OTOH, si tengo delimitadores explícitos es obvio a qué bloque pertenece el código y cómo debería ser (re) sangrado, lo hace buscando inteligentemente los delimitadores de bloque.

edición 2: algunas personas que proporcionan comentarios parecen pensar que esta es una característica que odio o que creo que hace de python un lenguaje pobre. Una vez más, no es cierto. Si bien no me gusta mucho, eso no viene al caso. La pregunta es sobre la característica de lenguaje más extraña , y creo que esto es extraño, en virtud de que es algo que muy, muy pocos (pero> 0) usan los idiomas.