Question

I have a function like this:

float_as_thousands_str_with_precision(value, precision)

If I use it like this:

float_as_thousands_str_with_precision(volts, 1)
float_as_thousands_str_with_precision(amps, 2)
float_as_thousands_str_with_precision(watts, 2)

Are those 1/2s magic numbers?

Était-ce utile?

La solution

Yes, they are magic numbers. It's obvious that the numbers 1 and 2 specify precision in the code sample but not why. Why do you need amps and watts to be more precise than volts at that point?

Also, avoiding magic numbers allows you to centralize code changes rather than having to scour the code when for the literal number 2 when your precision needs to change.

I would propose something like:

HIGH_PRECISION = 3;
MED_PRECISION = 2;
LOW_PRECISION = 1;

And your client code would look like:

float_as_thousands_str_with_precision(volts, LOW_PRECISION )
float_as_thousands_str_with_precision(amps, MED_PRECISION )
float_as_thousands_str_with_precision(watts, MED_PRECISION )

Then, if in the future you do something like this:

HIGH_PRECISION = 6;
MED_PRECISION = 4;
LOW_PRECISION = 2;

All you do is change the constants...

But to try and answer the question in the OP title:

IMO the only numbers that can truly be used and not be considered "magic" are -1, 0 and 1 when used in iteration, testing lengths and sizes and many mathematical operations. Some examples where using constants would actually obfuscate code:

for (int i=0; i<someCollection.Length; i++) {...}

if (someCollection.Length == 0) {...}

if (someCollection.Length < 1) {...}

int MyRidiculousSignReversalFunction(int i) {return i * -1;}

Those are all pretty obvious examples. E.g. start and the first element and increment by one, testing to see whether a collection is empty and sign reversal... ridiculous but works as an example. Now replace all of the -1, 0 and 1 values with 2:

for (int i=2; i<50; i+=2) {...}

if (someCollection.Length == 2) {...}

if (someCollection.Length < 2) {...}

int MyRidiculousDoublinglFunction(int i) {return i * 2;}

Now you have start asking yourself: Why am I starting iteration on the 3rd element and checking every other? And what's so special about the number 50? What's so special about a collection with two elements? the doubler example actually makes sense here but you can see that the non -1, 0, 1 values of 2 and 50 immediately become magic because there's obviously something special in what they're doing and we have no idea why.

Autres conseils

No, they aren't.

A magic number in that context would be a number that has an unexplained meaning. In your case, it specifies the precision, which clearly visible.

A magic number would be something like:

int calculateFoo(int input)
{
  return 0x3557 * input;
}

You should be aware that the phrase "magic number" has multiple meanings. In this case, it specifies a number in source code, that is unexplainable by the surroundings. There are other cases where the phrase is used, for example in a file header, identifying it as a file of a certain type.

A literal numeral IS NOT a magic number when:

  • it is used one time, in one place, with very clear purpose based on its context
  • it is used with such common frequency and within such a limited context as to be widely accepted as not magic (e.g. the +1 or -1 in loops that people so frequently accept as being not magic).
  • some people accept the +1 of a zero offset as not magic. I do not. When I see variable + 1 I still want to know why, and ZERO_OFFSET cannot be mistaken.

As for the example scenario of:

float_as_thousands_str_with_precision(volts, 1)

And the proposed

float_as_thousands_str_with_precision(volts, HIGH_PRECISION)

The 1 is magic if that function for volts with 1 is going to be used repeatedly for the same purpose. Then sure, it's "magic" but not because the meaning is unclear, but because you simply have multiple occurences.

Paul's answer focused on the "unexplained meaning" part thinking HIGH_PRECISION = 3 explained the purpose. IMO, HIGH_PRECISION offers no more explanation or value than something like PRECISION_THREE or THREE or 3. Of course 3 is higher than 1, but it still doesn't explain WHY higher precision was needed, or why there's a difference in precision. The numerals offer every bit as much intent and clarity as the proposed labels.

Why is there a need for varying precision in the first place? As an engineering guy, I can assume there's three possible reasons: (a) a true engineering justification that the measurement itself is only valid to X precision, so therefore the display shoulld reflect that, or (b) there's only enough display space for X precision, or (c) the viewer won't care about anything higher that X precision even if its available.

Those are complex reasons difficult to capture in a constant label, and are probbaly better served by a comment (to explain why something is beng done).

IF the use of those functions were in one place, and one place only, I would not consider the numerals magic. The intent is clear.

For reference:

A literal numeral IS magic when

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top