Worst Bug Ever
swanson.github.com
swanson.github.com
This perfectly fits my expectations of Matlab:
- i is a mutable, but should be constant
- It has a horrible, non obvious name because mathematicians are used to it. (And they are not used to var names longer than two chars)
- It is in the global scope.
- It's a feature that has a special syntax (sort of).
/edit Apologies for php programmers, maybe php is worse. But I'm not sure.
It's not really mutable, because it isn't a variable. However, if there is a variable by that name, Matlab will use it instead of the complex constant.
> - It a feature that has a special syntax (sort of).
The problem is rather a lack of special syntax (or too much leniency). Python also has built-in complex numbers:
>>> 1 + 1j
(1+1j)
but it doesn't allow you to omit the constant before the j: >>> 1 + j
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'j' is not defined
You can do it the same way in Matlab to avoid this problem (1 + 1i is always OK since implicit multiplication is not allowed), so the problem is that Matlab lets you use i syntactically like a variable when it in fact isn't.This is what i mean with a sort of special syntax. It's awful corner case.
I don't like the Python syntax either. What would be wrong with Math.C(1,1) for 1+i? Or how about 1 + Math.I ?
I don't have a problem with using i or j as the complex constant, as long as the necessary sanity checks exist to make sure it's not misused (e.g., duplicate declaration of i/j, overwriting i/j, etc).
Sort of like how PHP will treat undefined constants as unquoted strings. Like if that made any sense... At least PHP will trigger a warning if you do that.
The use of j is common in electrical engineering, where i denotes current.
The bug described in the article is impossible in Python (and probably in most other programming languages with native support for complex numbers) because `1j` is not a valid identifier.
Nowadays, whenever I have to do something (UI, non-numeric data processing) in Matlab, I tend to write a Matlab-shim that calls a Java-component (the Java interaction is fortunately very nice).
The mere fact that one gets things done with less hassle in Java than with a scripting language is a quite damning verdict for said scripting language.
Matlab was created to provide a simple way to make FORTRAN Libraries available to non-programmers. And it was quite successful at that. It was quickly picked up by engineers and all kinds of features were piled on top of it.
And the worst thing is that Matlab is a de-facto standard in many areas now. As a webprogrammer you can probably easily avoid PHP by using Python, Ruby, JavaScript, Perl or whatever. But in engineering many people only know Matlab. They don't care about anything else.
I was calculating a parameter enhancement where my calculations were showing a great 180% enhancement; this result would make it into very high ranking (15+ IF) paper right away. By then, several people had written numerous papers on this matter using this multiphysics software in well-known journals. But my gut feeling didn't let me. Eventhough my professors were pressing me to publish, I took 6 painful months (toward the end of my phd) to rigorously test the software itself, having nothing to do with my work, since it was closed-source.
After 6 months, I found out that a velocity term used in their stabilization algorithm does not use relative velocity, but absolute velocity, leading to enormous amount of fake diffusion into the model. I had to travel to another city in europe to convince them that there is such bug.
Every single work in my field that used this software till then had been severely invalid. And what the developers did: they fixed the bug in the next sub-release without putting it in the changelog like nothing happened.
Once, I was working on the "alias" keyword in MacRuby, and getting it to work with methods defined in Obj-C. Since MacRuby objects are just extensions on Obj-C objects, some methods are defined in Obj-C and require special casing in order to alias them to a different identifier. For example, if you want to alias "Array#length" to a different name, you'd actually be aliasing "-[NSArray length]".
So I do everything I should need to do to make it work: get a handle to the object, the object's class, the method defined for the class, a selector for the new name...but no matter what I tried, every time I aliased the method, and attempted to call the method by the new name, I would always get the same error: "Method not defined".
Finally, I decided to dive deep with gdb and find out exactly what was going on. To my shock and amazement, I came to realize that I was properly aliasing the method but, due to the nature of NSArray's implementation as a class cluster (and the fact that Obj-C doesn't have proper virtual methods like C++), the implementation of "-[NSArray length]" was literally:
- (NSInteger)length
{
[NSException raise:@"Method not defined." format:@"%"];
}This is pretty nasty, because it breaks the idea of message sends and subclass overrides of methods. There's two ways you could solve it:
1. Set the IMP to a static function that looks up the method it should forward to and re-send the message there. This is hard to do in a manner that supports all arguments, and you'd need at least 2, possibly 3 versions anyway (one for regular, one for strret, and on some architectures, one for fpret). It would probably need to be written in assembly in order to forward the arguments.
2. More recently (in iOS 4.3, and whatever the corresponding OS X release was), the runtime got a nice little function called imp_implementationWithBlock(). This takes a block and returns an IMP. Bill Bumgarner has a nice blog post about it (http://www.friday.com/bbum/2011/03/17/ios-4-3-imp_implementa...). You could use this function on every alias in order to invoke the correct method, passing along the correct arguments.
class Foo
def say; puts "hello"; end
alias shout say
end
class Bar < Foo
def say; puts "howdy"; end
end
Foo.new.say #=> "hello"
Bar.new.say #=> "howdy"
Foo.new.shout #=> "hello"
Bar.new.shout #=> "hello"... so she named her variable "time"
... which, when modified, would (naturally) set the system time of the computer.
I'm not sure whether they've fixed that one yet.
I also got to the point with FORTRAN (yes, I'm old) students where I'd cut them off and tell them to count the columns and make sure each line started with 6 blanks, not 5.
My favorite bug is still some piece of C code buried in a library that was like this:
if (flag == TRUE) ...
Or there's the old for loop typo (much easier to detect on today's high-DPI screens): for(float x=0.0; x < 3,4; x = x + 0.1) ...What you want varies but is probably something like:
if (flag & FLAG_VALUE) ...
if (flag) ....
if ((flag & FLAG_VALUE) == TRUE) ...
that kind of thing. if ((flag & FLAG_VALUE) == TRUE) ...
That would still check if flag is 1, right?Suggest (flag&FLAG_VALUE), or, if you need the expression to be of type bool, ((flag&FLAG_VALUE)!=0) or (!!(flag&FLAG_VALUE)).
using $a or $b for a throw-away script, but Perl uses these internally for sorting
Everything I learn about Perl just makes me hate it more. But a lot of people seem to love it -- it must have some redeeming qualities, right? our $a = 100; # using $a package variable
# then later do a sort on @list
my @sorted = sort { $a cmp $b } @list;
# @sorted worked correctly, $a = 100 had no effect on it
# and $a is still 100
And if we change our to my (so lexical variable) then script will fail to compile giving the fatal error: Can't use "my $a" in sort comparison at...For more information on sort see: http://perldoc.perl.org/functions/sort.html
PS. The OP problem may have been due to issue/bug in older version of Perl. Also using use strict; use warnings do help highlight issues with code.
First 3 lines of all perl code for me are:
#!/usr/bin/env perl
use strict;
use warnings;Answer: Yes, depends on where in the world you live.
The constness of i in Matlab is also imaginary, which is pretty terrible.
1.) not having lexical scoping
2.) not having warnings when a global is overridden in a local scope
these are pretty inexcusable. For anyone looking for a "better MATLAB", Python has NumPy, SciPy and Matplotlib which are pretty much everything.
I hear this at work all the time, "just use Python, we're going to use Python everywhere we use Matlab from now on". It simply doesn't work like that.
Usually it's programmers who are too overly enthusiastic about replacing Matlab with Python, because they are comfortable with all aspects of programming languages. The people typically writing the most complex Matlab code aren't, more often than not they are physicists or mathematicians. Python + SciPy + Matplotlib is not nearly as accessible as Matlab, and you drag in all kinds of typical 'software engineering' problems that don't exist when you stay inside the Matlab IDE and its related tools. I can conjure up a plot in Matlab and manipulate it incrementally for example, while Matplotlib often requires a lot of crazy data mangling and setup code that isn't required in Matlab (trust me, I've spent months re-implementing a library of Matlab plotting scripts in Matplotlib, and the code of some of them is completely untraceable to the original Matlab code, and full of stuff completely unrelated to plotting). Also, lots of Matlab code relies on all the crazy implicit operations and type juggling allowed by Matlab, many of which are almost fundamentally incompatible with a well-defined programming language suited for production code.
This is all even ignoring the fact that Matlab comes with a pretty extensive library of toolboxes that have no equivalent in SciPy or Numpy. If you're really determined and know how to program in Python, you can basically get a lot of stuff done without requiring Matlab, but if you've always been using Matlab like a prototyping tool or a very elaborate graphical calculator (and this constitutes a very extensive part of Matlab users), Python + all its scientific libraries is no substitute.
However, I still think my points about where MATLAB falls down are valid. There is no reason for it not to have lexical scoping, or warnings about when you are doing stupid things. It just doesn't have them, and it causes frustrations like the one in this article.
And despite not being a fan of closed source software in general, I must say that Matlabs "IDE" is hugely convenient and, for its purpose, far ahead of anything else out there.
With respect to complaint #1, based on the Wikipedia definitions of lexical and dynamic scoping, MATLAB has lexical scoping of function variables. Can you say more about what you mean?
With respect to complaint #2, I think it might be based on other comments in this thread. Other commenters have suggested that "i" in MATLAB is a special kind of global constant that is prone to getting unintentionally overridden. That is not the case, however. "i" is simply a function in MATLAB, as are "j" and "pi".
When a user assigns to "i", as in i = 5, it has the effect of creating a variable called "i". The variable "i" shadows the function "i" based on the rule that local definitions of names take precedence over names defined further away. That's a perfectly ordinary and common programming language convention.
If you create a variable "i" by assignment and then call a function, that function has its own set of variables and doesn't see the variable "i" in the caller. There's no global override happening.
for (x = 0; x < thing.length; x++) { }
I didn't put a "var" before the x- so Air used the window.x object, and shifted the entire contents of the window to the right by a seemingly random number of pixels.To look at it like that, it's blindingly obvious. But it was in the middle of a whole lot of other code, and of course, the for loop ran perfectly fine.
It was involved in at least six accidents between 1985 and 1987, in which patients were given massive overdoses of radiation, approximately 100 times the intended dose. These accidents highlighted the dangers of software control of safety-critical systems, and they have become a standard case study in health informatics and software engineering.
Thankfully, we were able to restore that table from a backup and rerun everything to rebuild the table's state to a correct place ... but suffice to say the experience taught me many things about attention to detail, and how debugging in production should happen.
Good times!
It makes polyglot programmers make a lot of silly mistakes. It would have been SO easy to call the imaginary constant just 'I' instead of 'i'...
i=sqrt(-1)
Sorry for the mess, hope you learn from this...'
But I keep tripping over the same stone...
Insisting on doing something, even if it's the wrong thing, is much worse in most applications than refusing to run in order to avoid producing incorrect and misleading results.
Thought the periods would make it clear. Oh well!
EDIT: Looks like the periods got removed from the title - I can see why that would make the reference a bit more obtuse.
The CMS had a database query result class with a method named something like "numberOfRecords". It returned the number of records minus one...
I told my boss about this, and his answer was "Yeah I know, but we don't want to fix it because a lot of code depend on that bug."
But still I was wondering: isn't that code horribly un-idiomatic for an array based programming language?
i = ...
... # lots of code
[ do_stuff(i) for i in range(n) ]
...
# whoops, our outside i has now been modifiedhttps://github.com/MrMEEE/bumblebee-Old-and-abbandoned/commi...
Always start with the small, obvious stuff first!
I work in matlab a lot and have had this error creep up several times. It's very annoying, to say the least.
Here's the same thing re-written in Python:
d = [compute_diffraction_at_wavelength(x, WAVELENGTH) for x in LensLayers]
Or oldschool Python (and still faster, I think): d = map(compute_diffraction_at_wavelength(WAVELENGTH), LensLayers)Title is still sensationalist.
</grammar nazi>
First I'll come with an old bug of mine (early nineties). The bug was very hard to reproduce because it was very very occasional (but terrible in consequences). I simply couldn't find it. I knew I was probably smashing some memory somewhere (I was not that experienced in C) but couldn't find where.
So what did I do after weeks of hunting the bug? I moved my design away to an entirely deterministic one and started recording all the inputs the program received and then I could replay them. At one point, logically, the bug happened. And so was it "recorded". Because my program was now deterministic, I could simply feed it the inputs (and the time at which they happened) and, surely enough, the bug was there.
And then finding the cause of the bug was of course trivial.
What's the lesson?
Well, first obviously bugs that you cannot easily reproduce because you cannot "reproduce the state" are typically kinda hard to track down.
The less "state" in your program, the easier it is to reason about your program and the easier it is to reproduce the state.
The lesson?
Functional programming rocks.