972
votes

What is, in your opinion, the most surprising, weird, strange or really "WTF" language feature you have encountered?

Please only one feature per answer.

1
  • 5
    @gablin I think if you combined LISP delimiters with PERL regex using javascript parsing you would cover 90% of the WTF... Commented Sep 19, 2010 at 23:41

320 Answers 320

1
2 3 4 5
11
1854
votes

In C, arrays can be indexed like so:

a[10]

which is very common.

However, the lesser known form (which really does work!) is:

10[a]

which means the same as the above.

22
  • 758
    that's because a[10] means *(a+10) ... and 10[a] means *(10+a) :) Commented Jan 3, 2010 at 14:50
  • 77
    Don't forget "Hello World"[i]. Or i["Hello World"] Commented Jan 3, 2010 at 15:12
  • 167
    Or, more usefully, "0123456789abcdef"[x & 0xf]
    – Dipstick
    Commented Jan 3, 2010 at 15:33
  • 17
    @frunsi: It always works as expected. Pointer addition is not the same as simple integer addition on addresses. It is commutative no matter what size is the type in question. Commented Jan 7, 2010 at 2:23
  • 12
    @mcv - a[10] is the same as "* (a+10)", where the expression "a+10" is pointer arithmetic (and since a is a short, in your example, a + 10 means 'start at a's address, and move 10 shorts, i.e. 20 bytes'). The expression 10[a] is interepreted as "* (10+a)", where "10+a" is also pointer arithmetic, and is treated exactly the same way.
    – Edan Maor
    Commented Jan 12, 2010 at 15:03
1290
votes

In JavaScript:

 '5' + 3 gives '53'

Whereas

 '5' - 3 gives 2
27
  • 81
    I remember when I first started using javascript using this sort of technique to add numbers in strings: "111" - -"222" gives 333 whereas "111" + "222" gives "111222". Commented Jan 3, 2010 at 16:03
  • 112
    + for string concatenation is horrible Commented Jan 3, 2010 at 16:42
  • 416
    + for concat isn't the problem. Weak typing is.
    – FogleBird
    Commented Jan 3, 2010 at 21:18
  • 270
    @FogleBird Neither one is really the problem. It's just the combination of the two with inconsistent coercion rules.
    – TM.
    Commented Jan 3, 2010 at 21:29
  • 70
    So basically, + is concat when a string is involved. Why can't they code something like '123456' - 456 = '123'? That would be interesting.
    – Jimmie Lin
    Commented Jan 4, 2010 at 8:40
869
votes

In JavaScript, the following construct

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

returns undefined is a syntax error due to the sneaky implicit semicolon insertion on the newline after return. The following works as you would expect though:

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

Even worse, this one works as well (in Chrome, at least):

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

Here's a variant of the same issue that does not yield a syntax error, just silently fails:

return
    2 + 2;
22
  • 226
    Semicolon insertion is one of the most evil parts of JavaScript.
    – user240438
    Commented Jan 5, 2010 at 1:17
  • 231
    You always run into problems when you design language features around the assumption that your users will mostly be idiots. Commented Jan 5, 2010 at 6:38
  • 8
    I actually had that problem, being c# developer myself, I put the brace in new line. Took me hours to realize what was the problem. Even when I've solved the issue I didn't know what was the problem until I read your answer! Commented Jan 5, 2010 at 16:30
  • 24
    Nick Retallack: Because, due to JavaScript's C-like curly brackets & semicolons syntax, it's not apparent at all that newlines are significant. Commented Jan 10, 2010 at 15:27
  • 19
    If you're not supposed to use C style when programming in JavaScript, then it was rather perverse of the JavaScript language designers to choose a C-style syntax.
    – Ryan Lundy
    Commented Jan 22, 2010 at 14:55
793
votes

JavaScript truth table:

''        ==   '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

17
  • 237
    Good thing Javascript has the === operator, then.
    – Anonymous
    Commented Jan 4, 2010 at 10:16
  • 65
    So what purpose does == serve in the eyes of the language designer?
    – Chris S
    Commented Jan 4, 2010 at 15:20
  • 14
    @Chris S: I think it's supposed to do what people expect most of the time.
    – cdmckay
    Commented Jan 4, 2010 at 16:26
  • 123
    It'd be nice if == had the meaning of ===, and then there was another operator, something like ~= that allowed type coercion.
    – TM.
    Commented Jan 4, 2010 at 22:39
  • 18
    @Otto Actually, since we're geeking out, his example shows that == is not symmetric. At the moment, I don't seen how commutativity would be specified for a binary relation. Commented Jan 6, 2010 at 21:48
657
votes

Trigraphs in C and C++.

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

This will print LOL|, because the trigraph ??! is converted to |.

24
  • 71
    Quick! Tell all C /b/ programmers! Commented Jan 3, 2010 at 20:39
  • 235
    Trigraphs are amazing, because you can be sure nobody will -ever- find out what ??! will mean from Google without knowing the name already.
    – zaratustra
    Commented Jan 4, 2010 at 4:47
  • 56
    Trigraphs are disabled by default in GCC.
    – sastanin
    Commented Jan 4, 2010 at 21:12
  • 360
    These let you use the "WTF operator": (foo() != ERROR)??!??! cerr << "Error occurred" << endl;
    – user168715
    Commented Jan 4, 2010 at 21:39
  • 57
    Trigraphs were a necessary evil when they were introduced. Some platforms just did not include certain characters key to the language, so it was either "trigraphs" or "you can't have a C compiler period-end-of-statement so go use assembler". Check out Stroustrup's description in "The C++ Programming Language". Commented Jan 5, 2010 at 3:31
573
votes

Fun with auto boxing and the 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

Explanation

A quick peek at the Java source code will turn up the following:

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

Note: IntegerCache.high defaults to 127 unless set by a property.

What happens with auto boxing is that both foo and bar the same integer object retrieved from the cache unless explicitly created: e.g. foo = new Integer(42), thus when comparing reference equality, they will be true rather than false. The proper way of comparing Integer value is using .equals;

26
  • 31
    Took me a couple of seconds to see why... java must keep a pool of Integer instances for values between -128 and 128, otherwise it allocs a new Integer, right?
    – Mike Akers
    Commented Jan 4, 2010 at 20:25
  • 18
    however keep in mind that if you specify new Integer(42) it will not be using the instance from the pool so foo == bar will evaluate to false
    – z -
    Commented Jan 4, 2010 at 20:58
  • 10
    I always use ints instead of Integers if possible, but if I had to use Integers for some reason, should I just use .equals() instead of == ?
    – Tyler
    Commented Jan 5, 2010 at 5:12
  • 10
    I find it more interesting that the programmers of JAVA decided to use an - assumably - modifiable value dubbed IntegerCache.high, but only 1 line ahead, they decide it's better to hardcode the 128 (instead of using IntegerCache.high+1).
    – monokrome
    Commented Jan 6, 2010 at 1:59
  • 87
    @Will: C# has some very similar gotchas. See blogs.msdn.com/jmstall/archive/2005/03/06/386064.aspx Commented Jan 7, 2010 at 11:08
372
votes

Quoting Neil Fraser (look at the end of that page),

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

(in Java, but behaviour is apparently the same in JavaScript and Python). The result is left as an exercise to the reader.

EDITED: As long as we are on the subject consider also this:

try {
    throw new AssertionError();
} finally {
    return false;
}
22
  • 153
    Thankfully C# doesn't allow such madness... Control cannot leave the body of a finally clause
    – Richard Ev
    Commented Jan 5, 2010 at 16:40
  • 64
    This returns, false, does it? It may look like a WTF (and possibly it is one), but I live by the rule: Finally always wins, unless you crash the Machine before. Commented Jan 5, 2010 at 19:01
  • 28
    To be fair, I blame TDWTF's nice explanation for remembering that finally always wins unless you yank the power cord: thedailywtf.com/Articles/My-Tales.aspx Commented Jan 6, 2010 at 2:10
  • 22
    I'm not sure what the code should return in this case. But I'm absolutely sure that you must not put return in finally clause.
    – jfs
    Commented Jan 6, 2010 at 20:31
  • 11
    Even if you can't return in a finally what would the following code do: bool x = true; try { return x; } finally { x = false; }
    – Chris Lutz
    Commented Jan 11, 2010 at 6:08
324
votes

APL (other than ALL of it), the ability to write any program in just one line.

e.g. Conway's Game of Life in one line in APL:

alt text http://catpad.net/michael/APLLife.gif

If that line isn't WTF, then nothing is!

And here is a video

0
321
votes

The weird things C++ templates can be used for, best demonstrated by "Multi-Dimensional Analog Literals" which uses templates to compute the area of "drawn" shapes. The following code is valid C++ for a 3x3 rectangle

#include"analogliterals.hpp"
using namespace analog_literals::symbols;

          unsigned int c = ( o-----o
                             |     !
                             !     !
                             !     !
                             o-----o ).area;

Or, another example with a 3D cube:

  assert( ( o-------------o
            |L             \
            | L             \
            |  L             \
            |   o-------------o
            |   !             !
            !   !             !
            o   |             !
             L  |             !
              L |             !
               L|             !
                o-------------o ).volume == ( o-------------o
                                              |             !
                                              !             !
                                              !             !
                                              o-------------o ).area * int(I-------------I) );
7
  • 18
    While Eelis' analog literals are great, are they a strange language feature, or just a strange way to use a feature?
    – Roger Pate
    Commented Jan 10, 2010 at 9:02
  • 85
    The real WTF will be the compiler error generated by one of those that is malformed. Commented Jan 20, 2010 at 12:10
  • 6
    How sick is that..wake me up again when there is a version of AnalogLiterals that supports turning the literal around the X, Y and Z axis in Eclipse...now that would give "visual programming" a new real meaning. Commented Aug 17, 2010 at 14:23
  • 2
    Do the ordering of the o's and L's and |'s matter?
    – Ming-Tang
    Commented Sep 4, 2010 at 17:47
  • 4
    The ordering matters, since the templates make creative use of operator overloading.( Don't do this with real code, misusing operators makes code hard to read)
    – josefx
    Commented Jan 14, 2011 at 23:31
291
votes

Perl’s many built-in variables:

  • $#not a comment!
  • $0, $$, and $? — just like the shell variables by the same name
  • , $&, and $' — weird matching variables
  • $" and $, — weird variables for list- and output-field-separators
  • $! — like errno as a number but strerror(errno) as a string
  • $_the stealth variable, always used and never seen
  • $#_ — index number of the last subroutine argument... maybe
  • @_ — the (non)names of the current function... maybe
  • $@ — the last-raised exception
  • %:: — the symbol table
  • $:, $^, $~, $-, and $= — something to do with output formats
  • $. and $% — input line number, output page number
  • $/ and $\ — input and output record separators
  • $| — output buffering controller
  • $[ — change your array base from 0-based to 1-based to 42-based: WHEEE!
  • $}nothing at all, oddly enough!
  • $<, $>, $(, $) — real and effective UIDs and GIDs
  • @ISA — names of current package’s direct superclasses
  • $^T — script start-up time in epoch seconds
  • $^O — current operating system name
  • $^V — what version of Perl this is

There’s a lot more where those came from. Read the complete list here.

23
  • 83
    The $[ variable is the most evil of them all. Commented Jan 4, 2010 at 4:34
  • 24
    Would definitely appreciate it if Perl 6 was something I could code in without having to check perldoc perlvar every five seconds. (Though I confess that half the time I check it thinking "I know there's a special variable that can do this for me, I just don't remember which one..." =P )
    – Chris Lutz
    Commented Jan 4, 2010 at 7:26
  • 17
    The problem with use English; is that it affects RegExp performance. I am not making this up. perldoc.perl.org/English.html#PERFORMANCE
    – David Webb
    Commented Jan 4, 2010 at 13:06
  • 13
    @Dave: it's not a problem because of the -no_match_vars option in the page you linked. @Brad: $[ is SO evil. The intention behind it is evil, yes, but it also doesn't even work! @Artem: from perlvar "Perl identifiers that begin with digits, control characters, or punctuation characters are exempt from the effects of the package declaration and are always forced to be in package main ; they are also exempt from strict 'vars' errors." So that means @$ would be created and assigned to without an error even under stricture. Ugh!
    – rjh
    Commented Jan 5, 2010 at 3:03
  • 4
    @Brian: How do you propose to learn the syntax when the official documentation itself states that there are circumstances where the Perl interpreter heuristically guesses what a sequence of characters means? E.g. in /$foo[bar]/, is the [bar] part a character class or a subscript to the array @foo? Grep perldata for the terrifying answer. Commented Jan 31, 2010 at 8:19
289
votes

PHP's handling of numeric values in strings. See this previous answer to a different question for full details but, in short:

"01a4" != "001a4"

If you have two strings that contain a different number of characters, they can’t be considered equal. The leading zeros are important because these are strings not numbers.

"01e4" == "001e4"

PHP doesn’t like strings. It’s looking for any excuse it can find to treat your values as numbers. Change the hexadecimal characters in those strings slightly and suddenly PHP decides that these aren’t strings any more, they are numbers in scientific notation (PHP doesn’t care that you used quotes) and they are equivalent because leading zeros are ignored for numbers. To reinforce this point you will find that PHP also evaluates "01e4" == "10000" as true because these are numbers with equivalent values. This is documented behaviour, it’s just not very sensible.

13
  • 56
    Just use === and !==. Which should be used anyway unless a loose type comparison is needed.
    – Dykam
    Commented Jan 3, 2010 at 16:52
  • 14
    @Dykam, if you follow the link to the fuller answer you'll see that I've addressed the use of the === operator.
    – Dan Dyer
    Commented Jan 3, 2010 at 17:17
  • 18
    Weak typing strikes again!
    – gillonba
    Commented Jan 6, 2010 at 22:50
  • 43
    I always knew PHP was a sin. Up until now I didn't realize it was an unforgivable sin :D Commented Feb 13, 2010 at 12:08
  • 2
    They should tech people to use === in any programming book or tutorial. Added note: On a badly written PHP app I was able to supply as my password anything that was parsed as the same number.
    – Pepijn
    Commented Jul 21, 2010 at 16:06
281
votes

The JavaScript octal conversion 'feature' is a good one to know about:

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

More details here.

14
  • 10
    @Yada Don't you mean octal? Hexadecimal is 0x.
    – luiscubal
    Commented Jan 6, 2010 at 22:43
  • 48
    And that's why parseInt takes an (optional) extra argument :).
    – LiraNuna
    Commented Jan 7, 2010 at 5:18
  • 10
    leading 0 means octal number. since 8 is not a valid octal digit, the result must be 0.
    – devio
    Commented Jan 7, 2010 at 16:07
  • 22
    ... and parseInt('010') -> 8 just to confuse you. Commented Jan 15, 2010 at 15:33
  • 6
    you should always pass the base parameter when parsing integers. parseInt('08') == 0 whereas parseInt('08', 10) == 8
    – Orr Siloni
    Commented Feb 21, 2010 at 17:33
280
votes

Let's have a vote for all languages (such as PL/I) that tried to do away with reserved words.

Where else could you legally write such amusing expressions as:

IF IF THEN THEN = ELSE ELSE ELSE = THEN

(IF, THEN, ELSE are variable names)

or

IF IF THEN THEN ELSE ELSE

(IF is a variable, THEN and ELSE are subroutines)

2
  • 28
    @RoadieRich one group of buffaloes is not explicitly from Buffalo, they are just nondescript buffalo. Commented Jan 12, 2010 at 2:24
  • 1
    Or FORTRAN, in which there were not only no reserved words, but whitespace was not significant (the END statement was defined as a card with 'E', 'N', and 'D', in that order, and spaces everywhere else). Parsing an IF statement was tricky, since IF( could mean either the start of one of the varieties of IF, or an assignment to the IF array. Commented Feb 18, 2010 at 18:36
213
votes

Duff's device in C!

In C one can interlace a do/while with a switch statement. Here an example of a memcpy using this method:

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);
    }
}
9
  • 9
    Duff's device is probably a good reason for the switch statement not having a break by default ;-) However, I did not yet see any other good use of interlaced switch and loop - but probably there is one. Oh wait, yes, there is another use: coroutines and protothreads.
    – Frunsi
    Commented Jan 7, 2010 at 19:14
  • 16
    @frunsi: "Duff's device is probably a good reason for the switch statement not having a break by default" - Always make the common case the default. I would not exactly say this is the common case.. Commented Jan 19, 2010 at 20:14
  • 6
    @mcv probably easiest if you try to read it as assembly code, i.e. the while at the end is a (conditional) JMP back to the do, which explains why you can skip the do and still end up in the loop.
    – wds
    Commented Jan 22, 2010 at 9:01
  • 14
    Do keep in mind that Duff's Device generally produces WORSE code than the normal looping statement for modern compilers, which know how to (better) loop unrolling than you can do by hand. Commented Feb 8, 2010 at 17:54
  • 37
    @frunsi: Duff himself, publishing it, claimed something like this: "This definitely provides an argument in the discussion whether switch should fall through by default, but I'm not sure if the argument is for or against it."
    – SF.
    Commented Feb 26, 2010 at 13:58
204
votes

Algol pass by name (illustrated using 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]);
}
17
  • 3
    It's possible in Scala though (def f(j : => int))
    – Dario
    Commented Jan 3, 2010 at 20:49
  • 10
    So this is something like ... 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]; } }); }? Commented Jan 5, 2010 at 10:38
  • 2
    It's actually pretty straight-forward: You generate a small piece of code (usually called a "thunk", hence my pun above) that calculates the address resulting from the expression, in this case &a[i]. A pointer to this function is passed to the called function, which then uses it to calculate the current address every time the parameter is accessed. Commented Jan 7, 2010 at 15:55
  • 1
    The traditional thing to do is to pass the array index as an argument as well, instead of making it a global variable, so you can say x = dotproduct(a[i], b[i], i). Commented Jan 7, 2010 at 22:12
  • 2
    This was originally done for things like integration and derivaties. It's indeed poor man's closure. No matter how complex is the expression you pass in, it's reevaluated every time it shows up in the function's text. Think of the fun with side effects! And, if I remember correctly, it was the default method for passing parameters, too. In Algol 68 it was called proceduring and was not default any more, as far as I can recall.
    – user3458
    Commented Aug 20, 2010 at 20:26
189
votes

In Python:

>>> x=5
>>> 1<x<10
True
>>> 1<x<3
False

Not a WTF, but a useful feature.

17
  • 4
    Geoffrey, it s a feature, and (10 > 5 > 1) != ((10 > 5) > 1) in Python.
    – sastanin
    Commented Jan 4, 2010 at 21:18
  • 18
    Also, it evaluates just once, so (funct_a(5)+5 > b > funct_a(5)) only calls funct_a(5) once. It's a GREAT feature!
    – Khelben
    Commented Jan 4, 2010 at 21:45
  • 3
    I was proficient in Python before learning much fortran and C, so this led to a subtle WTF in a piece of C code. That wasn't easy to spot.
    – wisty
    Commented Jan 5, 2010 at 4:53
  • 3
    What Khelben says actually is surprising, IMHO.
    – Tyler
    Commented Jan 5, 2010 at 5:16
  • 57
    @Khelben: No, funct_a will be called twice in that example. In b > funct_a(5) > c it will only be called once though, as opposed to b > funct_a(5) and funct_a(5) > c. Commented Feb 4, 2010 at 6:31
188
votes

In Java:

int[] numbers() {
  return null;
}

Can be written as:

int numbers() [] {
  return null;
}
7
  • 29
    I hate to say this but the WTF one is a consistent extension of the C type system. If C functions were allowed to return arrays then that's what it would look like. The nicer one is a consistency violation to make it more readable. Much like "const char * var" vs "char const * var". Commented Jan 4, 2010 at 22:38
  • 15
    @Adam - It actually makes sense when you consider that variable declaration similarly allows both "int stuff[]" and "int[] stuff". They just let the same rules work for method declaration. Commented Jan 5, 2010 at 0:06
  • 2
    @lImbus: Actually, const T* and T const* are equivalent, it's T* const that consts the pointer. Also, I hate sans fonts. Commented Jan 5, 2010 at 10:42
  • 1
    I agree, this isn't that strange if you are a C programmer. Commented Jan 11, 2010 at 22:22
  • 3
    After all, numbers()[2] is a legal statement.
    – badp
    Commented Feb 9, 2010 at 16:53
184
votes

INTERCAL is probably the best compendium of strangest language features. My personal favourite is the COMEFROM statement which is (almost) the opposite of GOTO.

COMEFROM is roughly the opposite of GOTO in that it can take the execution state from any arbitrary point in code to a COMEFROM statement. The point in code where the state transfer happens is usually given as a parameter to COMEFROM. Whether the transfer happens before or after the instruction at the specified transfer point depends on the language used. Depending on the language used, multiple COMEFROMs referencing the same departure point may be invalid, be non-deterministic, be executed in some sort of defined priority, or even induce parallel or otherwise concurrent execution as seen in Threaded Intercal. A simple example of a "COMEFROM x" statement is a label x (which does not need to be physically located anywhere near its corresponding COMEFROM) that acts as a "trap door". When code execution reaches the label, control gets passed to the statement following the COMEFROM. The effect of this is primarily to make debugging (and understanding the control flow of the program) extremely difficult, since there is no indication near the label that control will mysteriously jump to another point of the program.

10
  • 16
    Quite evil -- turns labels into GOTOs. Sounds like a language feature hackers would beg for...
    – RCIX
    Commented Jan 3, 2010 at 15:52
  • 114
    Ok, but INTERCAL is supposed to be funny - this is not really a surprising "gotcha". INTERCAL compiler can actually refuse to compile the program if you don't use the PLEASE modifier often enough!
    – vgru
    Commented Jan 4, 2010 at 10:54
  • 2
    @alex: that's just in the Threaded-INTERCAL implementation. It's not part of the INTERCAL spec. (I can't help but laugh when I say "INTERCAL spec") Commented Jan 4, 2010 at 20:53
  • 6
    What amazes me most is that in system requirement analysis in the "World of Commercial T. I." , COMEFROMs are actually used in text files describing Use Cases. (seriously: some analysts here delayed a corporate wide migration to OpenOffice instead of MS's Office because the former could not properly reference a "comefrom" with the required granularity in a link)
    – jsbueno
    Commented Jan 6, 2010 at 17:50
  • 5
    Groo: It's worse. Use PLEASE too frequently and it refuses to compile your program because you're grovelling (C-INTERCAL requires between 33% and 66% of statements to have PLEASE modifiers).
    – Vatine
    Commented Jan 7, 2010 at 12:21
160
votes

Not really a language feature, but an implementation flaw: Some early Fortran compilers implemented constants by using a constant pool. All parameters were passed by reference. If you called a function, e.g.

f(1)

The compiler would pass the address of the constant 1 in the constant pool to the function. If you assigned a value to the parameter in the function, you would change the value (in this case the value of 1) globally in the program. Caused some head scratching.

20
  • 124
    Ooh. Then 2+2 can equal 5 (for very large values of 2 of course!). Commented Jan 3, 2010 at 21:14
  • 12
    um, what value of 2 would make "2+2" == "5"? I don't know any integer value 2 can take on for that to be true.
    – Aaron
    Commented Jan 4, 2010 at 21:07
  • 36
    @earlz: I suspect that it would wind up as an integral value, of whatever bit pattern. On the other hand, you could probably set 5 to 4 that way (so 2+2 would equal 5 for small values of 5). Commented Jan 4, 2010 at 22:17
  • 18
    Excuse me, Alok, but this is early FORTRAN we're talking about. It won't be true that 2 + 2 = 5; that'll be a syntax error. What will be true is 2 + 2 .EQ. 5. Commented Jan 6, 2010 at 15:57
  • 3
    In Haskell the following snippet evaluates to 5: "let 2+2=5 in 2+2" :)
    – Tirpen
    Commented Jan 7, 2010 at 13:32
153
votes

Don't know if it can be considered a language feature, but, in C++ almost any compiler error related to templates delivers a fair amount of WTF to many C++ programmers around the world on daily basis :)

9
  • 15
    That's okay, most code related to templates already creates plenty of WTFs around the world. Commented Jan 4, 2010 at 13:31
  • 43
    Oh come now. undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)' Is perfectly readable!
    – Matt Greer
    Commented Jan 4, 2010 at 20:48
  • 10
    I once had a template-related compiler error that was five lines, the shortest of which was seventeen thousand characters (the classic 'no match for x' error, in a deeply templated program). That's the WTF, not the feature in the first place, templates are wonderful. Commented Jan 5, 2010 at 11:26
  • 111
    Even if there's no error, try finding which functions take the longest with your profiler. Oh look, it's 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> >)
    – rlbond
    Commented Jan 5, 2010 at 17:24
  • 12
    I think this fits here: Check out STLFilt at bdsoft.com/tools/stlfilt.html to make the output readable.
    – foraidt
    Commented Jan 6, 2010 at 9:58
150
votes

The many name spaces of C:

typedef int i;

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

Or with characters:

typedef char c;

void foo()
{
    struct c {c c;} c;
    c: c.c = 'c';
    printf( "%c\n", c.c);
}
1
  • 11
    It compiles because every one of those i's has an unambiguous namespace due to context. Commented Jan 6, 2010 at 9:31
149
votes

I would say the whole whitespace thing of Python is my greatest WTF feature. True, you more-or-less get used to it after a while and modern editors make it easy to deal with, but even after mostly full time python development for the past year I'm still convinced it was a Bad Idea. I've read all the reasoning behind it but honestly, it gets in the way of my productivity. Not by much, but it's still a burr under the saddle.

edit: judging by the comments, some people seem to think I don't like to indent my code. That is an incorrect assessment. 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.

51
  • 63
    if it gets in the way of your productivity then your non-python code can't be very readable...
    – Tor Valamo
    Commented Jan 3, 2010 at 15:36
  • 27
    What language did you use before Python? How were you able to work with other people and not indent that language? How could anyone put up with non-indented code in any language? Did you work in a room full of geniuses who didn't need visual cues in the source code?
    – S.Lott
    Commented Jan 3, 2010 at 16:21
  • 53
    +1 Couldn't agree more, if my editor (Emacs) can't indent my code based on something distinct (like braces/begin, end/you name it) automatically, it's seriously silly. Pretty much any refactoring you'd do on a "bigger" function can be a really bad experience.
    – Dmitry
    Commented Jan 3, 2010 at 16:43
  • 83
    Here's the deal - with any other language, I can highlight a block of code and have it indented properly by any editor. But because whitespace IS by definition the proper indenting, you lose that ability in Python. So it's harder to move code around or refactor things. And for the person who claims the OP is the "first person to claim it was a problem", well I had to maintain some python code for a while and I will now use any language over python for this very reason. Commented Jan 3, 2010 at 21:39
  • 38
    I don't mind the whitespace in Python. The WTF is that it's not enforced consistently. You can mix indent levels and tabs, so long as they're consistent with their siblings. So the first indent level can be one space, and the second can be two TABs, and this is not a syntax error.
    – ieure
    Commented Jan 4, 2010 at 20:51
136
votes

I struggled a bit about this:

1;

In perl, modules need to return something true.

5
  • 29
    Some modules may return values based on runtime operations. If you always return true, you still don't have to be uncreative about it: returnvalues.useperl.at
    – Anonymous
    Commented Jan 4, 2010 at 10:06
  • 8
    If my Perl memory serves me correctly, returning true from a module indicated that the module loaded successfully. Returning a false value meant that something went wrong and would prevent the program from running (if not caught). Commented Jan 5, 2010 at 0:28
  • This is a valid C statement as well, only nothing is returned.
    – sigjuice
    Commented Jan 6, 2010 at 12:53
  • 24
    Mark Dominus wrote, "I have very rarely used 'Cogito ergo sum'; which as everyone knows is self-evidently true in all possible universes. This ensures maximum portability."
    – Greg Bacon
    Commented Jan 27, 2010 at 3:50
  • PHP <?=1;?> returns 1. <?=true;?> returns 1. <?=false;?> returns null. Commented Jun 11, 2010 at 4:39
134
votes

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!

6
  • 47
    They should have made it "While and Whend", since there are some people who do pronounce the word "while" with the voiceless labialised velar approximant. And of course it lines up nicer, and code that lines up is nice.
    – dreamlax
    Commented Jan 4, 2010 at 21:06
  • 61
    ! isn't not in VB, it's "Not". Or is it? Yes, not is not !, but Not.
    – brianary
    Commented Jan 5, 2010 at 0:29
  • 7
    Yes, "Wend" is an English word, meaning to go or proceed along some course or way (google.com/search?q=define%3A+wend). I'm not sure if that helps or hurts.
    – Michael Myers
    Commented Jan 5, 2010 at 15:44
  • 3
    @mmyers: "wend" in VB and "wend" in English have two very different definitions. VB's "wend" means "repeat" or "go again", but "wend" in English doesn't include any sort of repetition at all. If anything, I think Wend should have been a replacement for goto. On Error Wend FixIt
    – dreamlax
    Commented Jan 6, 2010 at 3:05
  • BBC Basic had Repeat Until, While Wend and For Next. Wend is BASIC for "End While" from an era when the parser couldn't cope with two-word statements. Commented Jan 15, 2010 at 15:39
134
votes

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 ...

22
  • 34
    In some languages, "Hello World!" is a valid program. Commented Jan 4, 2010 at 20:16
  • 31
    @SoMoS: in most dynamic languages such as Python, Ruby, or Perl print "Hello World!" or some minor variation (e.g. puts instead of print) is a valid and complete program.
    – Dave Kirby
    Commented Jan 4, 2010 at 20:44
  • 36
    @Loadmaster: the implication was that "all code belongs in a class" or "all code belongs in a function" are unnecessary constraints
    – Jimmy
    Commented Jan 5, 2010 at 1:22
  • 19
    Just because a language enforces the use of objects, does not mean it is being used for proper object-oriented programming. It is perfectly possible to program procedurally in Java or C#. That's what static methods are for.
    – jdmichal
    Commented Jan 5, 2010 at 15:28
  • 68
    I love people who think OOP means that everything should be an object.
    – Tor Valamo
    Commented Jan 6, 2010 at 13:58
133
votes

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.

1
  • quit should be renamed to exit, and then this makes sense. I feel like language features were added ad-hoc, and then to keep backward compatibility, names weren't changed. Commented Jan 12, 2010 at 5:00
131
votes

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.

6
  • 8
    Works this way in Python too (try 3..__add__(4)). Then again I think (3).__add__(4) is a much less brain damaged way to do it :)
    – badp
    Commented Jul 21, 2010 at 11:32
  • 49
    You can just do (3).toString() Commented Jul 21, 2010 at 16:57
  • 13
    @Gorilla3D: yeah, but that's not a strange language feature, is it?
    – Theo
    Commented Jul 25, 2010 at 16:58
  • 25
    3.0.toString() makes my eyes itch.
    – Ben Blank
    Commented Oct 13, 2010 at 20:43
  • 2
    You can use 3 .toString() or (3).toString(), too.
    – user492203
    Commented Jan 30, 2011 at 18:02
129
votes

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?

6
  • 6
    That’s why you should use === instead.
    – Gumbo
    Commented Jan 4, 2010 at 21:00
  • 10
    This is useful btw, if you have a function that returns a number and you want to return some additional metadata with it, you can return [number] with some additional fields added. Simple code will never know it is not a real number, and other code can get the required metadata. Commented Jan 5, 2010 at 0:28
  • 36
    @Andrey except that if I ever have to maintain code that does what you suggest, I would very soon wish death upon its author.
    – Breton
    Commented Jan 5, 2010 at 6:45
  • @Andrey, that's a great idea! You can also use Number(n) to do something similar. Unfortunately in both of our solutions === breaks =(.
    – Xavi
    Commented Jan 5, 2010 at 14:50
  • @Breton unfortunately there was once a use for that, when two Array wrappers wanted to pass information between each other while staying within Array contract when only one was applied. Commented Jan 7, 2010 at 11:27
126
votes

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 a c**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.

7
  • What is this "Pythonic approach" you speak of? Is it writing the config file in python and doing "import MyConfigFile" ?
    – phkahler
    Commented Jan 5, 2010 at 14:49
  • 24
    Tcl re-invented that long before Python was born and Lisp invented it before that. So let's not call it Pythonic, let's call it Emacs-ish.
    – slebetman
    Commented Jan 7, 2010 at 1:55
  • 30
    AMEN. If your configuration or build language is turing complete, you're doing it wrong. I'm looking at you CMake / autotools. Commented Jan 7, 2010 at 15:40
  • 16
    This is exactly what Lua was designed for, originally
    – Cogwheel
    Commented Jan 18, 2010 at 23:00
  • 1
    Well, if your code is in Python, then having your configuration file be a Python file is a great idea, because you then just import the file and read the attributes of the module. And you get the 100% Turing Complete power of Python in your config file.
    – asmeurer
    Commented Jan 14, 2011 at 4:20
113
votes

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

# BLOAT {bloatsize}

this increases the size of the compiled executable by <bloatsize> 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:)

4
  • 9
    Haha yuk. I've heard about developers deliberately slowing down some operations (e.g. a search) because it helps people believe that it is really doing something. Similar thing I guess.
    – David
    Commented Jan 7, 2010 at 4:49
  • 42
    This reminds me of something I read recently. They were testing an FPS and decided to increase the number of hit points the bad guys had. Then they asked the testers how they AI was, and they swore it was much smarter. But the AI hadn't changed, just the hit points. People have a certain narrative about the world in their heads, and if you understand and match their expectations they will just assume it validates their narrative.
    – Nate C-K
    Commented Jan 7, 2010 at 17:42
  • 3
    Back in school we had 80286 machines and I actually had to write some screen output routines in assembly to get a reasonable speed (i.e. not crawling).
    – berkus
    Commented Nov 18, 2010 at 13:36
  • 7
    @Nate C-K, if the AI lives long enough to show off its AI, it may actually be smarter, whereas before it may have died too quickly to prove it.
    – zzzzBov
    Commented Feb 3, 2011 at 20:38
1
2 3 4 5
11

Not the answer you're looking for? Browse other questions tagged or ask your own question.