Opinion) Overuse of symbolic constants

S

Sandeep Sharma

Right from the time the first edition of K&R was released, the
advantages of using symbolic constants, as opposed to "magic numbers",
has been emphasized ---- and for good reason. I don't dispute that at
all. However, it gets on my nerves when people carry this practice
too far. Consider these examples (from the code written by a
distinguished colleague):

#define DASH '-'
#define SLASH '/'
#define SINGLE_BYTE 1

It is one thing to use symbolic constants with meaningful (and in some
cases, abstract) names, but methinks that use of symbolic constants in
this way is a complete waste. Let us take the first example. Either
the definition of DASH will never change (in which case it's usage is
superfluous) or the definition of DASH will change in the future (in
which case it will be completely misleading).


Any opinions?

--SS
 
N

Niels Dybdahl

Right from the time the first edition of K&R was released, the
advantages of using symbolic constants, as opposed to "magic numbers",
has been emphasized ---- and for good reason. I don't dispute that at
all. However, it gets on my nerves when people carry this practice
too far. Consider these examples (from the code written by a
distinguished colleague):

#define DASH '-'
#define SLASH '/'
#define SINGLE_BYTE 1

It is one thing to use symbolic constants with meaningful (and in some
cases, abstract) names, but methinks that use of symbolic constants in
this way is a complete waste. Let us take the first example. Either
the definition of DASH will never change (in which case it's usage is
superfluous) or the definition of DASH will change in the future (in
which case it will be completely misleading).

I consider three important uses for defines or constants:

1. For values that are subject to change.
2. To distinguish a certain usage of a value from other usages, so that
searches are more efficient.
3. More meaningfull names (e.g. PATH_NOT_FOUND instead of a value).

I do not think that the examples shown above fits into any of these usages.

Niels Dybdahl
 
C

Christopher Benson-Manica

(comp.lang.c only, I don't see clc++ caring much about this)
#define DASH '-'
#define SLASH '/'
#define SINGLE_BYTE 1

I'm dealing with similar code, except that ours look like

#define Splat '*'
#define Andpersand '&'
#define Asterik '*'

Those are verbatim - yes, ampersand and asterisk are misspelled, and
the constants aren't capitalized. I make a point of not using these
at any time in the code that *I* write. And the author is my boss, so
I guess he's "distinguished" too :)
 
J

Joona I Palaste

Christopher Benson-Manica said:
In comp.lang.c Sandeep Sharma <[email protected]> wrote:
(comp.lang.c only, I don't see clc++ caring much about this)
I'm dealing with similar code, except that ours look like
#define Splat '*'
#define Andpersand '&'
#define Asterik '*'
Those are verbatim - yes, ampersand and asterisk are misspelled, and
the constants aren't capitalized. I make a point of not using these
at any time in the code that *I* write. And the author is my boss, so
I guess he's "distinguished" too :)

Your boss obviously hasn't read enough European comics. =)

--
/-- Joona Palaste ([email protected]) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"'So called' means: 'There is a long explanation for this, but I have no
time to explain it here.'"
- JIPsoft
 
K

- Kees van der Bent -

Christopher said:
I'm dealing with similar code, except that ours look like

#define Splat '*'
#define Andpersand '&'
#define Asterik '*'

So why don't you:

#define SPLAT Splat
#define AMPERSAND Andpersand
#define ASTERISK Asterik

Cheers,

Kees

:)
 
D

Darrell Grainger

Right from the time the first edition of K&R was released, the
advantages of using symbolic constants, as opposed to "magic numbers",
has been emphasized ---- and for good reason. I don't dispute that at
all. However, it gets on my nerves when people carry this practice
too far. Consider these examples (from the code written by a
distinguished colleague):

#define DASH '-'
#define SLASH '/'
#define SINGLE_BYTE 1

It is one thing to use symbolic constants with meaningful (and in some
cases, abstract) names, but methinks that use of symbolic constants in
this way is a complete waste. Let us take the first example. Either
the definition of DASH will never change (in which case it's usage is
superfluous) or the definition of DASH will change in the future (in
which case it will be completely misleading).

Any opinions?

I use macros for data that is subject to change or to make the code more
readable. Symbols are just as readable as words so I see no point in two
of the three examples.

However, the SLASH might have a place. I have seen code like:

#ifdef WINDOWS
#define SEPERATOR '\\'
#else
#define SEPERATOR '/'
#endif

Have you asked the distinguished collegue why the need for the macros? If
they have a good reason maybe a comment in the source code would be
helpful.

I'm guessing they are just blindly following something they were taught
without understanding why.
 
F

Fred L. Kleinschmidt

Sandeep said:
Right from the time the first edition of K?R was released, the
advantages of using symbolic constants, as opposed to "magic numbers",
has been emphasized ---- and for good reason. I don't dispute that at
all. However, it gets on my nerves when people carry this practice
too far. Consider these examples (from the code written by a
distinguished colleague):

#define DASH '-'
#define SLASH '/'
#define SINGLE_BYTE 1

It is one thing to use symbolic constants with meaningful (and in some
cases, abstract) names, but methinks that use of symbolic constants in
this way is a complete waste. Let us take the first example. Either
the definition of DASH will never change (in which case it's usage is
superfluous) or the definition of DASH will change in the future (in
which case it will be completely misleading).

Any opinions?

--SS

I use the SLASH definition to distinguish the directory name separator
for Unix vs. Windows:

#ifdef WIN32
#define SLASH '\\'
#else
#define SLASH '/'
#endif
 
D

Dan Pop

In said:
However, the SLASH might have a place. I have seen code like:

#ifdef WINDOWS
#define SEPERATOR '\\'
#else
#define SEPERATOR '/'
#endif

It was probably written by someone ignoring both English and Windows.

In most contexts, Windows accepts the forward slash as path separator.
The only exception coming to mind is COMMAND.COM (newer command
interpreters are perfectly happy with Unix-style path specifications).

So, in a C context, it's only strings prepared to be passed to system()
that need the distinction. But such strings are typically affected by
much more important portability issues...

Dan
 
M

Martin Dickopp

Fred L. Kleinschmidt said:
I use the SLASH definition to distinguish the directory name separator
for Unix vs. Windows:

#ifdef WIN32
#define SLASH '\\'
#else
#define SLASH '/'
#endif

I find this misleading. I'd prefer

#ifdef WIN32
#define DIR_SEP '\\'
#else
#define DIR_SEP '/'
#endif

Martin
 
J

Jerry Coffin

Right from the time the first edition of K&R was released, the
advantages of using symbolic constants, as opposed to "magic numbers",
has been emphasized ---- and for good reason. I don't dispute that at
all. However, it gets on my nerves when people carry this practice
too far. Consider these examples (from the code written by a
distinguished colleague):

#define DASH '-'
#define SLASH '/'
#define SINGLE_BYTE 1

It is one thing to use symbolic constants with meaningful (and in some
cases, abstract) names, but methinks that use of symbolic constants in
this way is a complete waste. Let us take the first example. Either
the definition of DASH will never change (in which case it's usage is
superfluous) or the definition of DASH will change in the future (in
which case it will be completely misleading).

I agree. To be useful, a symbolic name needs to be symbolic -- it
needs to symbolize something. These are roughly equivalent to
comments like:

a=b; /* assign b to a */

that only repeat what's already obvious. To be useful, the symbol
needs to add meaning that isn't obvious without it. A constrast would
be names like the following:

#define switch_char '-'
#define path_sep '/'

which really add meaning, as well as the flexibility of (for example)
allowing a path separator to be changed from '/' to '\\' to ':' as
appropriate.
Later,
Jerry.
 
A

Arthur J. O'Dwyer

Right from the time the first edition of K&R was released, the
advantages of using symbolic constants, as opposed to "magic numbers",
has been emphasized ---- and for good reason. I don't dispute that at
all. However, it gets on my nerves when people carry this practice
too far. Consider these examples (from the code written by a
distinguished colleague):

#define DASH '-'
#define SLASH '/'
#define SINGLE_BYTE 1

One possibility I haven't seen anyone mention yet is that while the
abstract *value* of "DASH" will never change, the *type* of "DASH"
may well change: for example, when updating this code to deal with
wide character I/O we write

#define DASH L'-'
#define SLASH L'/'
#define SINGLE_BYTE (sizeof (wchar_t))

(Here SINGLE_BYTE is a misnomer; better to name it SINGLE_CHAR or
something similar.)

A second possibility is that the first couple entries were taken
out of context from a hand-written lexer or parser:

#define DASH '-'
#define SLASH '/'
#define ASSGNOP 1000
#define STAR_ASSGNOP 1001
#define DASH_ASSGNOP 1002
#define PLUSPLUS 1003
[...]

Here we are simplifying the lexer code by making the "dash" token
equal in value to the system's '-' character, and similarly for all
other one-character tokens: multi-character tokens get their own
numerical "token" values, out of the ASCII range.
(This example code is obviously not quite portable; it's implicitly
assuming that '-' and 1000 are distinct values, which is guaranteed
by ASCII but not by Standard C.)

The already-mentioned "platform-independent directory separator"
idea is a common one, too, but I don't see how it explains the presence
of DASH along with SLASH.

HTH,
-Arthur
 
O

Old Wolf

Niels Dybdahl said:
I consider three important uses for defines or constants:

1. For values that are subject to change.
2. To distinguish a certain usage of a value from other usages, so that
searches are more efficient.
3. More meaningfull names (e.g. PATH_NOT_FOUND instead of a value).

I do not think that the examples shown above fits into any of these usages.

From a C99 implementation near you:

#define and &&
#define and_eq &=
#define bitand &
#define bitor |
#define compl ~
#define not !
#define not_eq !=
#define or ||
#define or_eq |=
#define xor ^
#define xor_eq ^=

This is interesting because a co-developer of mine has a standard include
file (predating C99 by a long way) which has:

#define AND &&
#define OR ||
#define NOT !

So I guess there is a fourth category, which the OP's definitions might
fall into: improving readability.
 
C

CBFalconer

Old said:
.... snip ...

From a C99 implementation near you:

#define and &&
#define and_eq &=
#define bitand &
#define bitor |
#define compl ~
#define not !
#define not_eq !=
#define or ||
#define or_eq |=
#define xor ^
#define xor_eq ^=

This has been in C90 since about 1995. #include <iso646.h>
 
D

Dan Pop

In said:
This has been in C90 since about 1995. #include <iso646.h>

More correctly, this has been in C94 since about 1995. I don't know
if C94 implementations were popular enough to be worth messing with
<iso646.h> if you cared about portable programming.

Dan
 
K

Kenneth Brody

:
[...]
I use the SLASH definition to distinguish the directory name separator
for Unix vs. Windows:

#ifdef WIN32
#define SLASH '\\'
#else
#define SLASH '/'
#endif

Why bother? Unless you are building a filename to pass to system(),
and that specific command doesn't like '/', the above is superfluous.
(That, and misleading by using the name SLASH rather than something
like PATH_SET.)

All versions of MS-Windows, and all versions of MS-DOS back to 2.0
when they first allowed subdirectories can use the following:

FILE *f = fopen("/foo/bar/foobar.txt","r");

And even system() works if you're not exectuting a brain-dead command.
For example:

system("vi /foo/bar/foobar.txt");

It's amazing how many code samples I see that have code to build path
names differently under DOS/Windows, when these are used strictly for
internal purposes and not for system commands. And it's amazing how
many people are shocked when asked "since when?" and I tell them
"since always".
 
J

Jakob Bieling

Old Wolf said:
usages.

From a C99 implementation near you:

#define and &&
#define and_eq &=
#define bitand &
#define bitor |
#define compl ~
#define not !
#define not_eq !=
#define or ||
#define or_eq |=
#define xor ^
#define xor_eq ^=

This is interesting because a co-developer of mine has a standard include
file (predating C99 by a long way) which has:

#define AND &&
#define OR ||
#define NOT !

So I guess there is a fourth category, which the OP's definitions might
fall into: improving readability.

The point was not primarily readabilty, but rather to enable people to
use those operators if their keyboard either did not support some/all of
those characters, or if it was unconviniently difficult to type them.

regards
 
M

Michael Wojcik

It was probably written by someone ignoring both English and Windows.

In most contexts, Windows accepts the forward slash as path separator.

Which means that in Windows, you can generally use the forward slash
when generating paths, so there's no need for the macro; and when
parsing paths, you need to handle both slash and backslash, so the
macro won't help. It's doubly wrong.

As is often the case, attempting to hide platform-dependent code here
just produces a solution that's less obviously broken.

--
Michael Wojcik (e-mail address removed)

Therefore, it is possible to enjoy further by using under the
Netscape 2.0. However, Netscape will hangup at sometimes. You
should give it up. -- roro
 
K

Keith Thompson

Kenneth Brody said:
:
[...]
I use the SLASH definition to distinguish the directory name separator
for Unix vs. Windows:

#ifdef WIN32
#define SLASH '\\'
#else
#define SLASH '/'
#endif

Why bother? Unless you are building a filename to pass to system(),
and that specific command doesn't like '/', the above is superfluous.
(That, and misleading by using the name SLASH rather than something
like PATH_SET.)

All versions of MS-Windows, and all versions of MS-DOS back to 2.0
when they first allowed subdirectories can use the following:

FILE *f = fopen("/foo/bar/foobar.txt","r");

And even system() works if you're not exectuting a brain-dead command.
For example:

system("vi /foo/bar/foobar.txt");

Disclaimer: I don't write programs for Windows (except under Cygwin,
but that doesn't count in this context.)

If a file name is going to be displayed to a Windows end user, the
user is likely to be confused if the path name contains '/' characters
rather than '\' characters. Confusing users is seldom a good idea.
 
J

Joe Wright

Jakob said:
The point was not primarily readabilty, but rather to enable people to
use those operators if their keyboard either did not support some/all of
those characters, or if it was unconviniently difficult to type them.
I suppose not. This business of abusing the preprocessor is
typically done by newbies at play. Have you ever seen any code by a
professional programmer (someone who gets paid for it) using this
kind of stuff? I have not.
 
N

Nick Landsberg

Joe said:
[SNIP]
[SNIP]
The point was not primarily readabilty, but rather to enable
people to
use those operators if their keyboard either did not support some/all of
those characters, or if it was unconviniently difficult to type them.
I suppose not. This business of abusing the preprocessor is typically
done by newbies at play. Have you ever seen any code by a professional
programmer (someone who gets paid for it) using this kind of stuff? I
have not.

As a matter of fact, the first time I saw code for what was
to become the Bourne Shell (circa 1982), it was written exactly like
that except all the #defines were in CAPS.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top