Quelle est, selon vous, la fonctionnalité de langage la plus surprenante, bizarre, étrange ou vraiment "WTF" que vous ayez rencontrée?
Veuillez une seule fonctionnalité par réponse.
Quelle est, selon vous, la fonctionnalité de langage la plus surprenante, bizarre, étrange ou vraiment "WTF" que vous ayez rencontrée?
Veuillez une seule fonctionnalité par réponse.
Réponses:
En C, les tableaux peuvent être indexés comme suit:
a[10]
ce qui est très courant.
Cependant, la forme la moins connue (qui fonctionne vraiment!) Est:
10[a]
ce qui signifie la même chose que ci-dessus.
En JavaScript:
'5' + 3 gives '53'
Tandis que
'5' - 3 gives 2
+
pour la concaténation de chaînes est horrible
En JavaScript, la construction suivante
return
{
id : 1234,
title : 'Tony the Pony'
};
retours est une erreur de syntaxe due à l'insertion sournoise de points-virgules implicites sur la nouvelle ligne après undefined
return
. Les choses suivantes fonctionnent cependant comme vous vous en doutez:
return {
id : 1234,
title : 'Tony the Pony'
};
Pire encore, celui-ci fonctionne également (dans Chrome, au moins):
return /*
*/{
id : 1234,
title : 'Tony the Pony'
};
Voici une variante du même problème qui ne génère pas d'erreur de syntaxe, échoue silencieusement:
return
2 + 2;
Table de vérité 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
Source: Doug Crockford
==
sert le concepteur de langage?
==
avait le sens de ===
, et puis il y avait un autre opérateur, quelque chose comme ~=
ça permettait la contrainte de type.
Trigraphes en C et C ++.
int main() {
printf("LOL??!");
}
Cela s'imprimera LOL|
, car le trigraphe ??!
est converti en |
.
Amusant avec la boxe automatique et le cache d'entiers 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 rapide coup d'œil au code source Java se présente comme suit:
/**
* 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);
}
Remarque: par IntegerCache.high
défaut, 127
sauf si défini par une propriété.
Ce qui se passe avec la boxe automatique, c'est qu'à la fois foo et bar le même objet entier récupéré du cache à moins qu'il ne soit explicitement créé: par exemple foo = new Integer(42)
, lors de la comparaison de l'égalité de référence, ils seront vrais plutôt que faux. La bonne façon de comparer la valeur entière utilise.equals;
Citant Neil Fraser (regardez à la fin de cette page),
try {
return true;
} finally {
return false;
}
(en Java, mais le comportement est apparemment le même en JavaScript et en Python). Le résultat est laissé au lecteur comme exercice.
ÉDITÉ: Tant que nous sommes sur le sujet, considérez également ceci:
try {
throw new AssertionError();
} finally {
return false;
}
Control cannot leave the body of a finally clause
return
dans la finally
clause.
APL (autre que TOUS), la possibilité d'écrire n'importe quel programme sur une seule ligne.
par exemple Game of Life de Conway en une seule ligne dans APL :
texte de remplacement http://catpad.net/michael/APLLife.gif
Si cette ligne n'est pas WTF, alors rien ne l'est!
Et voici une vidéo
Les choses étranges que les modèles C ++ peuvent être utilisées, le mieux est démontré par les "littéraux analogiques multidimensionnels" qui utilisent des modèles pour calculer la zone des formes "dessinées". Le code suivant est C ++ valide pour un rectangle 3x3
#include"analogliterals.hpp"
using namespace analog_literals::symbols;
unsigned int c = ( o-----o
| !
! !
! !
o-----o ).area;
Ou, un autre exemple avec un cube 3D:
assert( ( o-------------o
|L \
| L \
| L \
| o-------------o
| ! !
! ! !
o | !
L | !
L | !
L| !
o-------------o ).volume == ( o-------------o
| !
! !
! !
o-------------o ).area * int(I-------------I) );
Les nombreuses variables intégrées de Perl:
$#
- pas un commentaire!$0
,, $$
et $?
- tout comme les variables shell du même nom$ˋ
, $&
Et $'
- variables d'appariement étranges$"
et $,
- variables étranges pour les séparateurs de liste et de champ de sortie$!
- comme errno
un nombre mais strerror(errno)
comme une chaîne$_
- la variable furtive, toujours utilisée et jamais vue$#_
- numéro d'index du dernier argument du sous-programme ... peut-être@_
- les (non) noms de la fonction courante ... peut-être$@
- la dernière exception levée%::
- la table des symboles$:
, $^
, $~
, $-
Et $=
- quelque chose à faire avec les formats de sortie$.
et $%
- numéro de ligne d'entrée, numéro de page de sortie$/
et $\
- séparateurs d'enregistrements d'entrée et de sortie$|
- contrôleur de tampon de sortie$[
- changez votre base de baies de 0 à 1 à 42: WHEEE!$}
- rien du tout, curieusement!$<
, $>
, $(
, $)
- UID et GID réels et efficaces@ISA
- noms des superclasses directes du paquet courant$^T
- temps de démarrage du script en secondes d'époque$^O
- nom du système d'exploitation actuel$^V
- de quelle version de Perl s'agit-ilIl y a beaucoup plus d'où cela vient. Lisez la liste complète ici .
$[
variable est la plus mauvaise de toutes.
perldoc perlvar
toutes les cinq secondes. (Bien que j'avoue que la moitié du temps je le vérifie en pensant "Je sais qu'il y a une variable spéciale qui peut le faire pour moi, je ne me souviens juste pas laquelle ..." = P)
use English;
est qu'il affecte les performances de RegExp. Je ne l'invente pas. perldoc.perl.org/English.html#PERFORMANCE
/$foo[bar]/
, la [bar]
pièce est-elle une classe de caractères ou un indice du tableau @foo
? Grep perldata pour la réponse terrifiante.
Gestion par PHP des valeurs numériques dans les chaînes . Voir cette réponse précédente à une autre question pour plus de détails mais, en bref:
"01a4" != "001a4"
Si vous avez deux chaînes qui contiennent un nombre différent de caractères, elles ne peuvent pas être considérées comme égales. Les zéros en tête sont importants car ce sont des chaînes et non des nombres.
"01e4" == "001e4"
PHP n'aime pas les chaînes. Il cherche toutes les excuses qu'il peut trouver pour traiter vos valeurs comme des nombres. Modifiez légèrement les caractères hexadécimaux dans ces chaînes et soudainement PHP décide que ce ne sont plus des chaînes, ce sont des nombres en notation scientifique (PHP ne se soucie pas que vous utilisiez des guillemets) et ils sont équivalents car les zéros de tête sont ignorés pour les nombres. Pour renforcer ce point, vous constaterez que PHP est également évalué "01e4" == "10000"
comme vrai car ce sont des nombres avec des valeurs équivalentes. C'est un comportement documenté, ce n'est tout simplement pas très sensé.
Ayons un vote pour toutes les langues (comme PL / I) qui ont essayé de supprimer les mots réservés.
Où pourriez-vous légalement écrire des expressions amusantes telles que:
IF IF THEN THEN = ELSE ELSE ELSE = THEN
( IF
, THEN
, ELSE
Sont les noms de variables)
ou
IF IF THEN THEN ELSE ELSE
( IF
est une variable THEN
et ELSE
sont des sous-programmes)
La «fonctionnalité» de conversion octale JavaScript est une bonne chose à savoir:
parseInt('06') // 6
parseInt('07') // 7
parseInt('08') // 0
parseInt('09') // 0
parseInt('10') // 10
Plus de détails ici .
En C, on peut entrelacer un do / while avec une instruction switch. Voici un exemple de memcpy utilisant cette méthode:
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
à-d. à la fin est un JMP
retour (conditionnel) à lado
, ce qui explique pourquoi vous pouvez ignorer le do
et toujours vous retrouver dans la boucle.
Algol passe par nom (illustré en utilisant la syntaxe 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
Pas un WTF, mais une fonctionnalité utile.
(10 > 5 > 1) != ((10 > 5) > 1)
en Python.
(funct_a(5)+5 > b > funct_a(5))
n'appelle funct_a(5)
qu'une seule fois. C'est une GRANDE fonctionnalité!
funct_a
sera appelé deux fois dans cet exemple. Dans b > funct_a(5) > c
ce ne sera appelée une fois que, par opposition à b > funct_a(5) and funct_a(5) > c
.
En Java:
int[] numbers() {
return null;
}
Peut être écrit comme:
int numbers() [] {
return null;
}
const T*
et T const*
sont équivalents, c'est T* const
ce consts le pointeur. De plus, je déteste les polices sans.
numbers()[2]
c'est une déclaration légale.
INTERCAL est probablement le meilleur recueil de fonctionnalités linguistiques les plus étranges. Mon préféré est la déclaration COMEFROM qui est (presque) l'opposé de GOTO.
COMEFROM est à peu près l'opposé de GOTO dans la mesure où il peut prendre l'état d'exécution de n'importe quel point arbitraire du code dans une instruction COMEFROM. Le point dans le code où le transfert d'état se produit est généralement donné comme paramètre à COMEFROM. Que le transfert ait lieu avant ou après l'instruction au point de transfert spécifié dépend de la langue utilisée. Selon le langage utilisé, plusieurs COMEFROM référençant le même point de départ peuvent être invalides, non déterministes, être exécutés dans une sorte de priorité définie, ou même induire une exécution parallèle ou autrement concurrente comme vu dans Threaded Intercal. Un exemple simple d'une instruction "COMEFROM x" est une étiquette x (qui n'a pas besoin d'être physiquement située n'importe où près de son COMEFROM correspondant) qui agit comme une "trappe". Lorsque l'exécution de code atteint l'étiquette, le contrôle est passé à l'instruction suivant COMEFROM. L'effet de ceci est principalement de rendre le débogage (et la compréhension du flux de contrôle du programme) extrêmement difficile, car il n'y a aucune indication près de l'étiquette que le contrôle sautera mystérieusement à un autre point du programme.
PLEASE
assez souvent le modificateur!
Pas vraiment une fonctionnalité de langage, mais une faille d'implémentation: certains des premiers compilateurs Fortran ont implémenté des constantes en utilisant un pool constant. Tous les paramètres ont été transmis par référence. Si vous avez appelé une fonction, par exemple
f(1)
Le compilateur transmettrait l'adresse de la constante 1 dans le pool de constantes à la fonction. Si vous affectiez une valeur au paramètre dans la fonction, vous changeriez la valeur (dans ce cas la valeur de 1) globalement dans le programme. Causé quelques grattements de tête.
2+2
peut alors égaler 5
(pour de très grandes valeurs 2
bien sûr!).
2+2
serait donc égal 5
pour les petites valeurs de 5
).
2 + 2 = 5
; ce sera une erreur de syntaxe. Ce qui sera vrai, c'est 2 + 2 .EQ. 5
.
Je ne sais pas si cela peut être considéré comme une fonctionnalité de langage, mais, en C ++, presque toutes les erreurs de compilation liées aux modèles fournissent quotidiennement une bonne quantité de WTF à de nombreux programmeurs C ++ du monde entier :)
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> >)
Les nombreux espaces de noms de C:
typedef int i;
void foo()
{
struct i {i i;} i;
i: i.i = 3;
printf( "%i\n", i.i);
}
Ou avec des personnages:
typedef char c;
void foo()
{
struct c {c c;} c;
c: c.c = 'c';
printf( "%c\n", c.c);
}
Je dirais que tout l'espace blanc de Python est ma meilleure fonctionnalité WTF. Certes, vous vous y habituez plus ou moins après un certain temps et les éditeurs modernes facilitent la gestion, mais même après le développement de python principalement à temps plein au cours de l'année écoulée, je suis toujours convaincu que c'était une mauvaise idée. J'ai lu tout le raisonnement derrière, mais honnêtement, cela nuit à ma productivité. Pas beaucoup, mais c'est toujours une bavure sous la selle.
edit: à en juger par les commentaires, certaines personnes semblent penser que je n'aime pas mettre en retrait mon code. C'est une évaluation incorrecte. J'ai toujours mis en retrait mon code, quelle que soit la langue et si je suis forcé ou non. Ce que je n'aime pas, c'est que c'est l'indentation qui définit le bloc dans lequel se trouve une ligne de code. Je préfère les délimiteurs explicites pour cela. Entre autres raisons, je trouve que les délimiteurs explicites facilitent la coupe et le collage de code.
Par exemple, si j'ai un bloc en retrait de 4 espaces et que je le colle à la fin d'un bloc en retrait de 8 espaces, mon éditeur (tous les éditeurs?) N'a aucune idée si le code collé appartient au bloc à 8 espaces ou à l'extérieur bloquer. OTOH, si j'ai des délimiteurs explicites, il est évident à quel bloc le code appartient et comment il doit être (ré) indenté - il le fait en recherchant intelligemment les délimiteurs de bloc.
edit 2: certaines personnes qui fournissent des commentaires semblent penser que c'est une fonctionnalité que je déteste ou qui, à mon avis, fait du python un langage pauvre. Encore une fois, ce n'est pas vrai. Bien que je n'aime pas beaucoup ça, c'est à côté de la question. La question porte sur la caractéristique de langage la plus étrange , et je pense que c'est étrange, car il s'agit de quelque chose de très, très peu (mais> 0) de langues.
J'ai un peu lutté à ce sujet:
1;
En perl, les modules doivent retourner quelque chose de vrai .
'Cogito ergo sum';
ce qui, comme tout le monde le sait, est évidemment vrai dans tous les univers possibles. Cela garantit une portabilité maximale."
<?=1;?>
renvoie 1. <?=true;?>
renvoie 1. <?=false;?>
renvoie null.
Je suis surpris que personne n'ait mentionné les constructions de boucle 7 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
Parce que coller un! devant votre conditionnel est bien trop compliqué!
While
et Whend
», car il y a des gens qui prononcent le mot «tandis que» avec l'approximant vélaire labialisé sans voix. Et bien sûr, cela s'aligne mieux et le code qui s'aligne est bien.
Pour ceux qui ne le savent pas, bc
c'est un "langage de calculatrice à précision arbitraire", et je l'utilise assez souvent pour des calculs rapides, en particulier lorsque les nombres impliqués sont importants ( $
est l'invite):
$ bc -lq
12^345
20774466823273785598434446955827049735727869127052322369317059031795\
19704325276892191015329301807037794598378537132233994613616420526484\
93077727371807711237016056649272805971389591721704273857856298577322\
13812114239610682963085721433938547031679267799296826048444696211521\
30457090778409728703018428147734622401526422774317612081074841839507\
864189781700150115308454681772032
bc
est une commande Unix standard depuis longtemps.
Maintenant pour la "fonctionnalité WTF". Cela vient de man bc
(soulignement le mien):
quit : lorsque l'instruction quit est lue, le processeur bc est arrêté, quel que soit l'endroit où se trouve l'instruction quit. Par exemple, "if (0 == 1) quit" entraînera l'arrêt de bc.
halt : L'instruction halt (une extension) est une instruction exécutée qui provoque la fermeture du processeur bc uniquement lors de son exécution. Par exemple, "if (0 == 1) halt" n'entraînera pas l'arrêt de bc car l'arrêt n'est pas exécuté.
bc
avant cela, et je voulais en parler bc
dans mon article en raison des grandes citations de la page de manuel.
echo '[q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq'|dc
(bien que vous le sachiez déjà).
Je me suis toujours demandé pourquoi le programme le plus simple était:
class HelloWorldApp {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Alors que ça pourrait être:
print "Hello World!"
C'est peut-être pour effrayer les étudiants en informatique en premier lieu ...
JavaScript est orienté objet, non? Par conséquent, l'exécution de méthodes sur des chaînes et des nombres littéraux devrait fonctionner. Comme "hello".toUpperCase()
et 3.toString()
. Il s'avère que le second est une erreur de syntaxe, pourquoi? Parce que l'analyseur s'attend à ce qu'un nombre suivi d'un point soit un littéral à virgule flottante. Ce n'est pas le WTF, le WTF est que vous n'avez qu'à ajouter un autre point pour le faire fonctionner:
3..toString()
La raison en est que le littéral 3.
est interprété comme 3.0
, et 3.0.toString()
fonctionne très bien.
3..__add__(4)
). Là encore, je pense que (3).__add__(4)
c'est une façon beaucoup moins endommagée par le cerveau de le faire :)
3.0.toString()
me démange les yeux.
En JavaScript:
2 == [2]
// Even stranger
2 == [[[2]]]
// And down-right nutty
var a = { "abc" : 1 };
a[[[["abc"]]]] === a["abc"]; // this is also true
Heureusement, les gens aimables de stackoverflow.com m'ont expliqué tout cela: pourquoi 2 == [2] en JavaScript?
===
place.
Number(n)
pour faire quelque chose de similaire. Malheureusement, dans nos deux solutions, les ===
pauses = (.
Ma plus grande fonctionnalité la plus détestée est toute syntaxe de fichier de configuration qui inclut une logique conditionnelle. Ce genre de chose est répandu dans le monde Java (Ant, Maven, etc. Vous savez qui vous êtes!).
Vous venez de terminer la programmation en langage ac ** p, avec un débogage limité et un support d'édition limité.
Si vous avez besoin de logique dans votre configuration, l'approche "Pythonic" de codage de la configuration dans un langage réel est bien meilleure.
powerbasic (www.powerbasic.com) inclut la directive du compilateur:
# BLOAT {bloatsize}
cela augmente la taille de l'exécutable compilé en <bloatsize>
octets. cela a été mis dans le compilateur au cas où les personnes créant l'exécutable n'aiment pas la petite taille de l'exécutable généré. cela fait que l'EXE semble plus gros pour rivaliser avec les langages de programmation gonflés :)