Merkwürdigste Sprachfunktion

Was ist Ihrer Meinung nach das überraschendste, komischste, merkwürdigste oder wirklich “WTF” -Sprachenmerkmal, auf das Sie gestoßen sind?

Bitte nur eine function pro Antwort.

   

In C können Arrays wie folgt indiziert werden:

a[10] 

Das ist sehr häufig.

Die weniger bekannte Form (die wirklich funktioniert!) Ist jedoch:

 10[a] 

Das bedeutet dasselbe wie oben.

In JavaScript:

  '5' + 3 gives '53' 

Wohingegen

  '5' - 3 gives 2 

In JavaScript das folgende Konstrukt

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

returns undefined ist ein Syntaxerrors aufgrund der hinterhältigen impliziten Semikolon-Einfügung auf dem Zeilenumbruch nach der return . Das Folgende funktioniert wie erwartet:

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

Schlimmer noch, das funktioniert auch (zumindest in Chrome):

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

Hier ist eine Variante des gleichen Problems, die keinen Syntaxerrors ergibt, sondern einfach nur 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

Trigraphen in C und C ++.

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

Dadurch wird LOL| gedruckt , weil der Trigraph ??! wird in | .

Spaß mit Auto-Boxen 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 

Erläuterung

Ein kurzer Blick auf den Java-Quellcode zeigt folgendes:

 /** * Returns a Integer instance representing the specified * int value. * If a new Integer 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 int value. * @return a Integer instance representing i. * @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: IntegerCache.high standardmäßig auf 127 sofern es nicht durch eine Eigenschaft festgelegt wird.

Was beim automatischen Boxen passiert, ist, dass foo und bar das gleiche Integer-Objekt aus dem Cache abrufen, wenn es nicht explizit erzeugt wird: zB foo = new Integer(42) , daher werden sie beim Vergleich der Referenzgleichheit wahr und nicht falsch sein. Die richtige Methode zum Vergleichen von Integer-Werten ist die Verwendung von .equals;

Neil Fraser zitierend (sieh das Ende dieser Seite an),

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

(in Java, aber das Verhalten ist anscheinend in JavaScript und Python identisch). Das Ergebnis bleibt dem Leser als Übung überlassen.

BEARBEITET: So lange wir das Thema behandeln, bedenke auch folgendes:

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

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 :

Alt Text http://sofde.miximages.com/language-agnostic/APLLife.gif

Wenn diese Linie 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 von “gezeichneten” Formen zu berechnen. Der folgende Code ist C ++ für ein 3×3-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 eingebaute Variablen:

  • $#kein Kommentar!
  • $0 , $$ und $? – Genau wie die Shell-Variablen mit dem gleichen Namen
  • , $& Und $' – seltsame übereinstimmende Variablen
  • $" und $, – seltsame Variablen für Listen- und Ausgabefeld-Separatoren
  • $! – wie errno als Zahl, aber strerror(errno) als String
  • $_die Stealth-Variable, immer benutzt und nie gesehen
  • $#_ – Indexnummer des letzten Unterroutinenarguments … vielleicht
  • @_ – die (Nicht-) Namen der aktuellen function … vielleicht
  • $@ – die zuletzt erhobene Ausnahme
  • %:: – die Symboltabelle
  • $: $^ , $~ , $- und $= – etwas mit Ausgabeformaten zu tun
  • $. und $% – Eingabezeilennummer, Seitenzahl der Ausgabe
  • $/ und $\ – Eingabe- und Ausgabesatztrennzeichen
  • $| – Ausgangspuffersteuerung
  • $[ – Ändern Sie Ihre Array-Basis von 0-basiert zu 1-basiert zu 42-basiert: WHEE!
  • $} – überhaupt nichts, seltsam genug!
  • $< , $> , $( , $) - echte und effektive UIDs und GIDs
  • @ISA - Namen der direkten Superklassen des aktuellen Pakets
  • $^T - Startzeit des Skripts in Epochen Sekunden
  • $^O - aktueller Betriebssystemname
  • $^V - welche Version von Perl ist das?

Es gibt viel mehr, wo diese herkamen. Lesen Sie die vollständige Liste hier .

PHPs Umgang mit numerischen Werten in Strings . Siehe diese vorherige Antwort auf eine andere Frage für alle Details, aber kurz gesagt:

 "01a4" != "001a4" 

Wenn Sie zwei Zeichenfolgen haben, die eine andere Anzahl von Zeichen enthalten, können sie nicht als gleichwertig betrachtet werden. Die führenden Nullen sind wichtig, weil diese Zeichenfolgen keine Zahlen sind.

 "01e4" == "001e4" 

PHP mag keine Zeichenfolgen. Es sucht nach einer Entschuldigung, die es finden kann, um Ihre Werte als Zahlen zu behandeln. Ändern Sie die hexadezimalen Zeichen in diesen Strings leicht und plötzlich entscheidet PHP, dass dies keine Strings mehr sind, sie sind Zahlen in wissenschaftlicher Notation (PHP kümmert sich nicht darum, dass Sie Anführungszeichen verwendet haben) und sie sind äquivalent, weil führende Nullen für Zahlen ignoriert werden. Um diesen Punkt zu "01e4" == "10000" Sie feststellen, dass PHP auch "01e4" == "10000" als wahr bewertet, da dies Zahlen mit äquivalenten Werten sind. Das ist dokumentiertes Verhalten, es ist einfach nicht sehr sinnvoll.

Lassen Sie uns für alle Sprachen (wie PL / I) abstimmen, die mit reservierten Wörtern auskommen wollten.

Wo sonst könntest du solche amüsanten Ausdrücke legal 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 Subroutinen)

Die JavaScript-Oktalkonvertierung ‘Feature’ ist eine gute Information:

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

Mehr Details hier .

Duffs Gerät in C!

In C kann man eine do / while mit einer switch-statement verschachteln. Hier ein Beispiel für ein Memcpy, das diese Methode verwendet:

 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); } } 

Algol nach Namen (illustriert 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]); } 

In Java:

 int[] numbers() { return null; } 

Kann geschrieben werden als:

 int numbers() [] { return null; } 

In Python:

 >>> x=5 >>> 1>> 1 

Kein WTF, aber ein nützliches Feature.

INTERCAL ist wahrscheinlich das beste Kompendium der merkwürdigsten Sprachmerkmale. Mein persönlicher Favorit ist die COMEFROM- statement, die (fast) das Gegenteil von GOTO ist.

COMEFROM ist in etwa das Gegenteil von GOTO, da es den Ausführungszustand von einem beliebigen Punkt im Code zu einer COMEFROM-statement führen kann. Der Punkt im Code, an dem die Zustandsübertragung stattfindet, wird normalerweise als Parameter für COMEFROM angegeben. Ob die Übertragung vor oder nach dem Befehl am angegebenen Übertragungspunkt stattfindet, hängt von der verwendeten Sprache ab. Abhängig von der verwendeten Sprache können mehrere COMEFROMs, die auf denselben Ausgangspunkt verweisen, ungültig, nicht deterministisch sein, in irgendeiner Art von definierter Priorität ausgeführt werden oder sogar parallele oder in anderer Weise gleichzeitige Ausführung induzieren, wie in Threaded Intercal zu sehen ist. Ein einfaches Beispiel für eine “COMEFROM x” -statement ist eine Kennung x (die nicht in der Nähe ihres entsprechenden COMEFROMs angeordnet sein muss), die als “Falltür” fungiert. Wenn die Codeausführung das Label erreicht, wird die Kontrolle an die statement übergeben, die auf COMEFROM folgt. Der Effekt davon besteht hauptsächlich darin, das Debuggen (und das Verstehen des Steuerflusses des Programms) extrem schwierig zu machen, da es in der Nähe der Markierung keine Anzeige gibt, dass die Steuerung auf mysteriöse Weise zu einem anderen Punkt des Programms springt.

Nicht wirklich ein Sprachfeature, aber ein Implementierungserrors: Einige frühe Fortran-Compiler implementierten Konstanten unter Verwendung eines konstanten Pools. Alle Parameter wurden als Referenz übergeben. Wenn Sie eine function aufgerufen haben, z

 f(1) 

Der Compiler würde die Adresse der Konstanten 1 im Konstantenpool an die function übergeben. Wenn Sie dem Parameter in der function einen Wert zugewiesen haben, würden Sie den Wert (in diesem Fall den Wert 1) global im Programm ändern. Verursacht Kopfkratzen.

Ich weiß nicht, ob es sich um ein Sprachfeature handelt, aber in C ++ liefert fast jeder Compilererrors in Bezug auf Templates täglich eine Menge an WTF für viele C ++ – Programmierer auf der ganzen Welt 🙂

Die vielen Namensräume von C:

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

Oder mit Charakteren:

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

Ich würde sagen, die ganze Whitespace-Sache von Python ist meine größte WTF-function. Natürlich gewöhnt man sich nach einiger Zeit mehr oder weniger daran, und moderne Editoren machen es einfach, sich damit auseinander zu setzen. Aber selbst nach den meisten Vollzeit-Python-Entwicklungen für das vergangene Jahr bin ich immer noch überzeugt, dass es eine schlechte Idee war. Ich habe alle Gedanken dahinter gelesen, aber ehrlich gesagt, es behindert 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 einrücken möchte. Das ist eine falsche Einschätzung. I’ve always indented my code no matter what the language and whether I’m forced to or not. What I don’t like is that it is the indentation that defines what block a line of code is in. I prefer explicit delimiters for that. Among other reasons, I find explicit delimiters makes it easier to cut and paste code.

For example, if I have a block indented 4 spaces and paste it at the end of a block that is indented 8 spaces, my editor (all editors?) have no idea if the pasted code belongs to the 8-space block or the outer block. OTOH, if I have explicit delimiters it’s obvious which block the code belongs to and how it should be (re-)indented — it does so by intelligently looking for block delimiters.

edit 2: some people who provide comments seem to think this is a feature I hate or that I think makes python a poor language. Again, not true. While I don’t like it all that much, that’s beside the point. The question is about the strangest language feature, and I think this is strange, by virtue of it being something very, very few (but >0) languages use.

I struggled a bit about this:

 1; 

In perl, modules need to return something true .

I’m surprised that no one has mentioned Visual Basic’s 7 loop constructs.

 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 

Because sticking an ! in front of your conditional is way too complicated!

For those who don’t know, bc is an “arbitrary precision calculator language”, and I use it quite often for quick calculations, particularly when the numbers involved are large ( $ is the prompt):

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

bc has been a standard Unix command for a long time.

Now for the “WTF feature”. This is from man bc (emphasis mine):

quit : When the quit statement is read, the bc processor is terminated, regardless of where the quit statement is found. For example, “if (0 == 1) quit” will cause bc to terminate.

halt : The halt statement (an extension) is an executed statement that causes the bc processor to quit only when it is executed. For example, “if (0 == 1) halt” will not cause bc to terminate because the halt is not executed.

I always wondered why the simplest program was:

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

Whereas it could be:

 print "Hello World!" 

Maybe this is to frighten computer science students in the first place …

JavaScript is object oriented, right? So running methods on literal strings and numbers should work. Like "hello".toUpperCase() and 3.toString() . Turns out that second one is a syntax error, why? Because the parser expects a number followed by a dot to be a floating point literal. That’s not the WTF, the WTF is that you only have to add another dot to make it work:

 3..toString() 

The reason is that the literal 3. is interpreted as 3.0 , and 3.0.toString() works fine.

In JavaScript:

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

Luckily the kind folks at stackoverflow.com explained the whole thing to me: Why does 2 == [2] in JavaScript?

My biggest most hated feature is any configuration file syntax which includes conditional logic. This sort of thing is rife in the Java world (Ant, Maven, etc. You know who you are!).

You just end up programming in ac**p language, with limited debugging and limited editor support.

If you need logic in your configuration the “Pythonic” approach of coding the configuration in a real language is much much better.

powerbasic (www.powerbasic.com) includes the compiler directive:

 # BLOAT {bloatsize} 

this increases the size of the compiled executable by bytes. this was put in the compiler in case people creating the executable don’t like the small size of the generated executable. it makes the EXE seem bigger to compete with bloated programming languages:)