Qual é, na sua opinião, o recurso de linguagem mais surpreendente, estranho, estranho ou realmente "WTF" que você encontrou?
Por favor, apenas um recurso por resposta.
Qual é, na sua opinião, o recurso de linguagem mais surpreendente, estranho, estranho ou realmente "WTF" que você encontrou?
Por favor, apenas um recurso por resposta.
Respostas:
Em C, matrizes podem ser indexadas da seguinte forma:
a[10]
o que é muito comum.
No entanto, a forma menos conhecida (que realmente funciona!) É:
10[a]
o que significa o mesmo que o acima.
Em JavaScript:
'5' + 3 gives '53'
Enquanto que
'5' - 3 gives 2
+
para concatenação é horrível
Em JavaScript, a construção a seguir
return
{
id : 1234,
title : 'Tony the Pony'
};
retorna é um erro de sintaxe devido à inserção de ponto e vírgula implícita furtiva na nova linha posterior undefined
return
. O seguinte funciona como seria de esperar:
return {
id : 1234,
title : 'Tony the Pony'
};
Pior ainda, este também funciona (no Chrome, pelo menos):
return /*
*/{
id : 1234,
title : 'Tony the Pony'
};
Aqui está uma variante do mesmo problema que não gera um erro de sintaxe, mas falha silenciosamente:
return
2 + 2;
Tabela de verdade do 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
Fonte: Doug Crockford
==
serve aos olhos do designer de idiomas?
==
tivesse o significado de ===
, e então houvesse outro operador, algo assim ~=
permitido coerção de tipo.
Trígrafos em C e C ++.
int main() {
printf("LOL??!");
}
Isso será impresso LOL|
, porque o trigrafo ??!
é convertido em |
.
Diversão com o boxe automático e o cache inteiro em 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
Uma rápida olhada no código-fonte Java exibirá o seguinte:
/**
* 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: o IntegerCache.high
padrão é a 127
menos que definido por uma propriedade.
O que acontece com o boxing automático é que foo e bar o mesmo objeto inteiro recuperado do cache, a menos que seja explicitamente criado: por exemplo foo = new Integer(42)
, portanto, ao comparar a igualdade de referência, elas serão verdadeiras e não falsas. A maneira correta de comparar o valor inteiro é usando.equals;
Citando Neil Fraser (veja o final dessa página),
try {
return true;
} finally {
return false;
}
(em Java, mas o comportamento é aparentemente o mesmo em JavaScript e Python). O resultado é deixado como um exercício para o leitor.
EDITADO: Enquanto estivermos no assunto, considere também o seguinte:
try {
throw new AssertionError();
} finally {
return false;
}
Control cannot leave the body of a finally clause
return
na finally
cláusula.
APL (exceto ALL), a capacidade de escrever qualquer programa em apenas uma linha.
por exemplo , Jogo da Vida de Conway em uma linha no APL :
texto alternativo http://catpad.net/michael/APLLife.gif
Se essa linha não for WTF, nada será!
E aqui está um vídeo
As coisas estranhas que os modelos C ++ podem ser usados, melhor demonstradas pelos "Literais analógicos multidimensionais", que usam modelos para calcular a área de formas "desenhadas". O código a seguir é válido em C ++ para um retângulo 3x3
#include"analogliterals.hpp"
using namespace analog_literals::symbols;
unsigned int c = ( o-----o
| !
! !
! !
o-----o ).area;
Ou outro exemplo com um 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) );
Muitas variáveis internas do Perl:
$#
- não é um comentário!$0
,, $$
e $?
- assim como as variáveis de shell com o mesmo nome$ˋ
, $&
E $'
- variáveis de captura estranhas$"
e $,
- variáveis estranhas para separadores de campos de lista e saída$!
- como errno
um número, mas strerror(errno)
como uma string$_
- a variável stealth, sempre usada e nunca vista$#_
- número do índice do último argumento da sub-rotina ... talvez@_
- os nomes (não) da função atual ... talvez$@
- a última exceção levantada%::
- a tabela de símbolos$:
, $^
, $~
, $-
, E $=
- algo a ver com formatos de saída$.
e $%
- número da linha de entrada, número da página de saída$/
e $\
- separadores de registros de entrada e saída$|
- controlador de buffer de saída$[
- mude sua base de array de 0 para 1 e 42: WHEEE!$}
- nada, curiosamente!$<
, $>
, $(
, $)
- UIDs e GIDs reais e efetivos@ISA
- nomes das superclasses diretas do pacote atual$^T
- tempo de inicialização do script em segundos$^O
- nome atual do sistema operacional$^V
- qual é a versão do PerlHá muito mais de onde eles vieram. Leia a lista completa aqui .
$[
variável é a mais má de todas.
perldoc perlvar
cada cinco segundos. (Embora eu confesso que metade do tempo eu verificá-lo pensando: "Eu sei que há uma variável especial que pode fazer isso por mim, eu não lembro qual ..." = P)
use English;
é que isso afeta o desempenho do RegExp. Eu não estou inventando isso. perldoc.perl.org/English.html#PERFORMANCE
/$foo[bar]/
, em , a [bar]
parte é uma classe de caracteres ou um subscrito para a matriz @foo
? Grep perldata pela resposta terrível.
Manipulação do PHP de valores numéricos em strings . Veja esta resposta anterior a uma pergunta diferente para obter detalhes completos, mas, resumindo:
"01a4" != "001a4"
Se você tiver duas cadeias que contêm um número diferente de caracteres, elas não poderão ser consideradas iguais. Os zeros à esquerda são importantes porque são cadeias e não números.
"01e4" == "001e4"
PHP não gosta de strings. Ele está procurando qualquer desculpa que possa encontrar para tratar seus valores como números. Altere os caracteres hexadecimais nessas cadeias um pouco e de repente o PHP decide que não são mais cadeias, são números em notação científica (o PHP não se importa que você tenha usado aspas) e são equivalentes porque zeros à esquerda são ignorados por números. Para reforçar esse ponto, você descobrirá que o PHP também é avaliado "01e4" == "10000"
como verdadeiro porque esses são números com valores equivalentes. Esse é um comportamento documentado, mas não é muito sensato.
Vamos votar em todos os idiomas (como PL / I) que tentaram eliminar as palavras reservadas.
Onde mais você poderia legalmente escrever expressões divertidas como:
IF IF THEN THEN = ELSE ELSE ELSE = THEN
( IF
, THEN
, ELSE
São nomes de variáveis)
ou
IF IF THEN THEN ELSE ELSE
( IF
é uma variável THEN
e ELSE
são sub-rotinas)
O 'recurso' de conversão octal do JavaScript é bom para saber sobre:
parseInt('06') // 6
parseInt('07') // 7
parseInt('08') // 0
parseInt('09') // 0
parseInt('10') // 10
Mais detalhes aqui .
Em C, pode-se entrelaçar um fazer / enquanto com uma instrução switch. Aqui está um exemplo de um 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
, o final é um JMP
retorno (condicional) para o do
, o que explica por que você pode pular o arquivo do
e ainda assim acabar no loop.
Passe Algol por nome (ilustrado usando a sintaxe 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]; } }); }
?
Em Python:
>>> x=5
>>> 1<x<10
True
>>> 1<x<3
False
Não é um WTF, mas um recurso útil.
(10 > 5 > 1) != ((10 > 5) > 1)
em Python.
(funct_a(5)+5 > b > funct_a(5))
apenas chama funct_a(5)
uma vez. É um ótimo recurso!
funct_a
será chamado duas vezes nesse exemplo. Em b > funct_a(5) > c
ela só vai ser chamado uma vez que, ao contrário b > funct_a(5) and funct_a(5) > c
.
Em Java:
int[] numbers() {
return null;
}
Pode ser escrito como:
int numbers() [] {
return null;
}
const T*
e T const*
são equivalentes, é isso T* const
que consome o ponteiro. Além disso, eu odeio fontes sem.
numbers()[2]
é uma declaração legal.
INTERCAL é provavelmente o melhor compêndio de recursos linguísticos mais estranhos. Meu favorito pessoal é a declaração COMEFROM , que é (quase) o oposto do GOTO.
COMEFROM é aproximadamente o oposto de GOTO, pois ele pode levar o estado de execução de qualquer ponto arbitrário no código para uma instrução COMEFROM. O ponto no código em que a transferência de estado ocorre geralmente é fornecido como parâmetro para o COMEFROM. Se a transferência ocorre antes ou depois da instrução no ponto de transferência especificado depende do idioma usado. Dependendo do idioma usado, vários COMEFROMs que referenciam o mesmo ponto de partida podem ser inválidos, não determinísticos, executados em algum tipo de prioridade definida ou até induzir a execução paralela ou simultânea, como visto no Threaded Intercal. Um exemplo simples de uma instrução "COMEFROM x" é um rótulo x (que não precisa estar fisicamente localizado em qualquer lugar próximo ao COMEFROM correspondente) que atua como um "alçapão". Quando a execução do código atinge o rótulo, o controle é passado para a instrução após o COMEFROM. O efeito disso é principalmente tornar a depuração (e entender o fluxo de controle do programa) extremamente difícil, pois não há indicação perto do rótulo de que o controle vá misteriosamente para outro ponto do programa.
PLEASE
modificador com bastante frequência!
Não é realmente um recurso de linguagem, mas uma falha de implementação: alguns compiladores anteriores do Fortran implementaram constantes usando um pool constante. Todos os parâmetros foram passados por referência. Se você chamou uma função, por exemplo
f(1)
O compilador passaria o endereço da constante 1 no pool constante para a função. Se você atribuiu um valor ao parâmetro na função, alteraria o valor (neste caso, o valor de 1) globalmente no programa. Causou algum coçar a cabeça.
2+2
pode ser igual 5
(para valores muito grandes, é 2
claro!).
2+2
seria igual 5
para valores pequenos de 5
).
2 + 2 = 5
; isso será um erro de sintaxe. O que será verdade é 2 + 2 .EQ. 5
.
Não sei se ele pode ser considerado um recurso de linguagem, mas em C ++ quase qualquer erro de compilador relacionado a modelos fornece uma quantidade razoável de WTF para muitos programadores de C ++ diariamente em todo o mundo :)
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> >)
Os muitos espaços de nomes de C:
typedef int i;
void foo()
{
struct i {i i;} i;
i: i.i = 3;
printf( "%i\n", i.i);
}
Ou com caracteres:
typedef char c;
void foo()
{
struct c {c c;} c;
c: c.c = 'c';
printf( "%c\n", c.c);
}
Eu diria que todo o espaço em branco do Python é o meu maior recurso WTF. É verdade que você se acostuma mais ou menos com isso depois de um tempo e os editores modernos facilitam o tratamento, mas mesmo depois do desenvolvimento de python em tempo integral no ano passado, ainda estou convencido de que foi uma má ideia. Eu li todo o raciocínio por trás disso, mas honestamente, isso atrapalha minha produtividade. Não muito, mas ainda é uma rebarba debaixo da sela.
editar: a julgar pelos comentários, algumas pessoas parecem pensar que eu não gosto de recuar meu código. Essa é uma avaliação incorreta. Eu sempre recuei meu código, não importa qual idioma e se sou forçado ou não. O que eu não gosto é que é o recuo que define em que bloco uma linha de código está. Prefiro delimitadores explícitos para isso. Entre outras razões, acho que delimitadores explícitos facilitam a recortar e colar o código.
Por exemplo, se eu tiver um bloco com quatro espaços recuados e colá-lo no final de um bloco com oito espaços recuados, meu editor (todos os editores?) Não faz ideia se o código colado pertence ao bloco de 8 espaços ou ao espaço externo quadra. OTOH, se eu tenho delimitadores explícitos, é óbvio a qual bloco o código pertence e como deve ser (re) indentado - ele o faz procurando inteligentemente por delimitadores de bloco.
edit 2: algumas pessoas que fazem comentários parecem pensar que esse é um recurso que odeio ou que faz do python uma linguagem ruim. Novamente, não é verdade. Embora eu não goste muito, isso não vem ao caso. A questão é sobre o recurso de idioma mais estranho , e acho isso estranho, por ser algo que muito, muito poucas (mas> 0) as linguagens usam.
Eu lutei um pouco sobre isso:
1;
No perl, os módulos precisam retornar algo verdadeiro .
'Cogito ergo sum';
que, como todos sabem, é evidentemente verdadeiro em todos os universos possíveis. Isso garante a máxima portabilidade".
<?=1;?>
retorna 1. <?=true;?>
retorna 1. <?=false;?>
retorna nulo.
Estou surpreso que ninguém tenha mencionado as construções de loop de 7 do 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 furando um! na frente de sua condicional é maneira muito complicado!
While
e Whend
", já que algumas pessoas pronunciam a palavra "enquanto" com o velar labializado sem voz aproximadamente. E é claro que ele se alinha melhor, e o código que se alinha é bom.
Para quem não sabe, bc
é uma "linguagem arbitrária da calculadora de precisão", e eu a uso com frequência para cálculos rápidos, principalmente quando os números envolvidos são grandes ( $
é o prompt):
$ bc -lq
12^345
20774466823273785598434446955827049735727869127052322369317059031795\
19704325276892191015329301807037794598378537132233994613616420526484\
93077727371807711237016056649272805971389591721704273857856298577322\
13812114239610682963085721433938547031679267799296826048444696211521\
30457090778409728703018428147734622401526422774317612081074841839507\
864189781700150115308454681772032
bc
tem sido um comando padrão do Unix há muito tempo.
Agora, para o "recurso WTF". Isto é de man bc
(ênfase minha):
quit : Quando a instrução quit é lida, o processador bc é finalizado, independentemente de onde a instrução quit foi encontrada. Por exemplo, "se (0 == 1) sair" fará com que bc seja finalizado.
parada : a instrução de parada (uma extensão) é uma instrução executada que faz com que o processador bc seja encerrado somente quando é executado. Por exemplo, "if (0 == 1) halt" não fará com que bc termine porque a parada não é executada.
bc
antes disso e queria escrever bc
no meu post por causa das ótimas citações da página de manual.
echo '[q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq'|dc
(embora você já deva saber disso).
Eu sempre me perguntei por que o programa mais simples era:
class HelloWorldApp {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Considerando que poderia ser:
print "Hello World!"
Talvez isso seja para assustar os estudantes de ciência da computação em primeiro lugar ...
JavaScript é orientado a objetos, certo? Portanto, os métodos em execução em strings e números literais devem funcionar. Como "hello".toUpperCase()
e 3.toString()
. Acontece que o segundo é um erro de sintaxe, por quê? Como o analisador espera que um número seguido de um ponto seja um literal de ponto flutuante. Esse não é o WTF, o WTF é que você só precisa adicionar outro ponto para fazê-lo funcionar:
3..toString()
A razão é que o literal 3.
é interpretado como 3.0
e 3.0.toString()
funciona bem.
3..__add__(4)
). Então, novamente eu acho que (3).__add__(4)
é uma forma menos muito cérebro danificado para fazê-lo :)
3.0.toString()
faz meus olhos coçarem.
Em JavaScript:
2 == [2]
// Even stranger
2 == [[[2]]]
// And down-right nutty
var a = { "abc" : 1 };
a[[[["abc"]]]] === a["abc"]; // this is also true
Felizmente, o pessoal do stackoverflow.com me explicou tudo: Por que 2 == [2] em JavaScript?
===
.
Number(n)
para fazer algo semelhante. Infelizmente, em ambas as nossas soluções, as ===
quebras = (.
Meu maior recurso mais odiado é qualquer sintaxe de arquivo de configuração que inclua lógica condicional. Esse tipo de coisa é comum no mundo Java (Ant, Maven, etc. Você sabe quem é!).
Você acaba programando em linguagem AC ** P, com depuração limitada e suporte limitado ao editor.
Se você precisar de lógica em sua configuração, a abordagem "Pythonic" de codificar a configuração em uma linguagem real é muito melhor.
O powerbasic (www.powerbasic.com) inclui a diretiva do compilador:
# BLOAT {bloatsize}
isso aumenta o tamanho do executável compilado em <bloatsize>
bytes. isso foi colocado no compilador caso as pessoas que criam o executável não gostem do tamanho pequeno do executável gerado. faz o EXE parecer maior para competir com as linguagens de programação inchadas :)