views:

2784

answers:

29

I'd like to hear some of the more pernicious 'gotchas' that exist out there. Any language, system, or library is fine.

+4  A: 

The doubling up of equality and assignment operators in VB. Most of the time, i'm able to switch back and forth between VB[.NET] and C-like languages without too much friction, but this difference is subtle enough to bite me.

Dim result As Double
Dim auxResult as Double

result = auxResult = input1 * input2 ' D'oh!
Shog9
Whoa! Who writes code like this?!
Konrad Rudolph
@Konrad: Me. But not in VB. Anymore.
Shog9
+1: This one's important to get if you come to VB from a different language. I had a co-worker who wrote `Dim result As Boolean = IIf(boolIsTrue, True, False)` all over the place "just to be safe," because he didn't trust VB's handling of the `=` operator.
Dan Tao
A: 

Perl's $_

The default magic variable. More than once I've been bitten by the ambiguity of what the value contained, or, more importantly, code that was simple before I accommodated a special case thanks to its magic, became much uglier once I unwittingly changed its value.

JasonTrue
Explain how you found it to be a gotcha?
ysth
you can write perfectly functional perl without complex usage of $_. Choose to use $_ only after you know how it behaves.
Jamie
It's not so much that the usage is complex, it's that once you do something slightly more complex, the value of $_ changes as a result of the side effects of other things you are doing. It creates ambiguity.In ruby, I can commit some perlisms, but the culture doesn't encourage such cleverness.
JasonTrue
The only thing that changes $_ in a non-localized fashion is a while(readline(...)) loop, which is implicitly while($_=readline(...)). Is that the problem? Or even things like a grep or map that alias $_ over a limited scope?
ysth
Also, there are places where Perl syntax is ambiguous, but this isn't one of them. I think you mean "confusion" or "doubt", not ambiguity.
ysth
Well, the details are a bit fuzzy since I gave up perl years ago in favor of other alternatives, but my problem wasn't my confusion. The specificity required most languages prevented me from making mistakes that are easy to make (and granted, easy to fix) in perl. I was bitten, not incapacitated.
JasonTrue
s/Perl's $_/Perl/:-)
Orion Edwards
I've liked perl, and been reasonably productive with it, long ago, but I'm happier working with ruby these days.
JasonTrue
+8  A: 

The canonical example is assignment within a comparison expression in C. if (alert_code = red) launch_missles (); and all that. When compilers start warning about using features of a language, is a big sign they shouldn't exist.

John Millikin
A good habit to get into is to always put the constant (or function call) left in a comparison. Ofcourse that only works when you compare against a constant or call - but you'll find that most of the time you do.
RazMaTaz
I wouldn't want to not be able to assign in a condition like that. I think it's worth allowing it but with a compiler warning.
Skilldrick
@Skilldrick, "not allowed" and "allowed with a warning" are the same exact thing in my book. Your code should compile with all not-totally-stupid warnings enabled without any warning.
Andreas Bonini
+1 for that last sentence, hear-hear!
BlueRaja - Danny Pflughoeft
+4  A: 

In .NET the System.Drawing.Bitmap object has a method called "GetHBitmap()" which returns a native GDI HBITMAP object. The code I was maintaining was a dynamic image generator for a web site that would take a product image and dynamically render a "15% off!" medallion or something on the image.

The System.Drawing stuff in .NET 1.1 was half baked, some methods were managed-only, some methods required native HBITMAPs, etc. So he was calling GetHBitmap() and then disposing of the object. Needless to say, this didn't work and the server would crash every few hours. Upon investigation, we found that the GDI Handle Count for the aspnet_wp.exe (ASP.NET worker process) was astronomical (65,000+ versus the normal 500-800).

Upon investigation, the GetHBitmap() function says that you must call the native GDI "DeleteObject()" Win32 API function to release the GDI handle. This function is not available in .NET and you must make a P/Invoke call to call it.

For the non-.NET'ers reading this, it's akin to making a native C call from Java or PHP. Totally non-intuitive.

It took us a few days to track it down. Once the fix was in place, everything worked great! :)

chadmyers
Everything about Bitmap is kinda half baked...
Patrick
+6  A: 

I strongly recommend reading Java Puzzlers. It's the whole book about gotchas. There is a sample chapter on the webpage.

Krzysiek Goj
A: 

Backtracking in Prolog.

JesperE
Programming in Prolog
Ryan
That's not a gotcha, because you know in advance that it is hard.
finnw
-1: why not `walking the callstack on breakpoints on C#`, then? Silly answer.
ANeves
Weird. I don't even remember writing this answer. I blame my evil twin. :-)
JesperE
I remember SWIProlog's debugger and it's call tree and backtracking visualization stuff. Really useful for understanding how prolog works.
pkoch
+2  A: 

The best ones are in C++, it lends itself to beatifull things like:

if(value=comparisson)
{
  //do something with value and wonder 
  //why is it allways 100% equal to comparison
}

C# spoiled all the fun on that one. A little off topic, pointers give out cool things too, even two days ago I had to write this gorgeous piece of code:

level = (int)(*((double *)(void.Ptr())));

The Lisp-like parentheses are the result of paranoia after 30 minutes staring wide eyed at a screen when the simpler level = *(int *)void.Ptr(); was not working.

Caerbanog
A: 

Casting. Especially in weak languages, casting can be one of the biggest gotchas. One of the worst casting situations I ran into (albeit quite rare) was when a string was being cast into a number, but only the first character was being cast into the number. So the string "31" became 3.

Jonathan Arkell
Can you provide an example?
eyelidlessness
An older (and potentially screwey) implementation of JSTL gave the result where the string "31" when compared to a number would cast the 31 to a 3.
Jonathan Arkell
+40  A: 

Auto-boxing in Java:

Integer n = 128;
Integer m = 128;
assert n <= m; // True
assert n >= m; // True
assert n == m; // False

Or anything involving Java's BigDecimals.

EDIT: Actually, this PHP gotcha is probably worse.

Dan Dyer
If something like this went on in my language of choice, I'd have to change languages out of sheer embarassment.
MusiGenesis
Wow, that's pretty evil.
Will
The best bit is that the behaviour is different if you change the value from 128 to 127.
Dan Dyer
@Dan: Why's that? Does Java provide singleton instances for int values up to 127? (Common trick …)
Konrad Rudolph
@Konrad, the JVM specs specify a certain behavior for values under 127. Values above 127 is implementation specific (either unbox or object behavior). See http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1.7
James Schek
Don't quite get it. Explain for a non-Java person?
Kaji
@Kaji: In Java Integer is an object type, but integer literals are of type int (a primitive type). Java 5 introduced automatic conversion between primitives and their object wrapper types. What's happening here is that the two values of 128 are converted into two separate objects with the same value. The == operator, when applied to object types, compares reference equality not values, so they are considered unequal. The <= and >= operators are not defined for reference types, so the values have to be unboxed back to primitives again and are therefore considered equal...
Dan Dyer
...The value 128 is significant because, as James points out, the language spec includes a fudge to ensure that values between -128 and +127 are always converted to the same, cached object.
Dan Dyer
Wow, I did not know this.
fastcodejava
ha ha, funny you add the 'php is worse' edit to dampen this. shows which way you bend.
Yehonatan
@Yehonatan The edit was just to note that I no longer considered this as the worst "gotcha", though it is a bad one. As for which way I "bend", I will always be a (Borland Turbo) Pascal programmer at heart.
Dan Dyer
@Dan Turbo Pascal! Nice.
Yehonatan
+5  A: 

Namespaces in LINQ to XML, mainly because it is my most recent gotcha. Examples of LINQ to XML rarely include a namespace declaration in the sample file, however once you move to a proper live XML file format (like GPX) failing to realise you need to include the namespace in your query leads to much returning of empty results.

Ian Hopkinson
Yup, this got me a few weeks back.
Moo
+2  A: 

In C:

Using math routines such as sin, cos or sqrt and forgetting to include math.h.

On old compilers that will just compile and link without warnings, but not work because C assumes that all parameters are int if no prototype is given. You'll pass an integer to a function expecting a float argument.

Nils Pipenbrinck
If you're calling a non-standard math routine (as opposed to one of the standard ones), this can still happen even with a modern compiler, unless you turn on a warning every time you use a function that isn't declared.The problem is more typically the return value, not the argument value; remember that in old (pre-ANSI) C, there was actually no way to declare argument types at all.
Kragen Javier Sitaker
@Kragen: I thought there was, you just had to specify it before the function?
BlueRaja - Danny Pflughoeft
BlueRaja: `double sin();` is valid K` is not, and only became valid during ANSI standardization. The first declaration specifies the type of the return value; the second one additionally specifies the type of the argument.
Kragen Javier Sitaker
+6  A: 

In some programming languages (like Java and C#) strings are designed as immutable classes, which means that certain methods don't change the original object but instead return a modified object copy. When starting with Java I used to forget this all the time and wondered why the replace method didn't seem to work on my string object.

String text = "foobar";
text.replace("foo", "super");
System.out.print(text); // still prints "foobar" instead of "superbar"
riadd
Agreed text = text.replace("foo", "super"); seems somehow redundant.
Meff
self-modifying methods are really annoying. I guess what matters is how consistent it is with the rest of the API - if all the other string methods return new copies, then this is all good
Orion Edwards
I don't program in Ruby, but one thing I *really* liked when reading about it is that, by convention, all self-mutating methods end in `!`. Thus, `text.replace(...)` returns a new string without changing text, while `text.replace!(...)` changes text. I would absolutely approve a convention like this in languages like C# (it could even be enforced by the compiler for some classes using attribute-tags!)
BlueRaja - Danny Pflughoeft
+4  A: 

Perl's glob() iterator. In scalar context, it will return successive results, followed by an undef, even if the argument changes.

$ touch quux
$ touch quuux
$ perl -w
sub globme {
    my $pattern = shift;
    my $result = glob($pattern);
    return $result;
}

print 'got: ', globme('qu*x'), "\n";
print 'got: ', globme('foo'), "\n";
__END__
got: quuux
got: quux

The 'foo' is disregarded because that call to glob() hasn't exhausted its results yet. To correctly use glob() it should always be in list context, even if you only want one result:

my ($result) = glob($pattern);

or care should be taken to make certain that the iterator is called until it returns undef before a fresh iteration is desired.

ysth
The whole idea of a function doing completely different things in a scalar or a list context is itself a deeply nasty gotcha. (NB: this is different from returning a single value that is interpreted differently in the two contexts; that's a bit unpleasant but sane.)
Donal Fellows
@Donal Fellows: I would say the latter is even worse
ysth
@ysth: Functions that return different values according to how they are wielded? You obviously like different things to me. :-)
Donal Fellows
@Donal Fellows: returning different values *is* "doing completely different things", which you claimed bothered you more (and bothers me not at all). Returning a single value that then acts differently in different contexts (that you seemed to say was better) is what I say is worse.
ysth
@ysth: No, that is a single value (OK, possibly of composite type) and it's possible to capture the whole of it in a suitable variable. Then you can simply view the value in different ways to get the "interpretations" but the value itself is principally unchanged. As your main answer reveals, Perl code doesn't always work that way; it's truly one of the nastiest things in the language (and has been worrying me since at least 1993; I forget exactly when I got a copy of the Camel book...)
Donal Fellows
Right, the expectations in Perl are the other way around. If you go against those, you are being surprising, and that is nasty to your callers.
ysth
A: 

In Ruby code like:

2 + "4"
"hello no. " + 1

Give type run-time errors. It's easy to fix, but I regularly get these errors when trying to print out debug strings. Sure, it's logical; just not very intuitive in a dynamically typed language. You could always redefine the meaning of +, but that's another story.

Firas Assaad
Use interpolation. "hello no. #{1}" is nicer than using +
Orion Edwards
I do sometimes. I wonder if it's really nicer, though. I guess I'm used to other languages that convert numbers to strings and use a concatenation operator.
Firas Assaad
+7  A: 

This isn't a big one for me anymore, but it bit me when I came across it and I see it hit a lot of people, so it stands out to me. Python allows nested functions and closures, as well as functions as objects. A common idiom to attempt is something like the following:

functions = []
for i in xrange(10):
    def f():
        return i
    functions.append(f)
for f in functions:
    print f()

The expectation is that one can create a series of functions, using the outer variables, and later call them in an expected way. However, anyone understanding closures will quickly notice the value of i will be 9 for every single call to the ten individual functions created. The name is looked up in the function's closure when it gets called, and they are all called after the loop, when i still has its last value, which is 9.

The solution to rebinding the variable as a local inside the nested function:

functions = []
for i in xrange(10):
    def f(i=i):
        return i
    functions.append(f)
for f in functions:
    print f()

In the new code, the function is defined with a single parameter, i, which is given a default value computed at definition time, so it has the correct value of i.

ironfroggy
This is also a problem in C#; there was recently a big discussion about it on some C# site.
Kragen Javier Sitaker
This is not a problem with closures per se, but with their implementation in certain imperative languages. A straight translation of your original "wrong" code to Scheme works as intended.
Porculus
+12  A: 

I once went back and forth between two systems on an hour-to-hour basis. One had an editor where Ctrl-X meant save and exit; on the other, it meant Exit without saving.

Bill Drissel

Bill Drissel
Something very similar: "vi -o file1 file2". On systems where 'vi' is actually vim, it edits 2 files in a split screen. But if 'vi' is a link to 'elvis', it edits file2, uses file1 as a log file, and overwrites it with no warning or backup.
finnw
@finnw: Thanks, I've had coworkers ask me why I religiously type "vim" instead of "vi". This is going on my list of reasons. :)
Nicholas Knight
so much for cutting
WalterJ89
+33  A: 

Default arguments in Python:

def f(x, a = []):
    if len(a) == 0:
        a.append(x)
    print a

>>> f(1)
[1]
>>> f(2, [5])
[5]
>>> f(3)
[1] # you expected [3], right?

By appending to the argument a when it is not specified, this actually changes the default argument value for subsequent calls! One way to fix this is:

def f(x, a = None):
    if a is None:
        a = [x]
    print a
Greg Hewgill
WTF? That would drive me batshit.
eyelidlessness
I got burned by that one as well.Python's 'def foo(a=[])' !== PHP's 'function foo($a=array())'!
too much php
This doesn't change the default argument, as the the instances of the default values are created when the function is defined. If the default value is a mutable type (such as a list, set, or dictionary), the items stored in that default value instance changes because it is the same instance.
Adam K. Johnson
Actually, this is quite a nice behaviour, *if you were used to it*. But for anyone coming from another language, this is just annoying, like too much php pointed out.
Boldewyn
@Boldewyn: I'm sure every gotcha is "nice behaviour" if you're used to it.
BlueRaja - Danny Pflughoeft
+8  A: 

I worked on a Data General mini-computer that had a couple of quirks in the Fortran compilier. When we first got it, I wrote a sample program about 10 lines long. We could not get it to compile and run properly, which was aggravating because we didn't have a hard disk and each compile/run cycle took about 15 minutes of reading and punching paper tape. I eventually realized that my little program defined a function named "mpy", but the compiler had an internal function of the same name used for multiplication. (In other words, it should have been a reserved word.)

On the same computer/compiler, if a subtraction resulted in zero, it would be a negative zero which would not test equal to a positive zero. IIRC, if you set a floating point number to 6 and printed it out, it was equal to something like 5.99994.

SeaDrive
Upmodded for a gotcha involving ones-complement.
Nick Retallack
The gotcha might be ones-complement or it might be floating-point; lots of floating-point formats (including IEEE!) are sign-magnitude.
Kragen Javier Sitaker
+7  A: 

Pretty silly...

someheader.h 

START_OF_FILE 
7/*********************************************************************************************************************************************************************************** 
LOTS OF DOCUMENTATION ,LOTS OF DOCUMENTATION ,LOTS OF DOCUMENTATION ,
LOTS OF DOCUMENTATION ,LOTS OF DOCUMENTATION ,LOTS OF DOCUMENTATION ,
LOTS OF DOCUMENTATION ,LOTS OF DOCUMENTATION ,LOTS OF DOCUMENTATION ,
LOTS OF DOCUMENTATION ,LOTS OF DOCUMENTATION ,LOTS OF DOCUMENTATION ,
LOTS OF DOCUMENTATION ,LOTS OF DOCUMENTATION ,LOTS OF DOCUMENTATION ,
LOTS OF DOCUMENTATION ,LOTS OF DOCUMENTATION ,LOTS OF DOCUMENTATION ,
LOTS OF DOCUMENTATION , 
*/ 

// code...
END_OF_FILE

in a C program composed of MANY files... got 2 days to find where it was, that damned "7" ( syntax check couldn't determine row/file error )

Joshi Spawnbrood
This is funny because as soon as I find it I'd be going "what kind of meth addict made that typo?"
eyelidlessness
A similar thing happened to me in PHP once. My file started with "<?phpw" instead of "<?php" and PHP just didn't want to interpret it (without any error message). Unfortunately, my IDE also didn't point out my mistake which took me hours to find.
codethief
@eyelidlessness: Many European keyboards, for instance, use Shift+7 for the slash, so I guess that's a reasonably easy typo to make.
Matti Virkkunen
I used to insert character 255 into Pascal source code. That yields a syntax error, or at least an "invalid character in source", while all the programmer saw in his IDE was a blank. (255 looks like a blank, but it isn't one.)
TheBlastOne
A: 

C

Maybe not the worst gotcha I've seen but recently I came across a colleague trying to set a double to an undefined value. He had read about the 0xFFFA5A5A memory pattern which also can act as a NaN for floats on SGI. How did he use it?

double dvalue = (double)0xFFFA5A5A;

Did he test it? No.

It took me a while to explain all the problems with this line.

epatel
A: 

Visual C++ 6 getline bug ><

string input;
 getline(STD::in,input,'\n');

needs pressing enter twice to work. very annoying, and shouldn't happen in a commercial product.

Objc :

if(string==string2)

doesn't works, it needs

if([string isEqual:string2])
wahkiz
+26  A: 

I posted an answer about Java already, but I think this is a better (worse?) gotcha.

PHP

Specifically, the way it handles numeric literals and strings containing numeric representations. The following is copied from my blog posting about it.

"01a4" != "001a4"

We start with something simple and non-controversial. 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"

However, PHP doesn’t like strings. It’s looking for any excuse it can find to treat your values as numbers. And here we have it. 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.

Enter ===

At this point the PHP apologists chime in with the suggestion to use the === operator. This is an equality operator that compares not only the values of the arguments but their types as well. Both sides must have the same type as well as identical values. This doesn’t seem like it should make any difference as the literals on both side of the comparison already have identical types, regardless of whether that type is string or integer. Of course that’s not the case and when you use the extra equals sign the values remain as strings rather than being interpreted as integers. "01e4" === "001e4" evaluates to false (correct, but not entirely convincing).

"0x001a4" == 0x01a4

So it seems that the rule in PHP is that if the contents of a string can be parsed as a numeric literal then, for comparisons, they are, as we see with the above hexadecimals (note the difference in notation from the first example, i.e. the use of the 0x prefix). Leading zeros are ignored when numbers are involved.

"0012" != 0012

Unfortunately that’s not the full story as the final example shows. Like many other languages, PHP interprets numbers beginning with a zero as octal values, but not when that number is within a string. This is completely inconsistent with the way it processes hexadecimal values and scientific notation within strings.

Dan Dyer
I hate all the time I spend in php figuring out mundanity like this :(.
Doug T.
A: 

I recently spent an hour looking for a problem with some documentation I was creating. The build process was complaining about a broken cross reference and it was there in the source file. I thought there were stale files that held the cross referencing information and deleted the entire builds repeatedly. Finally, I found the problem, the source files didn't have the cross references. The editor buffer I was looking at was showing me an outdated version of the file. Once I refreshed the buffer, it was obvious.

Noufal Ibrahim
Editors such as Visual Studio and Notepad++ will catch this immediately...
BlueRaja - Danny Pflughoeft
Oh. Emacs does that and more. It's however infinitely configurable and I had turned off auto-revertion since it would make editing remote files slow.
Noufal Ibrahim
+1  A: 

ReXX

Using PULL to read binary data from the external data queue.

PULL is a short hand way of saying PARSE UPPER PULL. Of course, once binary data (binary intergers in my case) were converted to upper case, they just wouldn't add up properly any more!

Always read non character data using PARSE PULL

NealB
A: 

Not the biggest, but today (embarrassingly enough) I was working on some legacy C++ code. I don't this often, so my mind sometimes slips going from C# back to C++. Anyway, one object returned (as a property) an internal object. Remember, it's legacy code I'm working with! :) Should have been a reference. So for the want of an ampersand I spent 3 hours tracking down what appeared to be a memory corruption issue.

this:

Foo Bar::GetFoo()
{
   return _foo;
}

should have been:

Foo & Bar::GetFoo()
{
   return _foo;
}

Good grief, Charley Brown!

Found it by putting break points on the c-tor and d-tor for Foo. When the the d-tor is called multiple times and c-tor isn't...

DevSolo
A: 

I was recently caught out by sequence points in C.

We all know the obvious cases, like that x = x++; leads to undefined behaviour because you are attempting to modify a variable twice without a sequence point in between. But there are also less obvious cases, such as:

someArray[f()] = g();

g() can be evaluated either before or after f(), so if g() modifies state that influences the return value of f(), you have undefined behaviour -- which array element gets assigned to will depend on the phase of the moon!

In my case, f() was actually a macro called SIBLING() that took a struct tree * and returned a pointer to the sibling of that node in the tree, and g() was a function that modified the child pointers in a given tree node. I could not figure out why the assignment seemed to be updating the wrong child. I thought for a long time that the problem must have been caused my SIBLING()'s macroness (since we all know that macros are evil) -- it wasn't till I rewrote it as a function and got exactly the same behaviour that I finally clicked.

j_random_hacker
+1  A: 

I did this once:

<input type="button" onlick="ShowPopup()" value="Go!" />

You've got no idea how stupid I felt when after few good minutes of wondering why my function is not being called, I realized all I need to do is to LICK this button...

rochal
A: 

You can't use generics in Windows Forms visual inheritance. Seems to me as if this particular feature was "developed" by an intern or something.

stormianrootsolver
There IS a workaround, but it is so ugly, the flying spaghetti monster kills a kitten everytime you use it. Or our Lady Discordia, if you prefer her.
stormianrootsolver
A: 

JavaScript's lousy scoping for variables in loops.

var functions = [];
for (var i = 0; i < 5; i++)
  functions.push(function() { alert(i); });
alert(functions[1]()); // displays 5, instead of the expected 1

There is, of course, a workaround for this but it's 1) not the sort of thing you expect, the first time you do this and 2) the workaround is fugly.

Phil