¿Cuál es, en su opinión, la característica de lenguaje más sorprendente, extraña, extraña o realmente "WTF" que ha encontrado?
Por favor, solo una función por respuesta.
¿Cuál es, en su opinión, la característica de lenguaje más sorprendente, extraña, extraña o realmente "WTF" que ha encontrado?
Por favor, solo una función por respuesta.
Respuestas:
En C, las matrices se pueden indexar así:
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 JavaScript:
'5' + 3 gives '53'
Mientras
'5' - 3 gives 2
+
para la concatenación de cuerdas es horrible
En JavaScript, la siguiente construcción
return
{
id : 1234,
title : 'Tony the Pony'
};
retornos es un error de sintaxis debido a la inserción punto y coma implícita disimulado en la nueva línea después undefined
return
. Sin embargo, lo siguiente funciona como es de 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 en silencio:
return
2 + 2;
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
==
sirve a los ojos del diseñador de idiomas?
==
tener el significado de ===
, y luego había otro operador, algo así ~=
permitía la coerción de tipo.
Trígrafos en C y C ++.
int main() {
printf("LOL??!");
}
Esto se imprimirá LOL|
porque el trigrafo ??!
se convierte a |
.
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
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 valor IntegerCache.high
predeterminado es a 127
menos que lo establezca una propiedad.
Lo que sucede con el auto boxing 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)
, al comparar la igualdad de referencia, serán verdaderas en lugar de falsas. La forma correcta de comparar el valor entero es usar.equals;
Citando a Neil Fraser (mira al 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 para el lector.
EDITADO: Mientras estemos en el tema, considere también esto:
try {
throw new AssertionError();
} finally {
return false;
}
Control cannot leave the body of a finally clause
return
en la finally
cláusula.
APL (aparte de TODO), la capacidad de escribir cualquier programa en una sola línea.
Ej . Juego de la vida de Conway en una línea en APL :
texto alternativo http://catpad.net/michael/APLLife.gif
Si esa línea no es WTF, ¡entonces nada lo es!
Y aqui hay un video
Las cosas extrañas para las plantillas C ++ se pueden usar, lo que se demuestra mejor con "Literales analógicos multidimensionales" que usan plantillas para calcular el área de 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) );
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 separadores de campo de lista y salida$!
- errno
como un número pero strerror(errno)
como una cadena$_
- la variable sigilo, siempre utilizada y nunca vista$#_
- número de índice del último argumento de subrutina ... tal vez@_
- los (no) nombres 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 buffer de salida$[
- cambie su base de matriz de 0 a 1 a 42: ¡WHEEE!$}
- Nada en absoluto, ¡curiosamente!$<
, $>
, $(
, $)
- UID y GID reales y efectivos@ISA
- nombres de las superclases directas del paquete actual$^T
- tiempo de inicio del script en segundos de época$^O
- nombre del sistema operativo actual$^V
- ¿Qué versión de Perl es esta?Hay mucho más de donde vinieron esos. Lea la lista completa aquí .
$[
variable es la más malvada de todas.
perldoc perlvar
cada cinco segundos. (Aunque confieso que la mitad del tiempo lo reviso pensando "Sé que hay una variable especial que puede hacer esto por mí, simplemente no recuerdo cuál ..." = P)
use English;
es que afecta el rendimiento de RegExp. No estoy inventando esto. perldoc.perl.org/English.html#PERFORMANCE
/$foo[bar]/
, en , ¿es la [bar]
parte una clase de caracteres o un subíndice de la matriz @foo
? Grep perldata por la aterradora respuesta.
Manejo de PHP de valores numéricos en cadenas . Vea esta respuesta anterior a una pregunta diferente para obtener detalles completos pero, en resumen:
"01a4" != "001a4"
Si tiene dos cadenas que contienen un número diferente de caracteres, no pueden considerarse iguales. Los ceros a la izquierda 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 use comillas) y son equivalentes porque los ceros iniciales se ignoran para los números. Para reforzar este punto, encontrará que PHP también se evalúa "01e4" == "10000"
como verdadero porque estos son números con valores equivalentes. Este es un comportamiento documentado, simplemente no es muy sensato.
Vamos a votar por todos los idiomas (como PL / I) que intentaron eliminar las palabras reservadas.
¿Dónde más podrías escribir legalmente 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)
Es bueno conocer la 'característica' de conversión octal de JavaScript:
parseInt('06') // 6
parseInt('07') // 7
parseInt('08') // 0
parseInt('09') // 0
parseInt('10') // 10
Más detalles aquí .
En C uno puede entrelazar un do / while con una instrucción switch. Aquí un ejemplo de una 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);
}
}
while
al final es un (condicional) de JMP
regreso al do
, lo que explica por qué puede omitirlo do
y aún terminar en el bucle.
Algol pasa por nombre (ilustrado usando la sintaxis 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]);
}
def f(j : => int)
)
... template<typename T> struct by_name { virtual operator T&() = 0; }; void f(by_name<int> j) { ... } int main() { f(struct : by_name<int> { operator int&() { return a[i]; } }); }
?
En Python:
>>> x=5
>>> 1<x<10
True
>>> 1<x<3
False
No es un WTF, sino una característica útil.
(10 > 5 > 1) != ((10 > 5) > 1)
en Python.
(funct_a(5)+5 > b > funct_a(5))
solo llama funct_a(5)
una vez. ¡Es una GRAN característica!
funct_a
se llamará dos veces en ese ejemplo. Sin b > funct_a(5) > c
embargo, solo se llamará una vez, a diferencia de b > funct_a(5) and funct_a(5) > c
.
En Java:
int[] numbers() {
return null;
}
Se puede escribir como:
int numbers() [] {
return null;
}
const T*
y T const*
son equivalentes, es lo T* const
que contrasta el puntero. Además, odio sin fuentes.
numbers()[2]
es una declaración legal.
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 opuesto a GOTO en que puede llevar el estado de ejecución desde cualquier punto arbitrario del 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 para COMEFROM. Si la transferencia se realiza antes o después de la instrucción en el punto de transferencia especificado depende del idioma utilizado. Dependiendo del lenguaje utilizado, varios COMEFROM que hacen referencia al mismo punto de partida pueden ser inválidos, no deterministas, ejecutarse en algún tipo de prioridad definida, o incluso inducir una ejecución paralela o concurrente de otro modo como se ve en la Intercal roscada. Un ejemplo simple de una declaración "COMEFROM x" es una etiqueta x (que no necesita estar físicamente ubicada cerca de su correspondiente COMEFROM) que actúa como una "puerta trampa". Cuando la ejecución del código alcanza la etiqueta, el control se pasa a la instrucción que sigue al 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 indicación cerca de la etiqueta de que el control saltará misteriosamente a otro punto del programa.
PLEASE
modificador con la frecuencia suficiente!
No es realmente una característica del lenguaje, sino una falla de implementación: algunos compiladores de Fortran implementaron constantes mediante el uso de un grupo constante. Todos los parámetros fueron pasados por referencia. Si llamó a una función, por ejemplo
f(1)
El compilador pasaría la dirección de la constante 1 en el grupo constante 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 poco de rascarse la cabeza.
2+2
puede ser igual 5
(¡para valores muy grandes, 2
por supuesto!).
2+2
lo que sería igual 5
para valores pequeños de 5
).
2 + 2 = 5
; eso será un error de sintaxis. Lo que será cierto es 2 + 2 .EQ. 5
.
No sé si se puede considerar una función de lenguaje, pero, en C ++, casi cualquier error de compilación relacionado con las plantillas ofrece una buena cantidad de WTF a muchos programadores de C ++ en todo el mundo a diario :)
std::vector<std::pair<int, std::complex>, std::allocator<std::pair<int, std::complex> > >::vector< std::vector<std::pair<int, std::complex>, std::allocator<std::pair<int, std::complex> > >::iterator>(std::vector<std::pair<int, std::complex>, std::allocator<std::pair<int, std::complex> > >::iterator, std::vector<std::pair<int, std::complex>, std::allocator<std::pair<int, std::complex> > >::iterator, std::allocator<std::pair<int, std::complex> >)
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);
}
Diría que todo el espacio en blanco de Python es mi mejor característica de WTF. Es cierto, más o menos te acostumbras después de un tiempo y los editores modernos hacen que sea fácil de tratar, pero incluso después del desarrollo de Python 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 esto, pero honestamente, se interpone en mi productividad. No por mucho, pero sigue siendo una rebaba debajo de la silla de montar.
editar: 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 me veo obligado a hacerlo o no. Lo que no me gusta es que es la sangría la que define en qué bloque está una línea de código. Prefiero delimitadores explícitos para eso. Entre otras razones, encuentro que los delimitadores explícitos hacen que sea más fácil cortar y pegar código.
Por ejemplo, si tengo un bloque con sangría de 4 espacios y lo pego al final de un bloque con sangría de 8 espacios, mi editor (¿todos los editores?) No tengo idea 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 se debe (re) sangrar; lo hace buscando inteligentemente 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 que Python sea un lenguaje pobre. De nuevo, no es cierto. Si bien no me gusta tanto, eso no viene al caso. La pregunta es sobre la característica más extraña del lenguaje, y creo que esto es extraño, en virtud de que es algo que muy, muy pocos (pero> 0) usan los idiomas.
Luché un poco sobre esto:
1;
En perl, los módulos deben devolver algo verdadero .
'Cogito ergo sum';
que, como todos saben, es evidentemente cierto en todos los universos posibles. Esto garantiza la máxima portabilidad".
<?=1;?>
devuelve 1. <?=true;?>
devuelve 1. <?=false;?>
devuelve nulo.
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 pegar un! en frente de su condicional se forma demasiado complicado!
While
y Whend
", ya que hay algunas personas que pronuncian la palabra "mientras" con la aproximación velar labializada sin voz. Y, por supuesto, se alinea mejor, y el código que se alinea es agradable.
Para aquellos que no saben, bc
es un "lenguaje de calculadora de precisión arbitraria", y lo uso con bastante frecuencia para cálculos rápidos, particularmente cuando los números involucrados son grandes ( $
es el indicador):
$ bc -lq
12^345
20774466823273785598434446955827049735727869127052322369317059031795\
19704325276892191015329301807037794598378537132233994613616420526484\
93077727371807711237016056649272805971389591721704273857856298577322\
13812114239610682963085721433938547031679267799296826048444696211521\
30457090778409728703018428147734622401526422774317612081074841839507\
864189781700150115308454681772032
bc
ha sido un comando estándar de Unix durante mucho tiempo.
Ahora para la "función WTF". Esto es de man bc
(énfasis mío):
salir : cuando se lee la declaración de salida, el procesador bc se termina, independientemente de dónde se encuentre la declaración de salida. Por ejemplo, "if (0 == 1) quit" hará que bc termine.
detener : la declaración de detención (una extensión) es una declaració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 la detención.
bc
antes de eso, y quería escribir sobre bc
mi publicación debido a las excelentes citas de la página de manual.
echo '[q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq'|dc
(aunque tal vez ya lo sepas).
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 ...
JavaScript está orientado a objetos, ¿verdad? Entonces, los métodos de ejecución en cadenas literales y números deberían funcionar. Me gusta "hello".toUpperCase()
y 3.toString()
. Resulta que el segundo es un error de sintaxis, ¿por qué? Porque el analizador espera que un número seguido de un punto sea un literal de coma flotante. Ese no es el WTF, el WTF es que solo tienes 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.
3..__add__(4)
). Por otra parte, creo que (3).__add__(4)
es una forma mucho menos dañada de hacerlo :)
3.0.toString()
hace que me piquen los ojos.
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 stackoverflow.com me lo explicó todo: ¿por qué 2 == [2] en JavaScript?
===
en su lugar.
Number(n)
para hacer algo similar. Desafortunadamente en nuestras dos soluciones se ===
rompe = (.
Mi característica más odiada es la sintaxis de cualquier archivo de configuración que incluye lógica condicional. Este tipo de cosas abundan en el mundo de Java (Ant, Maven, etc. ¡Sabes quién eres!).
Acabas de programar 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.
powerbasic (www.powerbasic.com) incluye la directiva del compilador:
# BLOAT {bloatsize}
esto aumenta el tamaño del ejecutable compilado por <bloatsize>
bytes. esto se puso en el compilador en caso de que a las personas que crean el ejecutable no les guste el pequeño tamaño del ejecutable generado. hace que el EXE parezca más grande para competir con los lenguajes de programación hinchados :)