[crowd:] Hi, Alex.
Back in the day, while fresh out of college and wet behind the ears in the programming world, I used to name some variables very badly.
The worst of which was my counter variable names. I now use i, j, k, and so on for local counts and things like activeRowCount for the more descriptive names. Before, in the early years mind you, it shames me to say, I would name my counters things like Dracula, Chocula, MonteChristo?. They are all counts after all. I apologize for my intial variable naming conventions and shall go beat my face now as punishment.
-- Alex
Don't use i, j, and k for iterators! Use ii, jj, kk. Convention is still honored, yet searchability is increased by a million percent. The vars i, j, and k are BadVariableNames too!
If your tools cannot search for single character variables, the problem is with your tools, not with the millions of lines of code and the thousands of programmers that have had no such problem. -- AdamBerger
Also, if you have to search for an iterator, you have bigger problems. The scope of such an iterator should be only a few lines anyway. -- DougKing
Um, that's the point of this pattern! Many times, programmers have to work under less than ideal situations. Sometimes nice developtment tools simply aren't available. On other occasions, old extremely simple or poorly designed programs have to be maintained or extended. The pattern, which I recommended, has a low cost, yet provides a useful safety net for future development. I'm also not the first to use this convention; I learned it from...
http://www.google.com/search?q=unmainnaming.html...and a quick google search shows many people also use it. -- Jimmy Cerra
None of that makes it a better pattern. The item about the scope being a few lines still applies. Any decent computer has vi: /\<i\> (notepad can search for whole words only too) or some similarly powerful editor.
l = l + 1; This = That + O;A PetPeeve of mine was someone I worked with who liked to name miscellaneous C character arrays "mystring". Was he afraid that someone else would come along and misuse his variable? (I think that misuse is much less likely if you give them a clue as to what the variable's *FOR*!)
Perhaps a habit derived from using the 'my' operator in PerlLanguage? -- DominicCronin
A good variable name should indicate its use, like "ErrorMessage" or "InputBuffer". And if it has several different uses, you should probably split it up into several different variables.
I couldn't believe this one: "Information" - duuhhh, so that's what it's for(!)
I have a class called Codes. It has a property called data. Guess what its type is... - that's right! CodeData? -- DorKleiman
Warning: NIL != NULL error on line 567 ^ Cannot assign NULL to NIL listener
I am working on a project right now, where I have taken over someone else's Java code. It often goes something like this:
public class Foo {i.e., the prefixes my, the and a are used a lot. Perhaps it is some kind of HungarianNotation? :)private String myString;
public Foo(String theString) { myString = theString;
int aPos1 = 0; int aPos2; // ... }
}
This is similar to UncleBobsNamingConventions. It takes some getting used to, but it can help make code read more like prose and disambiguate scopes.
const int TWENTY_EIGHT = 28;What in God's name were they thinking??? -- ChuckMcCorvey
The problem here is that you assume they were thinking! ;->
[Maybe they wanted to support other values of 28?]
At a past company, the coding standards forbid using MagicNumbers. We ran a tool that counted coding standards violations, and we included that value in our team status reports. I ended up defining FOUR = 4, etc., since I didn't have the time to enter meaningful names.
Maybe it was a descendent of an old UNIVAC program or by an old UNIVAC programmer? Twenty eight was the number of words per sector in old UNIVAC disk hardware and it lives on to this day. See http://www.fourmilab.ch/documents/univac/fastrand.html#28
(new speaker here) I actually did something very similar a year ago, to circumvent what seems to be a bug in the Microsoft C 5.1 compiler. While porting some code implementing the AdvancedEncryptionStandard? algorithm to a legacy DOS environment (!) I found the compiler choking on shifting certain values 8 bits to the right. But only when the literal digit 8 was used.
So I globally replaced
>> 8with
>> EIGHTand put
const int EIGHT = 8;at the top of the program. It worked great. Passed all unit tests. For some reason I don't think Microsoft will fix this particular bug, if indeed it is one.
I am not making this up. -- MarkSchumann
#define ONE 1 #define ZERO 0No, I'm not kidding. I'm glad I didn't have to work on it. -- RobCrawford
At least it wasn't the following:
#define ONE 0 #define ZERO 1
I guess the real solution is to never program in Fortran, and to not release old Fortran programmers into the world. ;-) -- Mike Gertz
Some people started programming a long time ago when FORTRAN was most of what there was. Some of us have adapted and do different things as well now. -- JohnFletcher
I think you are solving the wrong problem. You should define constants with names describing their purposes not their values. You need to define constants like "NumberOfFingersOnAHand" not "Five".
Let's not confuse fingers with digits. The human hand normally has five digits, only four of which are fingers, and one digit being the thumb. "NumberOfDigitsOnAHand" should be "five", "NumberOfFingersOnAHand should be "four"
''Let's also not forget polydactylism (or hermaphrodism)... The human body isn't really reliable enough to consign to constants.
Memory storage really was small, bulky and expensive by modern standards thirty years ago. I have a section of memory assembly 4K x 16 bit from a Honeywell 316 which is about the size of 2 Zip disks (holding 500 MBytes)!. Also the 0.0d0 was needed as otherwise the double precision variable was initialized with single precision zero and the rest nonzero rubbish. This could easily cause errors later. -- JohnFletcher
A similar trick was used often in AtariBasic, in which you would see the first line of a program looking like this:
10 N0=0:N1=1:N2=2:N3=3:N16=16:N100=100:N53248=53248The reason was that Atari BASIC would store every constant in a program as a float, which took about six bytes, even if the number was a really small integer. On the other hand, variable references used only one or two bytes. So large programs with big memory requirements would save memory with this trick. -- NickBensema
This trick was also used in Sinclair Basic on the Sinclair ZX81 (which was known as the Timex 1000 in some parts of the world). Because the machine only had 1Kb of memory as standard, it was common for the first two lines of any program to be:
10 LET O=PI-PI 20 LET I=PI/PIFloating point numbers were stored as five bytes, so this trick saved four bytes each time O or I was used. Also, the symbol PI only took up one byte (Sinclair BASIC was tokenized), so using PI-PI or PI/PI saved two more bytes in the initialization. -- SpencerCollyer?
#define ONE 0 #define ZERO 1There is a product out there that defines ONE as 0, and TWO as 1 to provide handy constants for a function taking an integer parameter
I worked once on a program that had a section of code sort of like this (my C is a bit rusty, so forgive any errors...)
#if FALSE ... some code. #endWhen debugging a section of code, I introduced a change that would break the "some code" bit, which I didn't care about because I was going to remove it shortly. Imagine my surprise when the "some code" bit failed to compile. It turned out that, about 2000 lines above this particular code snippet, somebody had done the following:
#define FALSE TRUE
I saw that some years ago in a C program. -- Jeff Grigg -- The coder used it in may loops and was trying to save space. (Not that automatic variables on the stack really take up much space!) It was a disaster when you had nested loops... in different functions! >-P
#define PI 3.14156in case you needed to change the ValueOfPi.
And if that's the value you were using for pi, you would need to change it!
(Yeah, yeah. :-) That was as much as I could remember at the time.)
I'll argue in favor of defining PI (but using a more accurate value ;-)
[Remainder of very lively discussion of the ValueOfPi moved.]
const int MinutesPerHour = 60;This is good, not because the value is likely to change, but so as to reduce confusion with SecondsPerMinute (which is also 60). -- DaveHarris
Recently encountered this in a production program, used to compare date/time values without the bother of converting to Julian dates:
year*980294400 + month*2678400 + day*86400 + hrs*3600 + min*60 + secIt's not an example of BadVariableNames, but it is an example of Bad MagicNumbers: It works, but when I double-checked the numbers, I was surprised to find that they assumed 366 MONTHS in a year!
2678400 seconds/month = 31 days/month * 24 hours/day * 60 minutes/hour * 60 seconds/minute 980294400 "seconds/year" = 366 months/year * 2678400 seconds/monthI can live with 31 days per month -- a reasonable compromise to compute a value used for sorting. But 366 months per year??? That's just an error - they clearly meant to do 366 days per year, but didn't get the numbers right.
A set of constants like this would have helped:
const SecondsPerMinute = 60; const MinutesPerHour = 60; const SecondsPerHour = SecondsPerMinute * MinutesPerHour; ...and so on, say with... const MaxDaysPerMonth = 31; ...-- JeffGrigg
Someone I went to University with claimed he used the characters in AnimalFarm for variable names - in commercial code.
I once had to read code where the variable names were all names in Tolkien or Frank Herbert's Dune.
I also had a discussion with a colleague who objected to using i and j as indexes in loops etc. He preferred US for universal subscript. Otherwise he was a wise programmer. We were both working on the same program -- in COBOL -- and so I went along with US, US2, and so on.
A German student in England wrote a large FORTRAN program where every integer variable had a name that started: ZEIT (meaning "time" in english.)
Using obfuscated and / or arbitrary variable names like this is bad for code that is supposed to be useful, but I found it very liberating when learning to code that I could throw the names in without having to bother what each variable is used for. It increases your programmer capability. :)
array = AllocateMemory(baseSize + isFooClipping)
Someone has "saved" code and time by reversing the sense of the global. So now we had a isFooClipping variable that's was TRUE (1) if you were not FooClipping!
-- PaulHudson
If and only if this is the least arcane solution, I routinely normalize integers in C (or even C++) as Boolean values (0 or 1) and use the Boolean value inside an integer expression. The correct way to do this is with the double-bang notation. For example, !!foo will normalize foo from 0 to 0 or non-zero to 1. Then I could use foo like "length = bar * !!foo;"--although "length = foo ? bar : 0;" is obviously clearer in this case. In the case of isFooClipping, a single bang would have been sufficient to invert and normalize the integral value. -- SunirShah?
const long ZHANYIZHOUQI = 1000; //1000 const long ZHANYIZHOUQI_WITH_NOZZLE_CHANGES = 100; // const int ENDING_SLOT_NUMBER_OF_FRONT_SIDE = 38; const int NOT_SHIELD = 0; const double PANZIGAILUU = 0.1;Anyone care to translate? -- ChrisBrooks
I have been writing some PythonLanguage programs for calculating sumo statistics. There just aren't useful English words for banzuke, sanyaku, heya, etc., but a sumo fan reading the code will know exactly what I mean. I think mixed languages are perfectly accessible in context. (For the record, a banzuke is a listing of ranks for wrestlers in a particular tournament, sanyaku translates as "three higher ranks" but means either the four highest ranks or the third and fourth highest ranks, and heya is usually translated as "stable" - it's essentially a wrestling club.) -- JohnFarrell
John, this isn't so much a case of using mixed languages, as using the domain language (in this case, sumo jargon) for variables. It's just a coincidence that the domain language consists of words from another natural language. -- RobertWatkins
Various languages are often mixed with English in European (Italian, German, Russian, Czech, Finnish...) code: typically there are technical words in English and domain words in local languages, and both categories are very difficult to eradicate completely. Many teams also contain a mix of developers who want to use English, developers who try to use English but make horrible mistakes, developers who don't care and developers who take pride in inventing convoluted or fuzzy neologisms in their national language. -- LorenzoGatti
VbUnit does this in several places:
On Error GoTo Hell ... Hell: ' Error handling code.(I changed all the error handling code labels to have more meaningful names, for the benefit of my customer, where we're trying to get more RegressionTesting going.)
For example, financial calculations in Smalltalk can be measurably affected by comparison tests such as
(aValue = 0) ifTrue: [].A trick I like is to replace this with
aValue ifZero: []where #ifZero: is appropriately implemented in the numeric generality system.
Question: When is 0 not Zero? Answer: When Zero is 0.0 or 0.00000 or '0 asDecimal'
Failure to test against the correct constant in a loop can force an unexpected coercion of aValue, significantly slowing the loop.
-- TomStambaugh
int temp = 0;AAARRRGGG!!!! ALL variables are temporary! The information content is ZERO (0) here!!!
I have to disagree: although temp/tmp/t *is* overused, inside small blocks it can concisely indicate that the variable is meant as scratch space.
BITS_PER_DEGREE = 72; FIVE_DEGREES = 325; /* (in BITS_PER_DEGREE) */And a little work with a calculator tells you that "FIVE_DEGREES" is really 4.513888... degrees.
[I guessed at the value for FIVE_DEGREES, from the text above. Please correct if I'm off. -- JeffGrigg]
If only it were so simple. I believe the conversion factor was 57.12-something-something bits per degree, for reasons that predated my time on the project and which now escape me.
FIVE_DEGREES .EQU 0101Hor something similar.
The conversion factors themselves never actually appeared in the code. They were written down in a several-year-old memo in a dusty ThreeRingBinder on the lead engineers' shelf. There was no point putting them in code - the 8088 assembler on the HP64000 development station had no preprocessing capabilities beyond simple (textual) macro substitution.
Why weren't the constants commented then? Well, the HP64000 assembler had problems dealing with input files larger than ??? bytes in size, and we were always close to those limits. Development environment limitations were just some of the many areas in which we pushed the limitations of the technology used on that project.
"Guns on the gun-deck," said the quartermaster, with intense relish. "He looked for to find 'em there; hor, hor."No doubt because she has no guns on her gun-deck... -- TomStambaugh"We only call it the gun-deck," explained Jack. "The guns are all on the upper-deck and quarter-deck, which is natural in a one-decker. The Wager is a one-decker, Toby."
"But there are at least four storeys, or decks, as you say in your jargon," cried Tobias, with some indignation.
"Ah," replied Jack at once, "we only call her a one-decker, you see."
The problem was that the program was actually manipulating a singly linked list, but the node record's "Next" pointer was named "Daughter"!
Not only does Daughter imply a hierarchy instead of a list, it would be more typing than using "Left" and "Right".
A linked list is a degenerate tree...
Granted, but in context the name obscured meaning.
int sz = list.size();Apparently, typing two more letters would have killed the guy.
I worked at a job where the GLOBALS!!!! were given one or two letter names in a 20,000 line program. No IDE, just use an editor. Oh yes -- printer variables often contained the vowel removed pnt or ptr. Never mind what pointers were called. Very frustrating.
For clarity I have called the local variable myV, but you could call it pizza or fireman if you liked.
The myV-example is part of a small (but complete) game, intended to show the benefits of using OO.
Brennan Young (author of the aforementioned lingo tutorial) adds: Out of context it looks as though I am recommending the use of 'pizza' or 'fireman', which is actually the opposite of what I am suggesting. In addition, 'me' in lingo is similar to Java's 'this', so use of the pronouns 'me' and 'my' in Lingo variables (and indeed in Applescript and other related languages) almost exclusively refers to the instance and not the programmer.
/* important global variables */ unsigned int x; unsigned int xx; unsigned int y; unsigned int yy;The only other comment in the entire system's code was /* Oooh, neat trick */.
Once I had to modify third party code with functions named X, Y and Z, each overloaded with completely different parameters and meaning. Apparently it was not a deliberate obfuscation attempt. -- LorenzoGatti
In theory, it could always be worse. What about variables with the perfectly valid names of _, __, ___, ____, _____, etc.? Of course, this is only made worse by the fact that most fonts don't clearly separate consecutive underscores; oddly enough, BitstreamVera Mono does make underscores distinct, but only in regular and not in bold. -- CodyBoisclair
At 19-04-2005 the link is dead: host not found
disclaimer: This is not a reflection of the code written at Lineo. My friend has not ever worked for Lineo. If you look at the other code for MP3::Daemon, it's rather sane compared to pimp. -- JohnBeppu
#define AND |I have seen this too. The explanation from the programmer was that they got confused by building a bitmask with the | operator, like
FileAccessMask = O_READ | O_WRITE | O_BINARY ;They thought that it would be less confusing to write:
FileAccessMask = O_READ AND O_WRITE AND O_BINARY ;I could not convince them that defining OR as AND was potentially a lot more confusing, and they would be better off getting used to the idiom of building bitmasks with |. I have also often seen people use:
FileAccessMask = O_READ + O_WRITE + O_BINARY ;This works fine as long as each symbol represents a discrete bit, but often leads to errors when combined masks are used:
NORMAL_ACCESS = O_READ ; FileAccessMask = NORMAL_ACCESS + O_READ + O_WRITE + O_BINARY ; //wrong! FileAccessMask = NORMAL_ACCESS | O_READ | O_WRITE | O_BINARY ; //OK!Windows has a lot of predefined combined masks, so whereas a UNIX programmer may get away with this idiom, in Windows you will get caught out eventually.
So the convention starts and my buddy's game is the center piece of the Microsoft booth. Their game is supposed to be running on a giant 16 foot screen over the booth.
So they try to install it on the Microsoft booth machines and....it does not work.
The company owner is there. The Microsoft VP in charge of the project is there. Crowds are now entering the convention hall. The Microsoft tech guys running the booth are helping trouble shoot. They think maybe its the drivers, maybe it is the version of the OS. no. no. They open the registry with regedit. Sure enough there was the problem. The variable BILL_GATES_IS_AN_******* was incorrectly defined by the install program.
Right on the 16 foot screen in regedit.
Microsoft was not amused.
I was glad when we dropped that applet a few months later! -- JohnWebber
(ancient Java applet? What would you call 15 year old C code I have to maintain???)
On a related note, I recently had to fix some bugs in some legacy Java code that was notorious for scattered and interconnected sections of code that were never used. It was the definition of SpaghettiCode. There was no way I would have been able to make the fixes without first wasting a lot of time trying to understand the code. I used a my favourite Java IDE (in my case IntellijIdea) which was great at finding unused methods and variables, as well as doing automated refactorings (such as changing bad names and removing unused parameters from method signatures). What a life-saver. It only took a couple of days to clean up the code and then making the fixes was pretty straightforward.
At another company I worked for, one of the previous employees had a habit of naming his nouns after places and people. So you'd have variables like texas, newyork, ... Then he'd name the method names stuff like "sucks" so the code would read "texas.sucks()"
It was a great.
I’d almost think texas might’ve been a state in a finite state machine…
Once I was receiving JavaScript Code for webpage. I checked the code and saw that a colleague named the variables like "idiot". The variable holds the login name of the customer. What will you think about a company which names its customers "idiot"? -- AndreasSchweikardt
Another story:
String str1 = "ACCOUNT"; String str2 = "USER"; String str3 = "AMOUNT"; .... String str18 = "ITEMS"; String value; value = getFromDB(str0); callMethod(value); value = getFromDB(str1); callMethod(value); .... value = getFromDB(str18); callMethod(value);str0 to str18 are used only once. -- AndreasSchweikardt
That looks a bit like something that certain automated tools for i18n or string externalization would generate.
No, that guy wasn't that smart like an automated tool.
#define TRUE 1 #define FALSE 0Nothing unusual or nasty about that. However, when our application #included another header, which did the following (which is less acceptable; it was from a locally-developed PinkyAndTheBrain library):
typedef int Bool; #ifdef FALSE # undef FALSE #endif #define FALSE ((Bool)0) #ifdef TRUE # undef TRUE #endif #define TRUE ((Bool)(!FALSE))or something like that. When we built our app, though, all hell broke loose. As it turned out, not because any incompatibility between the two definitions of TRUE and FALSE, which happened to be true (!0 is equal to 1 in our environment, though C doesn't guarantee that in general). The same header files from WindRiverSystems also featured this nonsense, to conditionally include/exclude code.
#if FALSE /* excluded code */ #endifWith FALSE redefined to be the text "((Bool)0)", this caused the preprocessor to puke.
The lessons learned:
$chomp, @chomp, %chomp $print, @print, %print $foreach @foreach %foreachWhich means you could conceivably write the following valid Perl:
print push @chomp,chomp $print{$foreach} foreach $foreach (keys %print);But please don't! (As seen originally in comp.lang.perl.misc at http://groups.google.com/groups?selm=tqlfcc.trn.ln%40goaway.wombat.san-francisco.ca.us .)
<reinserted after a revert:> Actually, I understood all that on the first pass, thanks to perl's sigils. While some people love to hate PerlLanguage PerlLanguage for its "ugly" syntax, there's a lot of clever stuff going on with it. Then again I've been programming in perl for some 8 years, and it has undoubtedly fried my brain.
<Perl has cool stuff going on, but regarding brain damage, apparently, yes.>
INTEGER REAL REAL INTEGERAnd you thought the Perl statement above was a headache to parse!IF (IF .EQ. THEN) THEN THEN = ELSE ELSE ELSE = IF ENDIF
A similar example in PliLanguage was mentioned in the Organization of Programming Languages class I'm in:
IF IF = THEN THEN THEN = ELSE; ELSE ELSE = END; END;-- CodyBoisclair
sesquipedalium phrasum - Cinematic Emporium - programmerese - i sesquipedalium phrasum - super sensorium - programmerese - j sesquipedalium phrasum - mutual masturbatorium - programmerese - kThere. That's much clearerThe new i Is not just a j But a highly effectual, Heterosexual k
public class AccountPermissionsRulesDipswitch? {
Dipswitch? A dipswitch is a thing for manually selecting clock speeds, bus timings etc. on a motherboard, or manually selecting the network address on ancient Arcnet network cards. Are you telling me that an administrator has to configure account permissions by manually changing dipswitches on the server? I'm going home...
Sounds like a dipshit.
private final static String DPHFROMACC = "DPHFROMACC";
Why?
To avoid typo's?
It's used a massive total of once. Maybe he just wanted to be sure. :-)
# Run a file through ProcessTemplateNew?.pl # Requires at least 2 arguments: template_file query_file [[arg3] [arg4] [arg5] [arg6] [arg7] [arg8] [arg9]] do_template() { ${PerlDir?}/ProcessTemplateNew?.pl "${3}" "${4}" "${5}" "${6}" "${7}" "${8}" "${9}" < ${1} > ${2} MyResult?=$? if [[ ${MyResult?} -ne 0 ]] then exit_msg "Cannot generate template ${1}" fi }
##00=$ARGV[0] ##99=$ARGV[1] ##01=dc_addmonth($ARGV[2],0) ##02=dc_fmtmdy(dc_firstday($ARGV[2])) ##03=dc_fmtmdy(dc_lastday($ARGV[2])) ##04=dc_fmtmdy(dc_addcrdays(dc_lastday($ARGV[2]))) ##05=dc_fmtmdy(dc_firstday(dc_addmonth($ARGV[2],-1))) ##06=dc_fmtmdy(dc_lastday(dc_addmonth($ARGV[2],-1))) ##07=dc_fmtmdy(dc_addcrdays(dc_lastday(dc_addmonth($ARGV[2],-1)))) ##08=dc_fmtmdy(dc_firstday(dc_addmonth($ARGV[2],-24))) ##08=dc_fmtmdy(dc_firstday(dc_addmonth($ARGV[2],-23))) ##09=dc_fmtmdy(dc_lastday(dc_addmonth($ARGV[2],-7))) ##09=dc_fmtmdy(dc_firstday(dc_addmonth($ARGV[2],-5))) ##10=dc_fmtmdy(dc_firstday(dc_addmonth($ARGV[2],-6))) ##11=dc_addmonth($ARGV[2],-1) ##12=dc_addmonth($ARGV[2],-60) ##13=dc_addmonth($ARGV[2],-59) ##80=$ARGV[3] eq ? : '--'
Back when I wrote code for the Mac for a living, the Mac system headers actually defined global variables named h & v. Never tracked them down to see exactly where they came from, but I was always horrified whenever I discovered shipping code of mine that used h & v & forgot to declare them locally.
When I'm in the zone, & I just can't think of an appropriately descriptive name, I'd rather use "bob" or "foo" or "dracula" & get things done than agonize until I come up with a GoodVariableName?. I usually try to fix them later, but sometimes I don't.
See: GoodVariableNames, MeaningfulName, MeaningfulVariable, CodingConventions, HowToWriteUnmaintainableCode, PetPeeve, MetasyntacticVariable and FunnyThingsSeenInSourceCodeAndDocumentation, UnderscoreVersusCapitalAndLowerCaseVariableNaming, DontNameClassesObjectManagerHandlerOrData
This page mirrored in WikiPagesAboutRefactoring as of April 29, 2006