Was ist Ihrer Meinung nach das überraschendste, seltsamste, seltsamste oder wirklich "WTF" -Sprachenmerkmal, auf das Sie gestoßen sind?
Bitte nur eine Funktion pro Antwort.
Was ist Ihrer Meinung nach das überraschendste, seltsamste, seltsamste oder wirklich "WTF" -Sprachenmerkmal, auf das Sie gestoßen sind?
Bitte nur eine Funktion pro Antwort.
Antworten:
In C können Arrays folgendermaßen indiziert werden:
a[10]
das ist sehr häufig.
Die weniger bekannte Form (die wirklich funktioniert!) Ist jedoch:
10[a]
was das gleiche wie oben bedeutet.
In JavaScript:
'5' + 3 gives '53'
Wohingegen
'5' - 3 gives 2
+
für String-Verkettung ist schrecklich
In JavaScript das folgende Konstrukt
return
{
id : 1234,
title : 'Tony the Pony'
};
return ist ein Syntaxfehler aufgrund der hinterhältigen impliziten Einfügung von Semikolons in die neue Zeile danach undefined
return
. Folgendes funktioniert jedoch wie erwartet:
return {
id : 1234,
title : 'Tony the Pony'
};
Schlimmer noch, dieses funktioniert auch (zumindest in Chrome):
return /*
*/{
id : 1234,
title : 'Tony the Pony'
};
Hier ist eine Variante desselben Problems, die keinen Syntaxfehler verursacht, sondern nur stillschweigend fehlschlägt:
return
2 + 2;
JavaScript-Wahrheitstabelle:
'' == '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
Quelle: Doug Crockford
==
der Sprachdesigner?
==
es die Bedeutung von hätte ===
, und dann gab es einen anderen Operator, so etwas ~=
erlaubte Typenzwang.
Trigraphen in C und C ++.
int main() {
printf("LOL??!");
}
Dies wird gedruckt LOL|
, da der Trigraph ??!
in konvertiert wird |
.
Spaß mit Auto-Boxing und dem Integer-Cache in 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
Ein kurzer Blick auf den Java-Quellcode zeigt Folgendes:
/**
* 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);
}
Hinweis: Der IntegerCache.high
Standardwert ist, 127
sofern nicht durch eine Eigenschaft festgelegt.
Was beim automatischen Boxen passiert, ist, dass sowohl foo als auch bar dasselbe ganzzahlige Objekt aus dem Cache abrufen, sofern es nicht explizit erstellt wurde: foo = new Integer(42)
Wenn Sie also beispielsweise die Referenzgleichheit vergleichen, sind sie eher wahr als falsch. Die richtige Methode zum Vergleichen des Integer-Werts ist die Verwendung.equals;
Zitat von Neil Fraser (siehe Ende dieser Seite),
try {
return true;
} finally {
return false;
}
(In Java ist das Verhalten in JavaScript und Python anscheinend gleich). Das Ergebnis bleibt dem Leser als Übung überlassen.
EDITIERT: Solange wir uns mit dem Thema befassen, bedenken Sie auch Folgendes:
try {
throw new AssertionError();
} finally {
return false;
}
Control cannot leave the body of a finally clause
return
in finally
Klausel.
APL (außer ALLES), die Fähigkeit, jedes Programm in nur einer Zeile zu schreiben.
zB Conways Spiel des Lebens in einer Zeile in APL :
Alternativtext http://catpad.net/michael/APLLife.gif
Wenn diese Zeile nicht WTF ist, dann ist nichts!
Und hier ist ein Video
Die seltsamen Dinge, für die C ++ - Vorlagen verwendet werden können, werden am besten durch "Multi-Dimensional Analog Literals" demonstriert, die Vorlagen verwenden, um den Bereich "gezeichneter" Formen zu berechnen. Der folgende Code ist in C ++ für ein 3x3-Rechteck gültig
#include"analogliterals.hpp"
using namespace analog_literals::symbols;
unsigned int c = ( o-----o
| !
! !
! !
o-----o ).area;
Oder ein anderes Beispiel mit einem 3D-Würfel:
assert( ( o-------------o
|L \
| L \
| L \
| o-------------o
| ! !
! ! !
o | !
L | !
L | !
L| !
o-------------o ).volume == ( o-------------o
| !
! !
! !
o-------------o ).area * int(I-------------I) );
Perls viele integrierte Variablen:
$#
- kein Kommentar!$0
,, $$
und $?
- genau wie die gleichnamigen Shell-Variablen$ˋ
, $&
Und $'
- seltsam passende Variablen$"
und $,
- seltsame Variablen für Listen- und Ausgabefeldtrennzeichen$!
- wie errno
als Zahl, aber strerror(errno)
als Zeichenfolge$_
- die Stealth-Variable, immer verwendet und nie gesehen$#_
- Indexnummer des letzten Unterprogrammarguments ... vielleicht@_
- die (Nicht-) Namen der aktuellen Funktion ... vielleicht$@
- die letzte Ausnahme%::
- die Symboltabelle$:
, $^
, $~
, $-
, Und $=
- etwas mit Ausgabeformaten zu tun$.
und $%
- Eingabezeilennummer, Ausgabeseitennummer$/
und $\
- Trennzeichen für Eingabe- und Ausgabedatensätze$|
- Ausgangspufferregler$[
- Ändern Sie Ihre Array-Basis von 0-basiert auf 1-basiert auf 42-basiert: WHEEE!$}
- Seltsamerweise gar nichts!$<
, $>
, $(
, $)
- reale und effektive UIDs und GIDs@ISA
- Namen der direkten Superklassen des aktuellen Pakets$^T
- Startzeit des Skripts in Sekunden$^O
- aktueller Name des Betriebssystems$^V
- Welche Version von Perl ist das?Es gibt noch viel mehr, woher diese kamen. Lesen Sie die komplette Liste hier .
$[
Variable ist die böseste von allen.
perldoc perlvar
alle fünf Sekunden nachsehen zu müssen. (Obwohl ich gestehe, dass ich die Hälfte der Zeit, in der ich es überprüfe, denke: "Ich weiß, dass es eine spezielle Variable gibt, die dies für mich tun kann, ich erinnere mich nur nicht, welche ..." = P)
use English;
ist, dass es die RegExp-Leistung beeinträchtigt. Ich mache das nicht nach. perldoc.perl.org/English.html#PERFORMANCE
/$foo[bar]/
der [bar]
Teil beispielsweise eine Zeichenklasse oder ein Index des Arrays @foo
? Grep perldata für die erschreckende Antwort.
PHPs Umgang mit numerischen Werten in Strings . In dieser vorherigen Antwort auf eine andere Frage finden Sie ausführliche Informationen, aber kurz gesagt:
"01a4" != "001a4"
Wenn Sie zwei Zeichenfolgen haben, die eine unterschiedliche Anzahl von Zeichen enthalten, können diese nicht als gleich angesehen werden. Die führenden Nullen sind wichtig, da dies Zeichenfolgen und keine Zahlen sind.
"01e4" == "001e4"
PHP mag keine Strings. Es sucht nach einer Entschuldigung, die es finden kann, um Ihre Werte als Zahlen zu behandeln. Ändern Sie die hexadezimalen Zeichen in diesen Zeichenfolgen geringfügig, und plötzlich entscheidet PHP, dass dies keine Zeichenfolgen mehr sind. Es handelt sich um Zahlen in wissenschaftlicher Notation (PHP kümmert sich nicht darum, dass Sie Anführungszeichen verwenden), und sie sind äquivalent, da führende Nullen für Zahlen ignoriert werden. Um diesen Punkt zu verstärken, werden Sie feststellen, dass PHP auch "01e4" == "10000"
als wahr ausgewertet wird , da dies Zahlen mit äquivalenten Werten sind. Dies ist dokumentiertes Verhalten, es ist einfach nicht sehr sinnvoll.
Lassen Sie uns für alle Sprachen (wie PL / I) abstimmen, die versucht haben, reservierte Wörter zu beseitigen.
Wo sonst könnten Sie legal so amüsante Ausdrücke schreiben wie:
IF IF THEN THEN = ELSE ELSE ELSE = THEN
( IF
, THEN
,ELSE
Sind Variablennamen)
oder
IF IF THEN THEN ELSE ELSE
( IF
ist eine Variable THEN
und ELSE
sind Unterprogramme)
Die Funktion zur oktalen JavaScript-Konvertierung ist gut zu kennen:
parseInt('06') // 6
parseInt('07') // 7
parseInt('08') // 0
parseInt('09') // 0
parseInt('10') // 10
Weitere Details hier .
In C kann man ein do / while mit einer switch-Anweisung verschachteln. Hier ein Beispiel für ein Memcpy mit dieser Methode:
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
am Ende ist ein (bedingtes) JMP
Zurück zum do
, was erklärt, warum Sie das überspringen können do
und trotzdem in der Schleife landen.
Algol-Pass-by-Name (dargestellt mit C-Syntax):
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]; } }); }
?
In Python:
>>> x=5
>>> 1<x<10
True
>>> 1<x<3
False
Kein WTF, aber eine nützliche Funktion.
(10 > 5 > 1) != ((10 > 5) > 1)
in Python.
(funct_a(5)+5 > b > funct_a(5))
nur funct_a(5)
einmal aufgerufen wird. Es ist eine großartige Funktion!
funct_a
wird in diesem Beispiel zweimal aufgerufen. In wird b > funct_a(5) > c
es aber nur einmal aufgerufen, im Gegensatz zu b > funct_a(5) and funct_a(5) > c
.
In Java:
int[] numbers() {
return null;
}
Kann geschrieben werden als:
int numbers() [] {
return null;
}
const T*
und T const*
äquivalent, es ist das T* const
, was den Zeiger konstituiert. Außerdem hasse ich ohne Schriftarten.
numbers()[2]
ist eine rechtliche Erklärung.
INTERCAL ist wahrscheinlich das beste Kompendium der seltsamsten Sprachfunktionen. Mein persönlicher Favorit ist das COMEFROM Aussage, die (fast) das Gegenteil von GOTO ist.
COMEFROM ist insofern das Gegenteil von GOTO, als es den Ausführungsstatus von einem beliebigen Punkt im Code in eine COMEFROM-Anweisung übernehmen kann. Der Punkt im Code, an dem die Statusübertragung stattfindet, wird normalerweise als Parameter an COMEFROM übergeben. Ob die Übertragung vor oder nach der Anweisung am angegebenen Übertragungspunkt erfolgt, hängt von der verwendeten Sprache ab. Abhängig von der verwendeten Sprache können mehrere COMEFROMs, die auf denselben Ausgangspunkt verweisen, ungültig sein, nicht deterministisch sein, in einer definierten Priorität ausgeführt werden oder sogar eine parallele oder anderweitig gleichzeitige Ausführung induzieren, wie in Threaded Intercal dargestellt. Ein einfaches Beispiel für eine "COMEFROM x" -Anweisung ist eine Bezeichnung x (die sich nicht physisch in der Nähe des entsprechenden COMEFROM befinden muss), die als "Falltür" fungiert. Wenn die Codeausführung das Label erreicht, wird die Steuerung an die Anweisung nach COMEFROM übergeben. Dies führt in erster Linie dazu, dass das Debuggen (und das Verstehen des Steuerungsflusses des Programms) äußerst schwierig wird, da in der Nähe des Etiketts kein Hinweis darauf angezeigt wird, dass die Steuerung auf mysteriöse Weise zu einem anderen Punkt des Programms springt.
PLEASE
Modifikator nicht oft genug verwenden!
Nicht wirklich eine Sprachfunktion, aber ein Implementierungsfehler: Einige frühe Fortran-Compiler implementierten Konstanten mithilfe eines konstanten Pools. Alle Parameter wurden als Referenz übergeben. Wenn Sie eine Funktion aufgerufen haben, z
f(1)
Der Compiler würde die Adresse der Konstante 1 im Konstantenpool an die Funktion übergeben. Wenn Sie dem Parameter in der Funktion einen Wert zugewiesen haben, würden Sie den Wert (in diesem Fall den Wert 1) global im Programm ändern. Verursachte einige Kopfkratzer.
2+2
kann gleich sein 5
(für sehr große Werte 2
natürlich!).
2+2
würde also 5
für kleine Werte von gleich sein 5
).
2 + 2 = 5
; Das ist ein Syntaxfehler. Was wahr sein wird, ist 2 + 2 .EQ. 5
.
Ich weiß nicht, ob es als Sprachfunktion angesehen werden kann, aber in C ++ liefert fast jeder Compilerfehler in Bezug auf Vorlagen täglich eine ganze Menge WTF an viele C ++ - Programmierer auf der ganzen Welt :)
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> >)
Die vielen Namensräume von C:
typedef int i;
void foo()
{
struct i {i i;} i;
i: i.i = 3;
printf( "%i\n", i.i);
}
Oder mit Charakteren:
typedef char c;
void foo()
{
struct c {c c;} c;
c: c.c = 'c';
printf( "%c\n", c.c);
}
Ich würde sagen, das ganze Whitespace-Ding von Python ist mein größtes WTF-Feature. Zwar gewöhnt man sich nach einer Weile mehr oder weniger daran und moderne Redakteure machen es einfach, damit umzugehen, aber selbst nach der größtenteils Vollzeit-Python-Entwicklung im vergangenen Jahr bin ich immer noch davon überzeugt, dass es eine schlechte Idee war. Ich habe alle Gründe dafür gelesen, aber ehrlich gesagt beeinträchtigt dies meine Produktivität. Nicht viel, aber es ist immer noch ein Grat unter dem Sattel.
edit: Nach den Kommentaren zu urteilen, scheinen einige Leute zu denken, dass ich meinen Code nicht gerne einrücken möchte. Das ist eine falsche Einschätzung. Ich habe meinen Code immer eingerückt, egal in welcher Sprache und ob ich dazu gezwungen bin oder nicht. Was ich nicht mag, ist, dass es der Einzug ist, der definiert, in welchem Block sich eine Codezeile befindet. Ich bevorzuge explizite Trennzeichen dafür. Unter anderem finde ich, dass explizite Trennzeichen das Ausschneiden und Einfügen von Code erleichtern.
Wenn ich beispielsweise einen Block mit 4 Leerzeichen eingerückt und am Ende eines Blocks mit 8 Leerzeichen eingerückt habe, hat mein Editor (alle Editoren?) Keine Ahnung, ob der eingefügte Code zum 8-Leerzeichen-Block oder zum äußeren gehört Block. OTOH, wenn ich explizite Trennzeichen habe, ist es offensichtlich, zu welchem Block der Code gehört und wie er (neu) eingerückt werden sollte - dies geschieht durch intelligente Suche nach Blocktrennzeichen.
edit 2: Einige Leute, die Kommentare abgeben, scheinen zu glauben, dass dies eine Funktion ist, die ich hasse oder die Python meiner Meinung nach zu einer schlechten Sprache macht. Wieder nicht wahr. Ich mag es zwar nicht so sehr, aber das ist nebensächlich. Die Frage bezieht sich auf das seltsamste Sprachmerkmal, und ich finde das seltsam, da es sehr, sehr wenige (aber> 0) Sprachen verwenden.
Ich hatte ein bisschen Probleme damit:
1;
In Perl müssen Module etwas Wahres zurückgeben .
'Cogito ergo sum';
was bekanntlich in allen möglichen Universen selbstverständlich ist. Dies gewährleistet maximale Portabilität."
<?=1;?>
gibt 1 <?=true;?>
zurück <?=false;?>
. Gibt 1 zurück. Gibt null zurück.
Ich bin überrascht, dass niemand die 7- Schleifen-Konstrukte von Visual Basic erwähnt hat .
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
Weil ein! vor Ihrer Bedingung ist viel zu kompliziert!
While
und Whend
" schaffen sollen, da es einige Leute gibt, die das Wort "während" mit dem stimmlosen labialisierten Velar-Approximanten aussprechen. Und natürlich ist es besser in einer Reihe, und der Code, der in einer Reihe steht, ist schön.
Für diejenigen, die nicht wissen, bc
ist es eine "willkürliche Präzisionsrechnersprache", und ich benutze sie ziemlich oft für schnelle Berechnungen, insbesondere wenn die beteiligten Zahlen groß sind ( $
ist die Eingabeaufforderung):
$ bc -lq
12^345
20774466823273785598434446955827049735727869127052322369317059031795\
19704325276892191015329301807037794598378537132233994613616420526484\
93077727371807711237016056649272805971389591721704273857856298577322\
13812114239610682963085721433938547031679267799296826048444696211521\
30457090778409728703018428147734622401526422774317612081074841839507\
864189781700150115308454681772032
bc
ist seit langem ein Standard-Unix-Befehl .
Nun zur "WTF-Funktion". Das ist vonman bc
(Schwerpunkt meiner):
Verlassen : Wenn die quit-Anweisung gelesen wird, wird der bc-Prozessor beendet, unabhängig davon, wo sich die quit-Anweisung befindet. Beispiel: "if (0 == 1) quit" führt dazu, dass bc beendet wird.
halt : Die halt-Anweisung (eine Erweiterung) ist eine ausgeführte Anweisung, die bewirkt, dass der bc-Prozessor nur beendet wird, wenn er ausgeführt wird. Beispiel: "if (0 == 1) halt" führt nicht dazu, dass bc beendet wird, da der Halt nicht ausgeführt wird.
bc
und wollte bc
wegen der tollen Zitate auf der Manpage in meinem Beitrag darüber schreiben .
echo '[q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq'|dc
(obwohl du das vielleicht schon weißt).
Ich habe mich immer gefragt, warum das einfachste Programm ist:
class HelloWorldApp {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Während es sein könnte:
print "Hello World!"
Vielleicht, um Informatikstudenten überhaupt zu erschrecken ...
JavaScript ist objektorientiert, oder? Daher sollten Ausführungsmethoden für Literalzeichenfolgen und -zahlen funktionieren. Wie "hello".toUpperCase()
und 3.toString()
. Es stellt sich heraus, dass der zweite ein Syntaxfehler ist. Warum? Weil der Parser erwartet, dass eine Zahl gefolgt von einem Punkt ein Gleitkomma-Literal ist. Das ist nicht die WTF, die WTF ist, dass Sie nur einen weiteren Punkt hinzufügen müssen, damit es funktioniert:
3..toString()
Der Grund ist, dass das Literal 3.
als interpretiert 3.0
wird und gut 3.0.toString()
funktioniert.
3..__add__(4)
). (3).__add__(4)
3.0.toString()
macht meine Augen jucken.
In JavaScript:
2 == [2]
// Even stranger
2 == [[[2]]]
// And down-right nutty
var a = { "abc" : 1 };
a[[[["abc"]]]] === a["abc"]; // this is also true
Zum Glück haben mir die freundlichen Leute von stackoverflow.com das Ganze erklärt: Warum ist 2 == [2] in JavaScript?
===
stattdessen verwenden.
Number(n)
etwas Ähnliches tun. Leider in beiden unserer Lösungen ===
Pausen = (.
Meine am meisten gehasste Funktion ist die Syntax einer Konfigurationsdatei, die bedingte Logik enthält. Diese Art von Dingen ist in der Java-Welt weit verbreitet (Ant, Maven usw. Sie wissen, wer Sie sind!).
Am Ende programmieren Sie nur in der Sprache ac ** p, mit eingeschränktem Debugging und eingeschränkter Editorunterstützung.
Wenn Sie in Ihrer Konfiguration Logik benötigen, ist der "Pythonic" -Ansatz zum Codieren der Konfiguration in einer realen Sprache viel besser.
powerbasic (www.powerbasic.com) enthält die Compiler-Direktive:
# BLOAT {bloatsize}
Dies erhöht die Größe der kompilierten ausführbaren Datei um <bloatsize>
Bytes. Dies wurde in den Compiler gestellt, falls Personen, die die ausführbare Datei erstellen, die geringe Größe der generierten ausführbaren Datei nicht mögen. es lässt die EXE größer erscheinen, um mit aufgeblähten Programmiersprachen zu konkurrieren :)