Dirty Coding Tricks To Make a Deadline 683
Gamasutra is running an article with a collection of anecdotes from game developers who had to employ some quick and dirty fixes to get their products to ship on time. Here's a brief excerpt:
"Back at [company X] — I think it was near the end of [the project] — we had an object in one of the levels that needed to be hidden. We didn't want to re-export the level and we did not use checksum names. So right smack in the middle of the engine code we had something like the following. The game shipped with this in: if( level == 10 && object == 56 ) {HideObject();} Maybe a year later, an artist using our engine came to us very frustrated about why an object in their level was not showing up after exporting to what resolved to level 10. I wonder why?"
Have you ever needed to insert terrible code to make something work at the last minute?
Here's one... (Score:5, Funny)
Re:Here's one... (Score:5, Funny)
Re: (Score:3, Funny)
Don't be absurd. Even the lowliest coder would know enough to write #DEFINE PSEUDO_RND_BSOD = 1
Re:Here's another one... (Score:5, Interesting)
This is the code for the Apollo 11 lunar lander flight computer.
http://code.google.com/p/virtualagc/source/browse/trunk/Luminary099/LUNAR_LANDING_GUIDANCE_EQUATIONS.s?r=258 [google.com]
and yes some of my code is in there along with the equivalent of a few "goto's
Lots of bright people worked on this and in some circumstances a "goto" is required.
Re:Here's another one... (Score:4, Funny)
HELP!
I'm trying to get this code to work. I'm at an altitude of 6,000 ft, hovering over the Sea of Tranquility, and the darn thing keeps crashing! (The code, not the lunar module.)
PLEASE don't connect me to that Bangalor helpdesk again! I am in serious trouble here!
Has this been tested for Y2K compliance?
Did we not pay our last support bill?
- Major Tom [wikipedia.org]
One word.. (Score:5, Funny)
Re:One word.. (Score:5, Informative)
The goto statement is very useful. Your dislike of it is irrational. Do you even know why you do not like it? Often, goto is the best solution to given problem.
Re: (Score:3, Informative)
I have not used a 'goto' statement in about 15 years now. But it's not some irrational fear. It was all due to someone saying 'there's no situation that requires a goto' and 'goto statements make code hard to read'.
And after I used goto a little more, I realized they were correct. In any good, modern language, 'goto' is completely unnecessary and makes your code harder to read.
If you're breaking out of a loop, you should use 'break'. If you're continuing a loop, 'continue'. If you're handling an error,
Re: (Score:3, Informative)
So, where's your example?
Finite State Machines. They really are quite difficult to implement without goto logic and is exactly what you do when discussing theory.
Re: (Score:3, Insightful)
as well as some oddly structured loops for which try/catch logic doesn't get you all the way
Such loops are almost certainly buggy, almost certainly maintenance nightmares and I'll stick my neck out and say certainly unnecessary. The logic needs redesigning. So they are examples of dirty tricks to get code out of the door, as the GOTO poster suggested.
Re:One word.. (Score:5, Interesting)
But as below says, they make error handling an easier task as well as some oddly structured loops for which try/catch logic doesn't get you all the way
Ugh. Magic invisible gotos FTW! [joelonsoftware.com]
Re: (Score:3, Informative)
Re: (Score:3, Informative)
From the linked article: [joelonsoftware.com]
I have done code that way, before exceptions came into vogue. To do it right, you've got to have many many many error-checking if() statements after every call to any function that could fail. That could mayb
Comment removed (Score:5, Interesting)
Re: (Score:3, Insightful)
You were very, very lucky, in an awesome way. None of my programming teachers were EVER that savvy.
Re: (Score:3, Insightful)
Re:One word.. (Score:5, Insightful)
I’m a goto-user, but this is a bad reason to use them: If you regard language features as ‘just’ syntactic sugar, why aren’t you programming in raw machine code? That is what everything eventually gets turned into anyway.
You use gotos when the normal control structures are inadequate somehow. It doesn’t matter what the compiler does; source code is for humans.
Re:One word.. (Score:4, Insightful)
You use gotos when the normal control structures are inadequate somehow.
This is the heart of the issue: control structures are a well defined, easy to follow, hard to fuck-up subset of the things you can do with goto. If you can do it reasonably with a control structure, you shouldn't use goto, because it makes your code more readable. If you can't, then you should consider if your program should be restructured (which is why goto is dangerous to novice programmers). If not, then you can use a goto.
Of course, all bets are off when you're scraping for clock cycles with machine code, but that's not necessary most of the time.
Re: (Score:3, Insightful)
So formatting is worthless, then? And why do we have so many languages, many of them domain-specific? Compilers don’t care about how understandable the metaphors are or how many lines are needed to do a specific thing.
Re:One word.. (Score:5, Funny)
So formatting is worthless, then?
No, formatting is for successors and maintainers. As fellow coders, they're not human, strictly speaking.
Re: (Score:3, Insightful)
Every control structure in C++ is equivalent to either a goto or jnz plus some syntactic sugar.
This is almost true, but I see one important exception: the exception machinery in C++ (that is the compilation of throw and catch C++ statements) is not exactly a goto (and neither is longjmp in C). And of course, any (method or function) call and return is not exactly a goto neither. Exceptions,calls and returns also change the stack pointer.
I would also notice that computed goto (i.e. the goto *p; GNU extension [gnu.org] of C) is compiled as an indirect jump.
A more interesting concept is continuation [wikipedia.org] Regards
Example (Score:5, Interesting)
#include <stdio.h>
void *f(void)
{
a:
printf("Here!\n");
return &&a;
}
int main(int ac, char **av)
{
goto *f();
printf("There\n");
return 0;
}
Re:Example (Score:5, Informative)
OMG. I didn't even knew you could write that in C (and I have my name in the comp.lang.c FAQ...)
Of course, I checked C99, and, no, you can't write that:
3.6.6 Jump statements
Syntax
jump-statement: ;
goto identifier ;
continue ;
break ;
return expression<opt>
identifier being defined as:
identifier:
nondigit
identifier nondigit
identifier digit
So, goto *f() is a no-no (as is probably &&a)
But, anyway, wow. Gcc actually compiles that to something that somewhat runs...
Re: (Score:3, Informative)
Yes, it is non-standard. But quite useful for some things (although not in the way written above). Consider a function that needs to return and then resume where it left off the next time it is called. Could be done by wrapping it in a large switch, but this is more direct and efficient.
#include
void *f(void *p)
{
if(p != 0)
goto *p;
return &
a: printf("A\n");
retur
Re: (Score:3, Interesting)
I don't think the efficiency is worth having a non-standard construct, considering a simple switch would do the trick.
You could also split the function in multiple function (because having all the code in the same function is not very useful as local variables are trashed between executions), and directly returning pointer to the next function to call (hence you could spare of the cost of actually calling f() before jumping).
Anyway, a nice trick. Didn't thought I would learn another one in C. The worst I ev
Re: (Score:3, Insightful)
I pity the developer who has to maintain your code after you've moved on.
Re:One word.. (Score:5, Insightful)
Breaking out of a deeply-nested loop, as can happen when you’re looking for a specific element in a multidimensional array. The alternative involves adding state variables and complicating the logic terribly.
Re:One word.. (Score:4, Insightful)
Ewww.
1) decent languages support labeled for/while cycles and apropriate "break label" constructs. It is not so different from using goto but has much better semantic meaning and thus allows neat optimalizations (with, say, paralelization in mind)
2) if you do this kind of thing, you are MUCH better off separating lookup code to method or function and simply using return statement once you find it without having to break from cycles per se. Cleaner, more structured.
Re:One word.. (Score:5, Interesting)
You often cannot develop software with the language you want, but must develop it with the language you have. C has no such features and, therefore, goto is used more often than in languages that have them. Fit the strategy to the tool.
This is reasonable, but it assumes some other function can do the needed cleanup code or other data massaging just as cleanly. If the goto is being used because finding the value is an error condition, you often have to do certain things as soon as possible in the code so you do not lose important debugging information.
And, no, exceptions are not part of C, and setjmp/longjmp is, if anything, even less likely to pass code review. An advantage of goto is that you can keep the cleanup code in the same function, visually close to the rest of the logic and sharing the same locals.
Re: (Score:3, Informative)
Yes it is, goto requires a label, and thus requires someone reading your code to go hunting for it. Return is known to push control flow to the exit of the function. One obfuscates code, the other doesn't.
Re: (Score:3, Funny)
I agree, if you need cleanup code... But I don't write code with side effects, so there's no problem whatsoever. No side effects means no clean up.
Re: (Score:3, Informative)
Error handling in C code is my typical example of that. It mostly avoids the need for lots of if statements to make sure that you clean up all that you need to and nothing more.
There are other ways to go about it, but in general I'm not convinced they are better.
The most common use of "goto" in that circumstance is to enforce "only one return".
Which is every bit the pedantic lunacy that goto-hate is.
Re:One word.. (Score:5, Insightful)
Hardly pedantic or lunacy. For example, pick one of the drivers from the Linux kernel, e.g. this one [sourceforge.jp]. Look in particular at the "geode_aes_probe" function.
The structure looks like a pyramid. On one side is the setup phase, on the other side is the cleardown phase. If one of the setup operations fails, then the "goto" jumps to the appropriate cleardown operation and continues from there. If the top of the pyramid is reached, then return #1 (success) is used. Otherwise, return #2 (failure) is used.
This function could be written in C without using goto. But would it be as easy to read and as easy to maintain? Doubt it. As it is, it's perfectly obvious what you would need to do in order to add a new capability to the driver. Tricks to work around "goto" would only obfuscate the functionality.
Re: (Score:3, Insightful)
Whether that is better or not is subjective. "Goto considered harmful" has become dogma, but while your example is a very good example of goto used well, most programmers would use it to write spaghetti code. Barring the use of the keyword means that it does only get used by people who know exactly what they're doing.
Re:One word.. (Score:5, Insightful)
I'd agree with all of that. Like C itself, goto is a powerful tool that is easily misused by beginners, but is still very useful in the right circumstances.
Re:One word.. (Score:5, Insightful)
I can't figure out if I'm the only sane one or the only crazy one. Especially given the 'pyramid' referred to - I don't see a pyramid unless it's rewritten to use nested ifs.
To me, nested ifs are much easier to read - they convey the meaning/intent of the code a lot better. As in 'if this function call works, then do this. Otherwise, just clean up and exit'
How is this so hard to understand?
geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id) {
int ret;
if ((ret = pci_enable_device(dev)))
return ret;
if (!(ret = pci_request_regions(dev, "geode-aes"))) { /* Clear any pending activity */
_iobase = pci_iomap(dev, 0, 0);
if (_iobase == NULL) {
ret = -ENOMEM;
}
else {
spin_lock_init(&lock);
iowrite32(AES_INTR_PENDING | AES_INTR_MASK, _iobase + AES_INTR_REG);
if (!(ret = crypto_register_alg(&geode_alg))) {
if (!(ret = crypto_register_alg(&geode_ecb_alg))) {
if (!(ret = crypto_register_alg(&geode_cbc_alg))) {
printk(KERN_NOTICE "geode-aes: GEODE AES engine enabled.\n");
return 0;
}
crypto_unregister_alg(&geode_ecb_alg);
}
crypto_unregister_alg(&geode_alg);
}
pci_iounmap(dev, _iobase);
}
pci_release_regions(dev);
}
pci_disable_device(dev);
printk(KERN_ERR "geode-aes: GEODE AES initialization failed.\n");
return ret;
}
Re:One word.. (Score:5, Funny)
Pyramid? It looks more like the players' ship sprite from Galaga, rotated 90 degrees...
Damn, now I want to play Galaga...
I see two unconditional jumps here (Score:3, Insightful)
But I might have missed some. There is not much difference between "return 0;" and "ret=0; goto exit_function;". Both are unconditional jumps there is no rational reason why one should be "considered harmful" and the other not.
Re:One word.. (Score:4, Informative)
How is this so hard to understand?
It's not. But nor is code that uses goto in the idiom that FourthAge posted above.
My objection to that code is that if you do even just three or four allocations, you start getting very large indentations pretty fast, especially if you like 8-character indentations [sourceforge.jp]. (They get pretty long even with 4, which is what I like!) This causes a problem if you restrict yourself to 80-columns [sourceforge.jp].
Arguably this is a problem with restricting yourself to 80 columns, but that's not entirely unreasonable even if I'd rather the limit be ~100. But guess how many your code uses? Your longest line is 109, longer even than my longer preference. Even if you use 4-character indentations, your longest line is still 80 characters.
If you reformat your code to use 8-character indentations and 80-character column limits, your code would become a bit uglier as you'd have to wrap four lines (a couple of which don't really have a good breaking point), and hence a little harder to understand on its face.
By contrast, the original code fits entirely within 80 characters (admittedly only just) without anything remotely like an awkward line break.
Further, in some sense it doesn't entirely follow the flow of the code. Perhaps this is a vice and not a virtue, but I tend to think of places where there's an unusual condition (like a failed allocation) as not on the same "level" as normal control flow. In this sense, I would think of that procedure as basically linear "with some provisions for exceptional conditions". In that sense, your proposal of the cascaded ifs doesn't really match my mental model of how the code behaves -- the indentation of the normal code changes depending on how many exceptional conditions might arise, and there's not really any reason why it should by that model. By contrast, the original code matches it.
(Incidentally, "linear with some provisions for exceptional conditions" is basically how I'd write it either in a language that supports exceptions or a language that has RAII. In the former case, there's a decent chance do just one try block for the body of the function, and in the associated catch test to see if each item is allocated in turn. (This doesn't match the structure of the real code exactly, but it's closer to it than it is to your nested-if code.) In the latter case, you'd have basically the real kernel code except that the deallocation would be in the RAII objects' destructors. Again, no nested ifs.)
Re:One word.. (Score:4, Funny)
If you were going to do that without goto, use a while with a break instead of ugly nested ifs.
while(1)
{
if (!start_condition) break;
action1();
cleanup1();
if (!test_condition1) break;
action2();
cleanup2();
if (!test_condition2) break;
}
And so on ... it basically gets you exception handling formatted code. Of course, goto is probably still cleaner :)
Re:One word.. (Score:4, Informative)
"How is this so hard to understand?"
For me, it's hard to understand because your most highly indented lines wrap off the edge of the window, back to the left margin, wrecking the indentation cues. In an IDE, it sets a limit on how many conbditions you can check before having to scroll around to see the whole function.
I used to work at a company where this was the standard and I was never fond of it.
Re: (Score:3, Insightful)
But why use a loop + break, when your loop isn't really a loop (i.e. it only executes once)? Every time I see this trick, it makes me cringe: it is just a goto in disguise, and its sole reason for existence is that disguise! If the given situation is best handled by goto (and there are many such cases), then don't be shy and just use it.
Re: (Score:3, Insightful)
Re:One word.. (Score:4, Insightful)
Actually most exception handling constructs are even worse than goto, because they can unwind the stack an arbitrary amount. This is because they are taken from languages like Lisp and Smalltalk, which had accurate garbage collection and stack introspection and so could be used safely, and plonked into languages which have neither. In Java they're not too bad because you have to explicitly declare every exception that you can throw and so they become part of the interface, but they are horrendous in something in the C family. There's a nice Raymond Chen article where he writes the same bit of code with and without exceptions, and it's clear where the bug is in the exception-free implementation (error value ignored) but with exceptions it's very difficult to spot and the number of possible code paths grows alarmingly.
Goto in C is not like goto in BASIC or many languages from the '70s and earlier, which was basically a higher-level wrapper around a jump instruction. In C, a goto statement is only allowed to jump within the current function, so it doesn't break structured programming too badly. Exceptions and longjmp(), do. Longjmp(), as it's traditionally implemented, is the worst because there is no way for any code in intervening stack frames to handle cleanup and so it's almost impossible to use without causing resource leaks of some kind. Non-local exceptions are almost as bad, because they hide multiple return paths. Sometimes it's cleaner to have two or three different return statements in a function, but with exceptions every single function call is a potential return path unless you wrap every single call in a try / catch block.
return, break, continue? (Score:4, Informative)
Have you ever wrote a function / procedure with more then one return statement? Or used break or continue in a loop? Then you can use goto as well. From a structure point of view goto, break, continue and return are all unconditional jumps. They are one of a kind. And looking back in retrospect: Since goto need to be paired with a label it's the least evil of the group.
Note that Pascal the archetype of structured programming had goto but it did not have break, continue or return.
pretty much everytime I write in (Score:3, Insightful)
Balancing act (Score:4, Interesting)
University Assignments. (Score:5, Funny)
Once I had an assignment due and at the last minute before being evaluated, realized I had made a huge mistake, even though the code looked OK...
Too much time playing games in class and I was about to fail the course unit if I didn't pass that one test (right at the end of a semester)
So I ran the program, adjusted the output in a word processor, saved it as a file and threw some code hidden in the comments that read the file, outputted it and exited.
Three minutes later my code was evaluated... I was the only one who passed.
Fortunately, no one investigated too carefully at the time why I was the only one who passed, because after trying to fix the code later in my own time, I realized the source data we were all supplied was corrupted.
Inevitably, Later the same lecturer came to the same conclusion when his program didn't work either and cornered me to ask why mine worked (of course he was suspicious). Thinking quickly, I told him my source data was corrupted and that I fixed that first so my program would work. I don't know if he believed me, but he accepted the story.
Fortunately, I got away with it and I got to keep the pass.
Re:University Assignments. (Score:4, Funny)
Similar story.
In one of my "Intro to C" mid-term exam, one of the (sit down in the 'puter lab and spew code type) assignments was a simple string manipulation exercise. After I was done with the program, while sitting around waiting for the output-verifying lab drone to come over to my place, I noticed all she was doing for the other folks with the same assignment question was key in the same series of words as test inputs. I saw this, and quickly whipped up another little program that basically displayed a prompt, and did a printf("{hard-coded desired output for same set of words}"); and ran this piddly little pile of 'code' when she stopped by my machine.
Sadly, I passed..
Re:University Assignments. (Score:4, Interesting)
You laugh, but that's the basis of 'Test Driven Design'. :D You were only supplied with 1 test, and you passed it. Had their been more tests, your code would have had to be what was really wanted.
I've started to think about how a class could be run like that... Create a series of unit test sets that progressively test more of the program. For each assignment, give the students the next set of tests and have them code to make the tests pass. In the next class session, work to show everyone how to make it happen, then give the next set.
Re: (Score:3, Interesting)
DOS to the rescue... (Score:3, Interesting)
> Once I had an assignment due and at the last minute before being evaluated, realized I had made a huge mistake, even though the code looked OK...
I once did almost the same thing, except that I wrote the entire assignment the first day we got it, during class. But I couldn't turn it in yet. And nearly forgot about it. So I turned it in at the last minute...
Except that I had misread the specification! Oh, the program worked just fine, but it printed everything to the screen. It was *supposed* to go
Re:University Assignments. (Score:5, Interesting)
Not the only lesson (Score:5, Insightful)
Well, in part, but another important lesson in science labs is learning to report the truth, even if is disappointing and not what you want. This is an important lesson and unfortunately even some well known scientists [wikipedia.org] don't learn it,
Re:University Assignments. (Score:5, Funny)
To this day I continue to find typos in my code but less and less bugs-in-libraries.
That's because the ratio of code-bugs to library-bugs increases with the programmer's age, even if both the code and the library remain unchanged. </zen>
Wolf 360 hack (Score:4, Interesting)
The deadline is looming, I can't spend much more time on this. So, I did the unthinkable -- I packed the controller id into the pointer parameter. I marked it as a horrible hack in a 4-line all-caps comment, and checked it in.
Does not sound so horrible, just make sure the 1,2,3,4 pointers never point at anything "free()"able and it'll work fine.
BTW, is that Wolf 360 game out?
Re: (Score:3, Funny)
(oh, and solaris lies about giving you rgba -- it only gives you rgb -- my code would work on one of the uni servers, but not on another)
Wrong question (Score:5, Insightful)
Have you ever needed to insert terrible code to make something work at the last minute?
Wouldn't "have you ever shipped a product without needing to insert terrible code to make something work at the last minute?" be a more sensible question?
Re:Wrong question (Score:5, Funny)
Probably. But reading a stream of "nope", "sorry", "you're kidding", "good one" ... answers leads to a lot of redundant mods but no good entertainment.
Never (Score:4, Funny)
My boss however *only* does coding tricks. And he puts them in one big 1k line function.
And is proud of it.
Sucker punch (Score:4, Funny)
When my deadline comes up and I haven't produced I wait for my boss to ask me for the code then I sucker punch him and run away. The trick is to hold down short term contracts and give false references and hire someone to back them up (another dirty trick). That also makes it easier to dodge the cops when your boss presses charges. It's getting harder though with all this talk of test driven development and short incremental releases. Then the trick becomes to write the most meaningless trivial unimportant tests first - but crucially tests that you can make pass quickly so you don't have to do any real work.
(For anyone insane enough not to realise it, this is a joke. Don't try this at home...or at work).
Game Art (Score:5, Interesting)
Technically not a code fix, but still a valid solution.
seen some bad shit. (Score:5, Interesting)
I once worked at a Fortune 25 company in Chicago. They had this ENORMOUS mainframe program written in COBOL that ran their order inventory system which accounted for 20% of the companies revenue. All the guys who wrote this grunting pig of a system had either retired or had passed away. In the middle of the code was the following;
*
* We don't know what this does.
* Please leave it alone !
*
SET INSIDE-INDEX TO 1.
*
* We don't know what this does.
* Please leave it alone !
*
If this statement was commented out or removed the system stopped working. No one could find the problem. People had spent years looking for it but the code was such a mess and the documentation was so useless that they just left it alone and made a note that when the order inventory was re-done to make sure they left this "feature" out. I have been told that many old system have similar problems.
Even worse stuff! (Score:5, Interesting)
Some of the worst I have seen:
In critical C code:
if (some condition)
i *= 0;
else
i *= 1;
And I was the actual variable name.
Even worse, on a different project, an Easter egg that told the user their hard drive was about to be erased, and another that popped up about 30 dialog boxes full of banter between Spock and Kirk. Worst of all this code written in VB and was licensed for megabux then we got hold of it for orders of magnitude more megabux (Most of the original coders were hired fresh out of highschool). It ended up being rewritten (thankfully NOT by me) but we had to get the source to work out how it worked in the first place.
I wish I was making this up.
Easter egg dependency (Score:5, Interesting)
We had an easter egg in our code that was in a routine scheduled to be executed only at 0-dark-30 when our users were long gone. But someone later called the routine as part of the loading process, and the users ended up seeing it anyway as they signed on at start of day. It made people smile, so we left it in.
A few years later, we were telling a client that we couldn't add their new feature X because we don't have the memory. At that point the director said to get rid of the easter egg and then it'd fit. (A few hundred bytes was not going to make a difference, but our director didn't care, it was a perception thing.) What we got instead was a hundred bug reports that the easter egg wasn't displaying, and that they "needed" to see it so they'd know when start of day was complete.
Train simulation (Score:5, Interesting)
Study Assignment (Score:5, Funny)
This was a pretty important assignment back when I was studying computer science. It added to the final mark mark for that particular class. The task was to write a reasonably complex application in Prolog or some functional programming language, I can't remember which it was. I think the goal was to pair males and females based on their preferences, and find the optimal solution. Of course, I screwed up royally, and nothing worked five minutes before I had to demonstrate my solution.
So in the final five minutes, I changed my code so it would avoid the parts which put it into an infinite loop, and instead simply output a random result. My goal was to tell the prof that it had worked a few minutes earlier, and that I didn't know what had gone wrong, and could I please have another week?
So I demonstrated my app, it gave its random output, and I was about to start with my "damn, it used to work properly" spiel when he said (and this is actually true, even though it sounds unbelievable):
"That's great! The result is correct, and your app is also quite a bit quicker than my own implementation of the problem. Congratulations, I think you're the only one so far who managed to get the correct result so far."
I was so taken aback that I probably just stared at him for a few seconds. Then, I stupidly said "So... You want to see my code?" but he was like "No, the result is correct, and your implementation is very fast, so I don't need to see the code. Good job. Send in the next guy."
And so I did.
Re:Study Assignment (Score:4, Insightful)
"That's great! The result is correct, and your app is also quite a bit quicker than my own implementation of the problem. Congratulations, I think you're the only one so far who managed to get the correct result so far."
I was so taken aback that I probably just stared at him for a few seconds. Then, I stupidly said "So... You want to see my code?" but he was like "No, the result is correct, and your implementation is very fast, so I don't need to see the code. Good job. Send in the next guy."
This is so sad. He notices your code is faster and he's not the least bit curious? (I presume he's some kind of CS prof.) Anyway, good for you, but still... :-(
Prolog Assignment (Score:5, Interesting)
That's completely understandable in this case of programming in Prolog.
Prolog is a declarative language.
You declare the rules, and the system figures out a result that matches those rules.
The problem is that this basically doesn't work. So a Prolog programmer has to write the "declarative" rules in a procedural order so that the run-time system doesn't have to try every possible combination to find (or fail to find) a matching result.
The proper ordering of declarations can be quite subtle. With a modestly complex program you can make a seemingly unimportant change in the order of the declarations and have the runtime go from a second to a week.
In this case the professor didn't (couldn't) know how long a Prolog program to solve this problem should take. He just assumed that you had found a more efficient ordering for the declarations. He might even have thought it was luck rather than deep insight that your program was faster than his. But you have to a decent understanding of the limits of Prolog to get a complex program to complete in a reasonable time, so you had to be good before you could get that lucky.
If you couldn't already tell, I have a low opinion of Prolog and declarative languages. They are "parlor tricks". Much like computer 'Life' and neural networks, simple programs can produce unexpected seemingly-sophisticated results. But they don't get better from those initial results. To compute the answers or results you want in a reasonable time, you end up with at least the complexity of writing things in the traditional explicitly procedural method.
The promoters of declarative language typically don't mention that you end up writing rules in an explicitly procedural order if you want the program to work. If you press them on the issue, they then say "well, OK, it's not actually any easier to write, but it's easier to verify that you've correctly specified the desired result." But if you have to carefully shuffle declarations around, and even then some results unpredictably take centuries to compute, pretty much no one cares.
Re:Prolog Assignment (Score:4, Informative)
General-purpose declarative languages are bunk, I agree.
However, domain-specific declarative languages often work pretty well. Consider build systems (Make, ant, etc.), or SQL, both of which are declarative.
Comment removed (Score:4, Interesting)
complex finance math (Score:3, Funny)
I worked with some finance guy who was convinced that the square root of a negative number -x was -sqrt(x), and wouldn't hear otherwise. I hacked sqrt(x) to return sgn(x)*sqrt(fabs(x)), but he complained that when he squared the answer, he didn't get back a negative number. Luckily our code was C99 so I changed his dollar type to be "double complex", made him use the complex sqrt, and changed his print function to display creal(x) - cimag(x). The guy said things worked great. I was glad to hear that, but it still feels wrong that part of our finance system is handling complex number of dollars, whatever that means.
Re: (Score:3, Funny)
> I was glad to hear that, but it still feels wrong that part of our finance system is handling complex number of dollars, whatever that means.
What? I'm sure most finance guys are adept enough at counting both real and imaginary dollars, so having complex dollars isn't really that complex...
Re: (Score:3, Insightful)
I learned long ago that regular math and financial math follow very different rules.
Who hasn't? (Score:5, Funny)
After years of programming, I guess everyone had to cut some corners sometimes. It's also not (always) a problem of goofing off, a module you depend on not shipping in time but you being required to keep your deadline can already force you into doing just that: Delivering a hack that 'kinda-sorta' works, or at least the customer won't notice 'til we can ship the patch.
Yes, that happens often. It's dubbed "Bananaware". Delivered green and ripens with the customer.
I knew a guy who pulled a hack like this (Score:3)
it made a total hash out of what I was trying to do. But he lost the source code, so I couldn't prove that he did it. Of course we couldn't fix it either. It was in code that calculated people's paychecks. He got fired. I quit.
Wow am I the only one in here (Score:3, Insightful)
I haven't implemented a fully finished system by the deadline in years simply because I can't squeeze 3 months work into 1 month.
Re: (Score:3, Interesting)
Here is my strategy for dealing with this situation:
1) Tell the salesmen that you have absolutely no problem with them telling the customer whatever they want. Their function is to make sales to customers. Your function is to write software. You won't try to tell them how to do their job, because quite frankly you aren't qualified to know what's best for sales. Of course the implication is that they shouldn't tell you how to write software, but you probably don't have to tell them this explicitly (well,
Customers (Score:3, Insightful)
Yes. But mostly it's not to "make it work"; it's because the customer wants something that is entirely against the original design they asked for.
char Str[255] (Score:3, Informative)
char Str[255];
sprintf(Str, "%s, %s", Lastname, FirstName);
I really wish snprintf was available on my C implementation.
Re:char Str[255] (Score:5, Insightful)
I believe another name for that little snippet is "buffer overflow vulnerability".
Configurable sleep() (Score:3, Interesting)
So we had a race condition on database transactions using two-phase commit, your usual mind-fucking WTF situation, drove us up the walls for days, you all know what I mean. We knew it was a race condition because if we put a sleep() statement at the end of one of the transactions, everything ran fine. sleep(10) was always long enough, and since all of this ran asynchronously in the back end, an end user would never notice the difference.
So we went to the customer. We told them that we could continue to bust our brains trying to find a "real" fix, and didn't know how long that would take, or we could just leave the sleep() in. And we could even make the length of the sleep interval configurable, so they could try to make it shorter than 10 seconds, if they really felt like fiddling around with it.
The customer went for the configurable sleep().
VB6: Lost source code - Ultimate repack (Score:5, Interesting)
. We finished converting a few rogue scripting modules and things like that, which creep in over time. But we COULD NOT find the source code to one of our VB6 DLLs (an old one that had not been changed since it was first compiled in VB6). We searched and searched and eventually the fastest coder(not me) started rewriting it. We were 1 day from delivery date and there was no way he could finish it, so I ran it through a disassembler.
the C++ code we delivered looked like this:
int functionName(int parm) {
_asm {
push esi
mov esi, dword ptr ds:[esp+8]
mov dword ptr ds:[edi], esi
retn
}
It was unreadable, but it compiled and worked and we got our money. I still wonder what they ever did with that... since the software is still in use...
Re:VB6: Lost source code - Ultimate repack (Score:5, Funny)
"Wow, assembler code."
"It must be highly optimized."
"Told you it was a good idea to buy it."
I program small games (Score:4, Funny)
And, I never split my code into multiple files - scroll and Ctrl+F were good enough for my grandfather, and they're good enough for me!
The Fucksort Incident (Score:5, Funny)
Apparently, however, Visual C++ includes a mysort in its standard library. So, with the clock ticking down and the solution's only impediment to our victory being an identifier conflict, I renamed the routine the way that any one of us would have: myfuckingsort. We won the competition.
In this particular competition, the judges were not supposed to read our code - they just run the output of your code on the input and check for correct output - so I felt safe when I typed what I did. However, one of them came up to us afterwards and told us that they do in fact usually read the code of the winning team to see if we did anything unique in our solution. Yep. Sure did. And my classmates and professors never did let me live down what was affectionately nicknamed the fucksort algorithm.
Re:Wow. Talk about old news. (Score:5, Funny)
The editor might have approved this submission just to meet some kind of deadline or a minimum requirement.
Re:Wow. Talk about old news. (Score:5, Insightful)
Re: (Score:3, Interesting)
Quick, find the dupe and copy-paste all the +5 Insightfuls!
Re:Wow. Talk about old news. (Score:5, Funny)
> it's the comments that are worth reading
More specifically the comments in the article. I loved this one:
"Back on Wing Commander 1 we were getting an exception from our EMM386 memory manager when we exited the game. We'd clear the screen and a single line would print out, something like "EMM386 Memory manager error. Blah blah blah." We had to ship ASAP. So I hex edited the error in the memory manager itself to read "Thank you for playing Wing Commander.""
That's awesome.
Re:Really? Not Slashdot's fault, if so... (Score:5, Funny)
Where'd he get to anyway?
Re:Really? Not Slashdot's fault, if so... (Score:5, Informative)
Re: (Score:3, Funny)
Re: (Score:3, Interesting)
Re:Deadline is not the problem (Score:5, Insightful)
In the real world there are deadlines, and it's entirely the developer's responsibility to be able to meet those deadlines without using such "dirty coding tricks". Good developers should have tested their code so as to not have serious problems to fix at the last minute, and designed it so as to be able to extend it easily.
Yes, because deadlines are always reasonable and never pushed up. And change orders are a myth.
Re:Deadline is not the problem (Score:5, Insightful)
Wait, you were serious? Does your hair come to points on the side of your head, by any chance?
If I could cope with unreasonable deadlines without some sort of nasty compromise, I wouldn't be developing software. I'd be turning water into wine, holding back the tide, etc. "Good software developer" doesn't mean "miracle worker". If the time isn't there before the deadline to solve the problem correctly, either the deadline will be missed or the problem will be unsolved or poorly solved. That's close to a tautology; it's implicit in the term "unreasonable".
Re:Deadline is not the problem (Score:5, Funny)
Re:yuck (Score:5, Insightful)
Basically ALL the software you use works like this.
Welcome to the real world, no need to feel bad.
Re: (Score:3, Insightful)
Re: (Score:3, Interesting)
We do this at my job. We have a decent production database system, but we develop against a K6-2/400 with 256MB of RAM and a couple flaky SCSI disks. If it performs adequately there, it'll perform adequately anywhere.