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

319 Answers 319

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.

Sign up to request clarification or add additional context in comments.

22 Comments

that's because a[10] means *(a+10) ... and 10[a] means *(10+a) :)
Image
Don't forget "Hello World"[i]. Or i["Hello World"]
Or, more usefully, "0123456789abcdef"[x & 0xf]
Image
@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.
@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.
|
1290
votes

In JavaScript:

 '5' + 3 gives '53'

Whereas

 '5' - 3 gives 2

27 Comments

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".
+ for string concatenation is horrible
+ for concat isn't the problem. Weak typing is.
@FogleBird Neither one is really the problem. It's just the combination of the two with inconsistent coercion rules.
So basically, + is concat when a string is involved. Why can't they code something like '123456' - 456 = '123'? That would be interesting.
|
868
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 Comments

Semicolon insertion is one of the most evil parts of JavaScript.
You always run into problems when you design language features around the assumption that your users will mostly be idiots.
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!
Nick Retallack: Because, due to JavaScript's C-like curly brackets & semicolons syntax, it's not apparent at all that newlines are significant.
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.
|
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 Comments

Good thing Javascript has the === operator, then.
So what purpose does == serve in the eyes of the language designer?
@Chris S: I think it's supposed to do what people expect most of the time.
It'd be nice if == had the meaning of ===, and then there was another operator, something like ~= that allowed type coercion.
@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.
|
657
votes

Trigraphs in C and C++.

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

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

24 Comments

Quick! Tell all C /b/ programmers!
Trigraphs are amazing, because you can be sure nobody will -ever- find out what ??! will mean from Google without knowing the name already.
Trigraphs are disabled by default in GCC.
These let you use the "WTF operator": (foo() != ERROR)??!??! cerr << "Error occurred" << endl;
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".
|
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 Comments

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?
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
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 == ?
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).
@Will: C# has some very similar gotchas. See blogs.msdn.com/jmstall/archive/2005/03/06/386064.aspx
|
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 Comments

Thankfully C# doesn't allow such madness... Control cannot leave the body of a finally clause
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.
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
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.
Even if you can't return in a finally what would the following code do: bool x = true; try { return x; } finally { x = false; }
|
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

Comments

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 Comments

While Eelis' analog literals are great, are they a strange language feature, or just a strange way to use a feature?
The real WTF will be the compiler error generated by one of those that is malformed.
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.
Do the ordering of the o's and L's and |'s matter?
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)
|
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 Comments

The $[ variable is the most evil of them all.
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 )
The problem with use English; is that it affects RegExp performance. I am not making this up. perldoc.perl.org/English.html#PERFORMANCE
@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!
@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.
|
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 Comments

Just use === and !==. Which should be used anyway unless a loose type comparison is needed.
@Dykam, if you follow the link to the fuller answer you'll see that I've addressed the use of the === operator.
Weak typing strikes again!
I always knew PHP was a sin. Up until now I didn't realize it was an unforgivable sin :D
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.
|
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 Comments

@Yada Don't you mean octal? Hexadecimal is 0x.
And that's why parseInt takes an (optional) extra argument :).
leading 0 means octal number. since 8 is not a valid octal digit, the result must be 0.
... and parseInt('010') -> 8 just to confuse you.
you should always pass the base parameter when parsing integers. parseInt('08') == 0 whereas parseInt('08', 10) == 8
|
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 Comments

@RoadieRich one group of buffaloes is not explicitly from Buffalo, they are just nondescript buffalo.
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.
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 Comments

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.
Image
@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..
@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.
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.
@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."
|
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 Comments

It's possible in Scala though (def f(j : => int))
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]; } }); }?
Image
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.
Image
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).
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.
|
189
votes

In Python:

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

Not a WTF, but a useful feature.

17 Comments

Geoffrey, it s a feature, and (10 > 5 > 1) != ((10 > 5) > 1) in Python.
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!
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.
What Khelben says actually is surprising, IMHO.
@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.
|
188
votes

In Java:

int[] numbers() {
  return null;
}

Can be written as:

int numbers() [] {
  return null;
}

7 Comments

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".
@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.
@lImbus: Actually, const T* and T const* are equivalent, it's T* const that consts the pointer. Also, I hate sans fonts.
I agree, this isn't that strange if you are a C programmer.
After all, numbers()[2] is a legal statement.
|
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 Comments

Quite evil -- turns labels into GOTOs. Sounds like a language feature hackers would beg for...
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!
Image
@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")
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)
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).
|
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 Comments

Ooh. Then 2+2 can equal 5 (for very large values of 2 of course!).
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.
@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).
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.
In Haskell the following snippet evaluates to 5: "let 2+2=5 in 2+2" :)
|
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 Comments

That's okay, most code related to templates already creates plenty of WTFs around the world.
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!
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.
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> >)
I think this fits here: Check out STLFilt at bdsoft.com/tools/stlfilt.html to make the output readable.
|
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 Comment

It compiles because every one of those i's has an unambiguous namespace due to context.
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 Comments

if it gets in the way of your productivity then your non-python code can't be very readable...
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?
+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.
Image
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.
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.
|
136
votes

I struggled a bit about this:

1;

In perl, modules need to return something true.

5 Comments

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
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).
This is a valid C statement as well, only nothing is returned.
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."
PHP <?=1;?> returns 1. <?=true;?> returns 1. <?=false;?> returns null.
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 Comments

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.
! isn't not in VB, it's "Not". Or is it? Yes, not is not !, but Not.
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.
@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
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.
|
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 Comments

In some languages, "Hello World!" is a valid program.
@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.
@Loadmaster: the implication was that "all code belongs in a class" or "all code belongs in a function" are unnecessary constraints
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.
I love people who think OOP means that everything should be an object.
|
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 Comment

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

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 :)
You can just do (3).toString()
@Gorilla3D: yeah, but that's not a strange language feature, is it?
3.0.toString() makes my eyes itch.
You can use 3 .toString() or (3).toString(), too.
|
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 Comments

That’s why you should use === instead.
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.
@Andrey except that if I ever have to maintain code that does what you suggest, I would very soon wish death upon its author.
@Andrey, that's a great idea! You can also use Number(n) to do something similar. Unfortunately in both of our solutions === breaks =(.
@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.
|
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 Comments

What is this "Pythonic approach" you speak of? Is it writing the config file in python and doing "import MyConfigFile" ?
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.
AMEN. If your configuration or build language is turing complete, you're doing it wrong. I'm looking at you CMake / autotools.
This is exactly what Lua was designed for, originally
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.
|
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 Comments

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.
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.
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).
@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.
1
2 3 4 5
11

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.