views:

1057

answers:

17
+17  Q: 

Constant abuse?

I have run across a bunch of code in a few C# projects that have the following constants:

    const int ZERO_RECORDS = 0;
    const int FIRST_ROW = 0;
    const int DEFAULT_INDEX = 0;
    const int STRINGS_ARE_EQUAL = 0;

Has anyone ever seen anything like this? Is there any way to rationalize using constants to represent language constructs? IE: C#'s first index in an array is at position 0. I would think that if a developer needs to depend on a constant to tell them that the language is 0 based, there is a bigger issue at hand.

The most common usage of these constants is in handling Data Tables or within 'for' loops.

Am I out of place thinking these are a code smell? I feel that these aren't a whole lot better than:

const int ZERO = 0;
const string A = "A";
+4  A: 

That definitely a code smell.

The intent may have been to 'add readability' to the code, however things like that actually decrease the readability of code in my opinion.

instanceofTom
yeah, it's unreadable :)
Phil
+12  A: 

Am I out of place thinking these are a code smell? I feel that these aren't a whole lot better than:

Compare the following:

if(str1.CompareTo(str2) == STRINGS_ARE_EQUAL) ...

with

if(str1.CompareTo(str2) == ZERO) ...
if(str1.CompareTo(str2) == 0) ...

Which one makes more immediate sense?

Anon.
str1.Equals(str2) makes sense :p
Tim Robinson
That is true. However, consider the case where we compare once and then switch based on the result.
Anon.
Id say the 2nd set of code makes more sense, if I see a named variable like STRINGS_ARE_EQUAL, it will strike me as odd and I will go look and see what the deal is. If i see "...CompareTo(str2) == 0)" or "str1.Equals(str2)" I instantly know what is happening and I can move on.
instanceofTom
@Tnay: If you fell the need to look up the value of every named constant, I think that says more about the "smell" of your fellow developers than anything else.
Anon.
If you need to look up the value of named constants then something is horribly wrong with the design of the code.
Paul Sasik
Well, the very last one makes the most sense to me. Comparisons in .NET consistently return -N, 0, or N to indicate order, and if you're a .NET programmer and don't know that idiom, you should learn it.
mquander
I use == instead of .Equals for strings. For maximum readability.
recursive
What more, it's not just "in .NET" - it is a very old idiom, at least as old as C `strcmp`, and possibly older. It's also very widely used, including high-level languages.
Pavel Minaev
Anon- what's your opinion- you don't state it in your answer!
RichardOD
@recursive, don't forget someString.Equals(someObject) instead of someString == someObject
Tim Robinson
If you use 0, everybody with any experience knows what it is. Inexperienced developers might have to look it up, but they'll learn. Use STRINGS_ARE_EQUAL, and nobody will actually know what it is. They'll have a good idea, but the fact that something odd is happening will make them check. The more experienced ones will remember times they were badly bitten by assuming a constant was what they thought it was.
David Thornley
@recursive, @Tim Robinson: http://blogs.msdn.com/ericlippert/archive/2009/04/09/double-your-dispatch-double-your-fun.aspx has some interesting notes on this.
Jeremy McGee
I'd ask: Which makes more sense to someone who doesn't know anything about `string.CompareTo()`?
DanM
If you have to do that much string comparison, define extension methods on string: `string.IsLessThan(string)` and/or `string.IsGreaterThan(string)`. But for equality, please, use `string.Equals(string)`. That's what it's for.
Kyralessa
+1  A: 

I'd go for code smell. If these kinds of constants are necessary, put them in an enum:

enum StringEquality
{
    Equal,
    NotEqual
}

(However I suspect STRINGS_ARE_EQUAL is what gets returned by string.Compare, so hacking it to return an enum might be even more verbose.)

Edit: Also SHOUTING_CASE isn't a particularly .NET-style naming convention.

Tim Robinson
enum casting doesn't follow any .NET style conventions I've seen either.
micahtan
@micahtan, hence the word 'hack' - not really a serious suggestion
Tim Robinson
+1  A: 

i don't know if i would call them smells, but they do seem redundant. Though DEFAULT_INDEX could actually be useful.

The point is to avoid magic numbers and zeros aren't really magical.

Paul Sasik
yea default_index could be useful if you want to maintain forward compatability in the event that microsoft change from 0 based indexing to -13 based indexing....
Paul Creasey
@Paul, I thought that was a feature in .NET 4.0 -- You can change your index base in the web/app config file. : )
Bryan Rowe
+4  A: 

Some people consider any raw number within a program to be a 'magic number'. I have seen coding standards that basically said that you couldn't just write an integer into a program, it had to be a const int.

tloach
Yeah, I've run into this before. The code standard says "no magic numbers" and an overzealous SQA person says using 0 is a magic number. I'm imagining a frustrated programmer placating them with a quick series of consts.
John D.
i've seen this too. Thing is, there are always exceptions and zeros ought to be an exception to the magic numbers rule.
Paul Sasik
We did this at one place I worked, because we had offshore developers that were less than stellar. It was much easier to enforce "all raw numbers are magic numbers" than any other standard we could come up with.
Dean J
+10  A: 

Abuse, IMHO. "Zero" is just is one of the basics.

Although the STRINGS_ARE_EQUAL could be easy, why not ".Equals"?

Accepted limited use of magic numbers?

gbn
I agree. I'm all for readability, but you have to expect some core competency. +1
Aaron Daniels
+3  A: 

Am I out of place thinking these are a code smell? I feel that these aren't a whole lot better than:

const int ZERO = 0;

const int A = 'A';

Probably a bit of smell, but definitely better than ZERO=0 and A='A'. In the first case they're defining logical constants, i.e. some abstract idea (string equality) with a concrete value implementation.

In your example, you're defining literal constants -- the variables represent the values themselves. If this is the case, I would think that an enumeration is preferred since they rarely are singular values.

micahtan
+2  A: 

You should have a look at some of the things at thedailywtf

One2Pt20462262185th

and

Enterprise SQL

astander
A: 

If the zero indicates something other than zero (in this case STRINGS_ARE_EQUAL) then that IS Magical. Creating a constant for it is both acceptable and makes the code more readable.

Creating a constant called ZERO is pointless and a waste of finger energy!

Brian
I'd argue that zero isn't magical in that sense either. String.Compare follows the usual standard concerning return values to indicate success/failure -- what is so magical about that?
Bryan Rowe
It's magic because it indicates something other than zero. Readable code is readable code, standards or not.
Brian
0 is a well known return value. I think 0 meaning true/false, success/fail are all obvious.
Bryan Rowe
+2  A: 

That is definite bad coding.

I say constants should be used only where needed where things could possible change sometime later. For instance, I have a lot of "configuration" options like SESSION_TIMEOUT defined where it should stay the same, but maybe it could be tweaked later on down the road. I do not think ZERO can ever be tweaked down the road.

Also, for magic numbers zero should not be included.

I'm a bit strange I think on that belief though because I would say something like this is going to far

//input is FIELD_xxx where xxx is a number
input.SubString(LENGTH_OF_FIELD_NAME); //cut out the FIELD_ to give us the number
Earlz
A: 

Smells a bit, but I could see cases where this would make sense, especially if you have programmers switching from language to language all the time.

For instance, MATLAB is one-indexed, so I could imagine someone getting fed up with making off-by-one mistakes whenever they switch languages, and defining DEFAULT_INDEX in both C++ and MATLAB programs to abstract the difference. Not necessarily elegant, but if that's what it takes...

Kena
+1  A: 

Is this code something in your office or something you downloaded?

If it's in the office, I think it's a problem with management if people are randomly placing constants around. Globally, there shouldn't be any constants unless everyone has a clear idea or agreement of what those constants are used for.

In C# ideally you'd want to create a class that holds constants that are used globally by every other class. For example,

class MathConstants
{
 public const int ZERO=0;
}

Then in later classes something like:

....
if(something==MathConstants.ZERO)
...

At least that's how I see it. This way everyone can understand what those constants are without even reading anything else. It would reduce confusion.

Daniel
What benefit would you get from MathConstants.ZERO ?
Bryan Rowe
What I'm getting at is that it is an agreed upon constant rather than constants that are written all over the place. This way, any future developer can easily understand constants. Like FIRST and SECOND, are confusing to me, but if they were agreed upon constants by the team, it would be far more understandable. At least that's how I see it.
Daniel
A: 

Right you are to question this smell young code warrior. However, these named constants derive from coding practices much older than the dawn of Visual Studio. They probably are redundant but you could do worse than to understand the origin of the convention. Think NASA computers, way back when...

grenade
A: 

You might see something like this in a cross-platform situation where you would use the file with the set of constants appropriate to the platform. But Probably not with these actual examples. This looks like a COBOL coder was trying to make his C# look more like english language (No offence intended to COBOL coders).

Ken Lange
What!? I *always* take the opportunity to offend COBOL coders! :-)
Chris Dwyer
A: 

There are generally four reasons I can think of for using a constant:

  1. As a substitute for a value that could reasonably change in the future (e.g., IdColumnNumber = 1).
  2. As a label for a value that may not be easy to understand or meaningful on its own (e.g. FirstAsciiLetter = 65),
  3. As a shorter and less error-prone way of typing a lengthy or hard to type value (e.g., LongSongTitle = "Supercalifragilisticexpialidocious")
  4. As a memory aid for a value that is hard to remember (e.g., PI = 3.14159265)

For your particular examples, here's how I'd judge each example:

const int ZERO_RECORDS = 0;
// almost definitely a code smell

const int FIRST_ROW = 0;
// first row could be 1 or 0, so this potentially fits reason #2,
// however, doesn't make much sense for standard .NET collections
// because they are always zero-based

const int DEFAULT_INDEX = 0;
// this fits reason #2, possibly #1

const int STRINGS_ARE_EQUAL = 0;
// this very nicely fits reason #2, possibly #4
// (at least for anyone not intimately familiar with string.CompareTo())

So, I would say that, no, these are not worse than Zero = 0 or A = "A".

DanM
first_row and default_index are just used when iterating through a loop. IE: (for int i = default_index...). first_row is used in the same way when iterating over a data table.
Bryan Rowe
If that's how they are used, I'd definitely say code smell then.
DanM
+2  A: 

I think sometimes people blindly follow 'Coding standards' which say "Don't use hardcoded values, define them as constants so that it's easier to manage the code when it needs to be updated' - which is fair enough for stuff like:

const in MAX_NUMBER_OF_ELEMENTS_I_WILL_ALLOW = 100

But does not make sense for:

if(str1.CompareTo(str2) == STRINGS_ARE_EQUAL)

Because everytime I see this code I need to search for what STRINGS_ARE_EQUAL is defined as and then check with docs if that is correct.

Instead if I see:

if(str1.CompareTo(str2) == 0)

I skip step 1 (search what STRINGS_ARE... is defined as) and can check specs for what value 0 means.

You would correctly feel like replacing this with Equals() and use CompareTo() in cases where you are interested in more that just one case, e.g.:

switch (bla.CompareTo(bla1))
{
     case IS_EQUAL:
     case IS_SMALLER:
     case IS_BIGGER:
     default:
}

using if/else statements if appropriate (no idea what CompareTo() returns ...)

I would still check if you defined the values correctly according to specs.

This is of course different if the specs defines something like ComparisonClass::StringsAreEqual value or something like that (I've just made that one up) then you would not use 0 but the appropriate variable.

So it depends, when you specifically need to access first element in array arr[0] is better than arr[FIRST_ELEMENT] because I will still go and check what you have defined as FIRST_ELEMENT because I will not trust you and it might be something different than 0 - for example your 0 element is dud and the real first element is stored at 1 - who knows.

stefanB
A: 

It's all right to use constants to represent abstract values, but quite another to represent constructs in your own language.

const int FIRST_ROW = 0 doesn't make sense.

const int MINIMUM_WIDGET_COUNT = 0 makes more sense.

The presumption that you should follow a coding standard makes sense. (That is, coding standards are presumptively correct within an organization.) Slavishly following it when the presumption isn't met doesn't make sense.

So I agree with the earlier posters that some of the smelly constants probably resulted from following a coding standard ("no magic numbers") to the letter without exception. That's the problem here.

Inner Drive Technology