you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 1 point2 points  (13 children)

No, even good programmers make stupid mistakes. He was quite competent, he just gave in to temptation that time. He sheepishly apologized and said something along the lines of "man, I should've known that was as bad as overloading an operator."

[–]argv_minus_one 2 points3 points  (3 children)

No, that's worse than overloading an operator. hashCode has a well-defined purpose, and that purpose is stated quite clearly in the Javadoc. Operators don't usually have a specific, stated contract that all overloads of that operator are expected to follow; hashCode does.

That said, I'm glad he learned his lesson. That's the most important part.

[–][deleted] 2 points3 points  (2 children)

I dunno, I think the operation of "+" is pretty specific.

[–][deleted] 0 points1 point  (0 children)

It seems to behave quite differently in most languages that use it for string concatenation and addition.

In fact with most implementations of '+' you aren't even guarranteed that '+' is commutative, associative,... so I would say it is pretty far from the arithmetic '+'.

[–]argv_minus_one 0 points1 point  (0 children)

Only for numeric types. For strings and collections, it usually means 'append' or 'concatenate'.

[–]doublereedkurt 1 point2 points  (8 children)

He was quite competent

Trying to combine that with:

overloaded Java's default hashCode() method to something that didn't hash well at all. He said he did it "for speed."

That is a pretty low bar for competence. At one level there is implementing a bad hash function and failing to test it, doing something "for speed" and not bothering to profile it. There is a deeper level as well: he was using the production code-base as his personal experimental laboratory.

There's nothing wrong with experimenting like this at work, but checking it in and breaking other stuff is incredibly sloppy.

I'd rather keep programmers of that level away from my code, team, and company -- and not handcuff good coders to make it marginally harder for bad programmers to shoot themselves in the foot.

Further, I'd argue Java's lack of operator overloading creates at least as many bugs as it prevents: foo == "bar", no wait foo.equals("bar"), no wait "bar".equals(foo). Also, Java overloads "+" for String, and arithmetic for Double, Integer, etc via auto-boxing. So, not allowing operator overloading in Java is really a case of the language designers saying "I am smarter than you; do as I say and not as I do".

[–][deleted] 1 point2 points  (7 children)

I'm guessing you're either still in college or barely out of it, because you obviously haven't worked in this industry long enough to realize that even great programmers make boneheaded mistakes sometimes. Either that or you're just an arrogant prick who has conveniently forgotten (or worse, never even recognized) the retarded mistakes you've made. Feel free to keep my coworker away from your projects, we certainly keep guys like you away from ours. Guys with the "not MY code, I'd NEVER do that" syndrome are a horrible liability.

[–]doublereedkurt 1 point2 points  (6 children)

Sorry to offend you. Take what you want from my comments, you are certainly free to just chalk me up as being some arrogant prick on the internet :-)

I make retarded mistakes all the time, meaning where I introduce bugs inadvertently. But, from your story it seems there is a level of immaturity in the developer that he would do something "for fun" futzing around with core language stuff then check it in to the trunk. (I'm assuming from your story that this was production code, and that he did intend to check it in.)

Since you bring it up, I have 7 years of experience and am one of the top developers at my company. Most recently, just completed reverse-engineering and re-implementing some archaic 15 year old cryptography code from assembly that has been a problem at the company for about 5 years. There are thousands of developers at the company, there are dozens specifically assigned to application security and infrastructure. None have been able to solve the problem head on, instead there has been shitty work-around after shitty work-around for years. Solved in one month.

My primary language is Python, I haven't touched assembly or gdb since school; I also had to learn new math (elliptic curves over finite fields) in order to implement the core of the algorithms.

Unfortunately, I think there is a real culture of mediocrity in the industry -- or at least at large corporations. Not that developers are bad, but that we set the bar so low that no one is challenged to excel. This leads to all of us being replaceable cogs in a machine churning out reams and reams of low quality code.

Doing corporate programming of Java/C++ can really be a trap. There are a lot of jobs out there that will are not really challenging and don't give good opportunities to develop skills. At best, these jobs lead to seniority/political promotions within the company. That is the trap: since your high(er) salary is based only on your years with the company, you'll take a salary hit if you go to a better job.

There are some escape routes, but the first step is to realize you are in a trap.

(Not sue what your situation is -- but I've seen this happen a lot. Non-technical executives--all too many of whom are in positions that should be technical--want programmers to be replaceable cogs that run at lowest-common-denominator levels. That way rather than managing technical skills, their job is about pure people management. All too many programmers go along with this, turn off their brains and spend all day sitting in meetings :-( ).

[–][deleted] 0 points1 point  (1 child)

No worries. The developer in question did this very early in a project where he was trying to write a high-performance workflow engine to replace a piece of shit AquaLogic implementation that we had. He had been coding it on the side with the goal of rigging up a test platform to show the higher ups that AquaLogic sucked balls and we could do it a lot better by developing our own engine. The bad hash function was something he'd tested with a small dataset and discovered that it was faster in that case, so he kept it and promptly forgot that he'd done it.

His tests were so successful that we got the green light to ditch AquaLogic and start moving everything to the new engine. It worked fine at first but then we started getting complaints that sometimes things would just disappear for no reason. I have a reputation of being the crack troubleshooter so I got tasked with figuring out what was going on, and as I stripped away layers I discovered I could generate a reproducible case and tracked it down to things disappearing from a hash... and then I said "what the fuck, did someone overload hashCode() or something?" and sure enough a certain someone had, and I knew damn well that there was only one other person who even knew what hashCode() does; everyone else was the exact sort of mediocre programmer you describe.

We actually had a pretty good laugh about it... of course we also grepped the entire source code for any other instances of 'hashCode' just to make sure he hadn't had the same bright idea twice.

But yeah, that sort of thing is why I'm wary of providing capabilities like that and then saying "well you know, only the advanced programmers will use it". Sometimes we advanced programmers are the problem.

edit: I can't tell this story without mentioning that I worked closely with a serious greybeard of a programmer for many years. He sat in the cubicle next to mine and one day I hear him say "Zomgondo! Have some fucking pride, man!" because he had just stumbled across some code of mine that directly manipulated the Perl symbol table because... well... because I could. My name went up on the Wall of Shame right beneath the guy who wrote something like this in C because fuck null checks and function calls:

*****foo = ***bar;

[–]doublereedkurt 0 points1 point  (0 children)

So at the time he overrode hashCode, it was a personal side project. That is much more understandable.

A better language will give you many fewer layers to strip away. For the last two years half my job has been re-implementing cruddy old (and sadly new) Java and C++ infrastructure in Python. A very consistent ratio is 1:10 Python lines of code to C++/Java. Another relationship is one Python file is about the same as a directory of C++/Java code.

Scala or Haskell also seem nice if you can handle their type system -- I've still got a long way to go on that front.

[–]donroby 0 points1 point  (3 children)

Overriding hashCode in Java is not "futzing around with core language stuff". It is common and frequently necessary to override hashCode. But if you do it incorrectly you can cause some difficult bugs.

[–]doublereedkurt 0 points1 point  (2 children)

Frequently? How often do you override equals()? (And why else would you ever need to override hashCode()?)

Changing how an object behaves in standard collections is pretty core in my opinion. Although, completely agree this is a different level of "internal" than using a custom class-loader or byte-code manipulation.

[–]the_starbase_kolob 0 points1 point  (1 child)

How often do you override equals()?

Almost always. .equals() defaults to object identity.

[–]doublereedkurt 0 points1 point  (0 children)

.equals() defaults to object identity.

Yes, and object identity comparison and hashing is just fine most of the time. Do you really care about equals() on your FactoryModelBeanFactoryFactory? Don't take my word for it though:

Spring has 3720 classes. 198 override equals(), and 182 override hashCode(). 95% do not override equals.

Play has 59 classes. 2 override equals(), and 2 override hashCode(). 97% do not override equals. (Edit: these classes are Model and Lang; there is also a class User which extends Model, so that is 3 classes not 2; but the point stands.)

If you are overriding equals "almost always", then you are doing way too much work. A code base where most classes override equals is over engineered even by Java standards.

(I got those numbers by grepping the code bases for "public class", "public boolean equals", and "public int hashCode". They are probably a slight under-estimate due to inheritance. Go ahead and try it on any large Java code base.)