1

I know that -1, 0, 1, and 2 are exceptions to the magic number rule. However I was wondering if the same is true for when they are floats. Do I have to initialize a final variable for them or can I just use them directly in my program.

I am using it as a percentage in a class. If the input is less than 0.0 or greater than 1.0 then I want it set the percentage automatically to zero. So if (0.0 <= input && input <= 1.0).

Thank you

user2426500
  • 29
  • 2
  • 6
  • 1
    You don't "have" to. It's a style thing. – Oliver Charlesworth Oct 22 '13 at 15:05
  • The future maintainers of your code, however, will thank you for putting your magic numbers in a constant so they don't have to guess what they mean. – DVG Oct 22 '13 at 15:09
  • If a constant will only be used once *with a particular meaning* and will have no meaning outside the context where it's used, it's often better to have a comment there than define a name. If the same numeric value is used multiple times but with *different* meanings, using the same name for multiple meanings is worse than using raw numeric constants. – supercat Oct 23 '13 at 18:13

4 Answers4

2

It really depends on the context. The whole point of avoiding magic numbers is to maintain the readability of your code. Use your best judgement, or provide us with some context so that we may use ours.

Magic numbers are [u]nique values with unexplained meaning or multiple occurrences which could (preferably) be replaced with named constants.

http://en.wikipedia.org/wiki/Magic_number_(programming)

Edit: When to document code with variables names vs. when to just use a number is a hotly debated topic. My opinion is that of the author of the Wiki article linked above: if the meaning is not immediately obvious and it occurs multiple times in your code, use a named constant. If it only occurs once, just comment the code.

If you are interested in other people's (strongly biased) opinions, read What is self-documenting code and can it replace well documented code?

Community
  • 1
  • 1
Dan Bechard
  • 5,104
  • 3
  • 34
  • 51
  • 1
    I am using it as a percentage in a class. If the input is less than 0.0 or greater than 1.0 then I want it set the percentage automatically to zero. So if (0.0 <= input && input <= 1.0). – user2426500 Oct 22 '13 at 15:16
  • If this bounding is somewhere obvious (e.g. a function called `EnforceBounds()`, a `{ set; }` accessor, etc.) then I would just comment _why_ you are bounding to those numbers rather than using a variable name to document your code. – Dan Bechard Oct 22 '13 at 15:19
2

Those numbers aren't really exceptions to the magic number rule. The common sense rule (as far as there is "one" rule), when it isn't simplified to the level of dogma, is basically, "Don't use numbers in a context that doesn't make their meaning obvious." It just so happens that these four numbers are very commonly used in obvious contexts. That doesn't mean they're the only numbers where this applies, e.g. if I have:

long kilometersToMeters(int km) { return km * 1000L; }

there is really no point in naming the number: it's obvious from the tiny context that it's a conversion factor. On the other hand, if I do this in some low-level code:

sendCommandToDevice(1);

it's still wrong, because that should be a constant kResetCommand = 1 or something like it.

So whether 0.0 and 1.0 should be replaced by a constant completely depends on the context.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
0

Usually, every rule has exceptions (and this one too). It is a matter of style to use some mnemonic names for these constants.

For example:

int Rows = 2;
int Cols = 2;

Is a pretty valid example where usage of raw values will be misleading.

The meaning of the magic number should be obvious from the context. If it is not - give the thing a name.

Sergey K.
  • 24,894
  • 13
  • 106
  • 174
0

Attaching a name for something creates an identity. Given the definitions

const double Moe = 2.0;
const double Joe = 2.0;
...
double Larry = Moe;
double Harry = Moe;
double Garry = Joe;

the use of symbols for Moe and Joe suggests that the default value of Larry and Harry are related to each other in a way that the default value of Garry is not. The decision of whether or not to define a name for a particular constant shouldn't depend upon the value of that constant, but rather whether it will non-coincidentally appear multiple places in the code. If one is communicating with a remote device which requires that a particular byte value be sent to it to trigger a reset, I would consider:

void ResetDevice()
{
  // The 0xF9 command is described in the REMOTE_RESET section of the
  // Frobnitz 9000 manual
  transmitByte(0xF9);
}
... elsewhere
myDevice.ResetDevice();
...
otherDevice.ResetDevice();

to be in many cases superior to

// The 0xF9 command is described in the REMOTE_RESET section of the
// Frobnitz 9000 manual
const int FrobnitzResetCode = 0xF9;
... elsewhere
myDevice.transmitByte(FrobnitzResetCode );
...
otherDevice.transmitByte(FrobnitzResetCode );

The value 0xF9 has no real meaning outside the context of resetting the Frobnitz 9000 device. Unless there is some reason why outside code should prefer to send the necessary value itself rather than calling a ResetDevice method, the constant should have no value to any code outside the method. While one could perhaps use

void ResetDevice()
{
  // The 0xF9 command is described in the REMOTE_RESET section of the
  // Frobnitz 9000 manual
  int FrobnitzResetCode = 0xF9;
  transmitByte(FrobnitzResetCode);
}

there's really not much point to defining a name for something which is in such a narrow context.

The only thing "special" about values like 0 and 1 is that used significantly more often than other constants like e.g. 23 in cases where they have no domain-specific identity outside the context where they are used. If one is using a function which requires that the first parameter indicates the number of additional parameters (somewhat common in C) it's better to say:

output_multiple_strings(4, "Bob", Joe, Larry, "Fred"); // There are 4 arguments
...
output_multiple_strings(4, "George", Fred, "James", Lucy);  // There are 4 arguments

than #define NUMBER_OF_STRINGS 4 // There are 4 arguments

output_multiple_strings(NUMBER_OF_STRINGS, "Bob", Joe, Larry, "Fred");
...
output_multiple_strings(NUMBER_OF_STRINGS, "George", Fred, "James", Lucy);

The latter statement implies a stronger connection between the value passed to the first method and the value passed to the second, than exists between the value passed to the first method and anything else in that method call. Among other things, if one of the calls needs to be changed to pass 5 arguments, it would be unclear in the second code sample what should be changed to allow that. By contrast, in the former sample, the constant "4" should be changed to "5".

supercat
  • 77,689
  • 9
  • 166
  • 211