When are numbers NOT Magic? Example

A risky and lengthy post, I’m hoping you’ll indulge me on. Stack
Overflow doesn’t like opinion questions, and I wasn’t sure where else to
go to get the opinions of a well-informed group of folks. I figure the
Ruby community is about as uniformly a good-practices OCD bunch as any.
If you have a suggestion for a better place to have this discussion,
please do let me know.

Magic Numbers. Virtually every example of one is obvious. I have a case
I think is NOT a magic number, and neither readability nor
maintainability are improved by using a constant label.

The definitions of a magic number that I like are:

“Unique values with unexplained meaning or multiple occurrences which
could (preferably) be replaced with named constants.”
Magic number (programming) - Wikipedia (3rd bullet)

“The term magic number is also used in programming to refer to a
constant that is employed for some specific purpose but whose presence
or value is inexplicable without additional information.”
Magic number definition by The Linux Information Project (LINFO) (last line)

There’s some critical details there which open the door for cases where
literal numerals are not magic numbers. I for one do not subscribe to
open-ended -1, 0, 1, 2 are not magic numbers just because. IMO, context
is everything. I do not like literal 1 being used to compensate for 0/1
based offsets. I prefer to see new_variable = variable + ZERO_OFFSET
because I still want to know WHY that 1 is there. I don’t want to have
to asssume it is because of zero offset. So, that should tell you I’m in
favor of being cautious with magic numbers.

OK, so here’s my case…

Setup: a bunch of floating point values displayed on a web page.
Essentially a dashboard of a bunch of measured things. Each number has a
distinct engineering-based relevance to the precision which is
displayed. In other words, it’s not a repetition of money values where
of course you would create a MONEY_DISPLAY_PRECISION constant for 2
decimal places to centralize that definition.

Each value has unique units.

Each value’s precision is uniquely meaningful based on real-world
measurement technology and accuracy. Changing one value’s precision
doesn’t mean you’d want to change any of the others.

Each value is displayed in only one place in the application. So there’s
no incentive to create a constant to prevent redundant literals.

The precision is not something the user can choose. The application must
hard code the displayed values, because the precision is meaningful. So
there’s no incentive to have a variable.

The software has a generic method to render a floating point number as a
string with thousands separators and with a specified precision.

SomeClass#float_as_thousands_with_precision(value, precision)

Which would get used something like:

<%= float_as_thousands_with_precision(volts, 1) -%>


<%= float_as_thousands_with_precision(amps, 2) -%>


<%= float_as_thousands_with_precision(watts, 2) -%>

I contend, those are NOT magic numbers.

Using the above definitions (and others I found like them), such numbers
do not need constants because:
– each number is a single instance (no redundancy)
– each number is independent from the other (no shared cause & effect
on precision)
– each number’s purpose is very clear from from both the function name
and argument name (no need to clarify purpose)

I know somone out there will say, “well, why not make a constant for
them? What does it hurt?”

I say, why do it? It’s more code to maintain with no benefit. If people
can justify not making constants for clearly varying purposes of using 1
in code just because it’s a 1, then I contend this is even a more
justifiable case to not bother with a constant.

OK, that’s my exhaustive argument.

What say ye? Do these require constants? Are they magic numbers?

On 19/04/12 17:30, Greg W. wrote:

Setup: a bunch of floating point values displayed on a web page.
Essentially a dashboard of a bunch of measured things. Each number has a
distinct engineering-based relevance to the precision which is
displayed.

What say ye? Do these require constants? Are they magic numbers?

Hard to know without knowing what the software does, but …

If the software has hardware attached that could potentially have a
higher or lower precision in terms of the specific metric it/ they
measure(s), you have a place to configure it outside of the code based
on the attached hardware. This makes the software more flexible; for
users as well as developers. Also, seeing it named in the code makes it
clear which constant will affect which display.

Perhaps that is irrelevant. Hard to say =]

Sam

Greg W. писал 19.04.2012 09:30:

there’s no incentive to have a variable.

numbers
them? What does it hurt?"
What say ye? Do these require constants? Are they magic numbers?
I would just put a comment at the top of the file explaining the nature
of
these numbers. It’s enough. Constants for magic numbers are essentially
inline comments which also add another layer of error proofing.

On Thu, Apr 19, 2012 at 7:30 AM, Greg W. [email protected]
wrote:

measurement technology and accuracy. Changing one value’s precision
string with thousands separators and with a specified precision.

<%= float_as_thousands_with_precision(watts, 2) -%>

I contend, those are NOT magic numbers.

Certainly not.

Using the above definitions (and others I found like them), such numbers
do not need constants because:
– each number is a single instance (no redundancy)
– each number is independent from the other (no shared cause & effect
on precision)
– each number’s purpose is very clear from from both the function name
and argument name (no need to clarify purpose)

But a constant’s name goes a long way in documenting the meaning.

I know somone out there will say, “well, why not make a constant for
them? What does it hurt?”

I say, why do it? It’s more code to maintain with no benefit.

Oh, you do get benefits:

  • documentation
  • error checking (using a wrong value will show)

They are not magic numbers, by no means. Do they require constants?
It may turn out there are better solutions around. For example:

MeasurementValue = Struct.new :val, :precision do
def to_s
float_as_thousands_with_precision(val, precision)
end
end

The place in code which creates the value is certainly the one which
knows what type the data really is. By bundling information at that
place it cannot get lost. But now we have bundled display semantics
with a data type. It’s probably better to separate things.

MeasurementValue = Struct.new :val, :kind

FORMATS = {
:velocity => “%4.2f”,
:speed => “%10.1f”,
}

def FORMATS.show(mv)
sprintf self[mv.kind], mv.val
end

<%= FORMATS.show(volts) -%>

Kind regards

robert

Robert K. wrote in post #1057330:

On Thu, Apr 19, 2012 at 7:30 AM, Greg W. [email protected]
wrote:

measurement technology and accuracy. Changing one value’s precision
string with thousands separators and with a specified precision.

<%= float_as_thousands_with_precision(watts, 2) -%>

I contend, those are NOT magic numbers.

Certainly not.

Using the above definitions (and others I found like them), such numbers
do not need constants because:
– each number is a single instance (no redundancy)
– each number is independent from the other (no shared cause & effect
on precision)
– each number’s purpose is very clear from from both the function name
and argument name (no need to clarify purpose)

But a constant’s name goes a long way in documenting the meaning.

Generically, I agree that’s a good purpose for a constant, but in this
case, it seems to me that

<%= float_as_thousands_with_precision(watts, PRECISION_OF_WATTS) -%>
isn’t any clearer or better documented than
<%= float_as_thousands_with_precision(watts, 2) -%>

I think that’s the crux of what I see. To me, the latter can’t really be
improved upon. It can be different, but is the extra code really adding
value? Your FORMATS idea is interesting (and useful for a repeatedly
used value), but in the end isn’t it a variation on a list of constants?

Anyway, thanks for your comments. I appreciate your taking the time to
noodle on my epistle.

– gw

On Fri, Apr 20, 2012 at 6:39 PM, Greg W. [email protected]
wrote:

Robert K. wrote in post #1057330:

But a constant’s name goes a long way in documenting the meaning.

Generically, I agree that’s a good purpose for a constant, but in this
case, it seems to me that

<%= float_as_thousands_with_precision(watts, PRECISION_OF_WATTS) -%>
isn’t any clearer or better documented than
<%= float_as_thousands_with_precision(watts, 2) -%>

Probably, yes. :slight_smile:

I think that’s the crux of what I see. To me, the latter can’t really be
improved upon. It can be different, but is the extra code really adding
value? Your FORMATS idea is interesting (and useful for a repeatedly
used value), but in the end isn’t it a variation on a list of constants?

I prefer to look at it differently: I have introduced typed values.
That extra information about the data can be used elsewhere to
properly present a datum. It can also be used for other things, e.g.
flagging errors if someone tries to compare apples and oranges, or do
argument checks in methods that are designed for a particular type of
data only etc. That separates type logic from presentation logic
while improving type safety by attaching the type info at the location
which creates the data. If your data would consist of two values
(e.g. a coordinate) it would be much more obvious to create a specific
class for it but you can do so for single values also. Another
approach would be to create several classes and use different logic
for the calculation of the precision (i.e. look up via obj.class).

Anyway, thanks for your comments. I appreciate your taking the time to
noodle on my epistle.

Don’t call me “Noodles” - that name is taken already. :slight_smile:
http://akas.imdb.com/title/tt0087843/combined

Kind regards

robert