Is there a class name macro?

J

James Kanze

James Kanze wrote:

[...]
Another advantage of using a macro is that I can (and do)
conditionally compile it, so that I can completely remove the
Trace code (although I can also control it programmatically).
Conditional compilation should also be used sparingly, and
this is the only place I use it in what has now become a
substantial sized project.

I've provided for this possibility many times as well. I've
never had to use it, but often, it's a necessary argument to
sell tracing.
Another place I use macros is to replace curly brackets. Eg
// Global include
#define THEN {
#define ELSEIF }else if
#define ELSE }else{
#define ENDIF }
// -----------------
Then I can write
if (condition)
THEN
// Do something
ELSE
// Do something else
ENDIF
This may be controversial,

It's not controversial; it's proven bad practice. You've just
made your code unreadable by any other C++ programmer, and by
any other tool which doesn't to a full parse (syntax
highlighting and indenting by the editor, for example).

C++ has a defined syntax. I don't always like it either, but
that's the way it is. You can't really create a new language
with macros, and you don't really want to, since no one else
(and no tool) knows that language. For better or for worse, you
have to live with C++ as it is.

(Also, if you were doing it, the #defines would be:

#define IF if (
#define THEN ) {
#define ELSE } else {
#define ELSIF } else if (
#define END }

..)
but I think it makes code clearer. My code automatically
documents where the various parts of the if statement are,
rather than leaving the reader to count brackets and look at
indentation.

How is counting the brackets and looking at the indentation any
better than counting the THEN/ELSE and looking at the
indentation. My editor does the indentation automatically (as
do most, I think), which ensures that it is correct, and it's
doubtlessly the easiest thing to follow. (And of course, I
don't nest overly deep, so there's not that much to follow
anyway.)
 
J

James Kanze

@my.homepage> wrote:

[...]
It depends a lot on who your customers are. Where I am right
now, they are fairly close, and I can make demands. I make a
point of only giving them releases which can be traced back to
one version of the source code, and they know (or can find
out) which release they are using. Come to think of it, it's
printed first in the log file.
In that scenario, file and line is enough.

If you're managing your sources correctly, that should be
enough. In practice, it depends on the organization, and more
than once, even knowing the version of the executable, I've had
difficulty determining which version of a specific source it
contained. In such cases, adding the version only adds a few
characters to the line header (which already contains the
filename, line number and a timestamp), and seems worth it. In
better run organizations, it's probably not worth the bother.
 
C

Chris Gordon-Smith

James said:
James Kanze wrote:
[...]
Another advantage of using a macro is that I can (and do)
conditionally compile it, so that I can completely remove the
Trace code (although I can also control it programmatically).
Conditional compilation should also be used sparingly, and
this is the only place I use it in what has now become a
substantial sized project.

I've provided for this possibility many times as well. I've
never had to use it, but often, it's a necessary argument to
sell tracing.
Another place I use macros is to replace curly brackets. Eg
// Global include
#define THEN {
#define ELSEIF }else if
#define ELSE }else{
#define ENDIF }
// -----------------
Then I can write
if (condition)
THEN
// Do something
ELSE
// Do something else
ENDIF
This may be controversial,

It's not controversial; it's proven bad practice. You've just
made your code unreadable by any other C++ programmer, and by
any other tool which doesn't to a full parse (syntax
highlighting and indenting by the editor, for example).
I think the main issue when picking up someone else's code is understanding
the overall application design, how it works, and all the other application
specific aspects. Finding your way around unfamiliar (but intuitive) syntax
is a small step compared to this.

Syntax highlighting works with my editor.
C++ has a defined syntax. I don't always like it either, but
that's the way it is. You can't really create a new language
with macros, and you don't really want to, since no one else
(and no tool) knows that language. For better or for worse, you
have to live with C++ as it is.
I haven't created a new language, but I have varied the syntax slightly. It
is working fine for me, and I don't have to live with the curly brackets
that annoy me. I do realise however that the approach I like may annoy
other people.
(Also, if you were doing it, the #defines would be:

#define IF if (
#define THEN ) {
#define ELSE } else {
#define ELSIF } else if (
#define END }

.)

The seem to be different ways of doing it. I don't have a #define for "if"
(that does seem to be unnecessary), and I have separate #defines for END
and ENDIF. That way I can distinguish between the end of an "if" statement
and the end of a "for" loop (for which I use END).
How is counting the brackets and looking at the indentation any
better than counting the THEN/ELSE and looking at the
indentation.
There is less reliance on counting and checking indentation. Instead of
looking at a "}"curly bracket and wondering what kind of block it ends, I
see ENDIF and know immediately what it means.
My editor does the indentation automatically (as
do most, I think), which ensures that it is correct, and it's
doubtlessly the easiest thing to follow. (And of course, I
don't nest overly deep, so there's not that much to follow
anyway.)

I don't use automatic indentation. I tried it for a while with Emacs but
couldn't get it to indent the way I wanted.

Agree about the over-deep nesting.

Chris Gordon-Smith
www.simsoup.info
 
R

Richard Herring

Chris Gordon-Smith said:
[etc]
It's not controversial; it's proven bad practice. You've just
made your code unreadable by any other C++ programmer, and by
any other tool which doesn't to a full parse (syntax
highlighting and indenting by the editor, for example).
I think the main issue when picking up someone else's code is understanding
the overall application design, how it works, and all the other application
specific aspects. Finding your way around unfamiliar (but intuitive)

Intuitive? ...
syntax
is a small step compared to this.

Syntax highlighting works with my editor.

I haven't created a new language, but I have varied the syntax slightly. It
is working fine for me, and I don't have to live with the curly brackets
that annoy me. I do realise however that the approach I like may annoy
other people.
Meiosis.

The seem to be different ways of doing it.

.... which implies that it's not intuitive, as claimed above.
I don't have a #define for "if"
(that does seem to be unnecessary),

(and the other macros aren't?)

So you have a construct with a language keyword at the top and macros
elsewhere. Foolish consistency, at the very least, would dictate using
macros throughout if you must use then at all.
and I have separate #defines for END
and ENDIF. That way I can distinguish between the end of an "if" statement
and the end of a "for" loop (for which I use END).

(why not ENDFOR?)
But can someone else who picks up your code and doesn't notice that
there are two macros for } ?
There is less reliance on counting and checking indentation. Instead of
looking at a "}"curly bracket and wondering what kind of block it ends,

The usual solution to that is to write, mutatis mutandis, something like
} // end if (condition)
I
see ENDIF and know immediately what it means.

Unless you (or someone else) typed the wrong macro :-(
The compiler won't provide any helpful error messages if you do.
 
J

James Kanze

In message <[email protected]>, Chris Gordon-Smith
James Kanze wrote:
[etc]
(Also, if you were doing it, the #defines would be:
#define IF if (
#define THEN ) {
#define ELSE } else {
#define ELSIF } else if (
#define END }
.)
The seem to be different ways of doing it.
... which implies that it's not intuitive, as claimed above.
(and the other macros aren't?)
So you have a construct with a language keyword at the top and
macros elsewhere. Foolish consistency, at the very least,
would dictate using macros throughout if you must use then at
all.

Consistency would dictate that at the very least, if THEN and
ELSE are all caps, then IF should be as well. And probably all
of the other keywords, which means a few more macros.

IMHO, consistency would also dictate that if you aren't writing
C++, you conform to the use of some other language, which is why
my definitions of IF and THEN have the parentheses. Of course,
common sense would also dictate that if you want to write in
some other language, the obvious solution would be to use a
compiler for that language, and not to try to fool the C++
compiler (and your readers).
(why not ENDFOR?)

And ENDWHILE. And ENDFUNCTION, and ENDCLASS. Let's do this
right:).
But can someone else who picks up your code and doesn't notice
that there are two macros for } ?

And for {, I suppose. Otherwise:

for ( ... ) {
// ...
END
The usual solution to that is to write, mutatis mutandis,
something like
} // end if (condition)

The one point I'd disagree with. The usual solution is to
write:
}
, correctly indented, and if the { is so far away that it isn't
evident, then to break the function up into smaller, more
manageable chunks.
Unless you (or someone else) typed the wrong macro :-( The
compiler won't provide any helpful error messages if you do.

And of course, the casual reader won't know exactly what it
means.
 
R

Richard Herring

In message
In message <[email protected]>, Chris Gordon-Smith
James Kanze wrote:
On Sep 18, 10:13 pm, Chris Gordon-Smith <[email protected]>
wrote:
#define THEN {
[etc]
(Also, if you were doing it, the #defines would be:
#define IF if (
#define THEN ) {
#define ELSE } else {
#define ELSIF } else if (
#define END }
.)
The seem to be different ways of doing it.
... which implies that it's not intuitive, as claimed above.
(and the other macros aren't?)
So you have a construct with a language keyword at the top and
macros elsewhere. Foolish consistency, at the very least,
would dictate using macros throughout if you must use then at
all.

Consistency would dictate that at the very least, if THEN and
ELSE are all caps, then IF should be as well. And probably all
of the other keywords, which means a few more macros.

IMHO, consistency would also dictate that if you aren't writing
C++, you conform to the use of some other language, which is why
my definitions of IF and THEN have the parentheses. Of course,
common sense would also dictate that if you want to write in
some other language, the obvious solution would be to use a
compiler for that language, and not to try to fool the C++
compiler (and your readers).
(why not ENDFOR?)

And ENDWHILE. And ENDFUNCTION, and ENDCLASS. Let's do this
right:).
But can someone else who picks up your code and doesn't notice
that there are two macros for } ?

And for {, I suppose. Otherwise:

for ( ... ) {
// ...
END
The usual solution to that is to write, mutatis mutandis,
something like
} // end if (condition)

The one point I'd disagree with. The usual solution is to
write:
}
, correctly indented, and if the { is so far away that it isn't
evident, then to break the function up into smaller, more
manageable chunks.

I suspect I write more multidimensional numerical code than you do.
Sometimes the "most manageable chunk" is unavoidably several levels deep
in nested loops, and splitting it into separate functions would actually
obscure the structure of the algorithm.

Besides, in the OP's case:

;-/
 
H

Hendrik Schober

Richard said:
In message
[...]
The one point I'd disagree with. The usual solution is to
write:
}
, correctly indented, and if the { is so far away that it isn't
evident, then to break the function up into smaller, more
manageable chunks.

I suspect I write more multidimensional numerical code than you do.
Sometimes the "most manageable chunk" is unavoidably several levels deep
in nested loops, and splitting it into separate functions would actually
obscure the structure of the algorithm.

I have never seen an algorithm that wouldn't benefit from
giving parts of them names and calling it by those. Would
you care to give an example?

Schobi
 
C

Chris Gordon-Smith

Richard said:
In message
In message <[email protected]>, Chris Gordon-Smith
<[email protected]> writes
James Kanze wrote:
On Sep 18, 10:13 pm, Chris Gordon-Smith <[email protected]>
wrote:
#define THEN {
[etc]
(Also, if you were doing it, the #defines would be:
#define IF if (
#define THEN ) {
#define ELSE } else {
#define ELSIF } else if (
#define END }
.)

The seem to be different ways of doing it.
... which implies that it's not intuitive, as claimed above.
Its the syntax that is intuitive, not necessarily the macros used to enable
it.
I use the macros to make the code more readable to me. I find that
replacing "}" with "ENDIF" helps understanding. Replacing "if" with "IF"
would not help understanding. It would have the disadvantage of removing
syntax highlighting with no compensating advantage.
The code compiles, so strictly speakig I think it must be C++, albeit with
somewhat unusual usage.
I think they would very soon work it out.
Where possible, I prefer to write code that documents itself rather than
write a comment.
I suspect I write more multidimensional numerical code than you do.
Sometimes the "most manageable chunk" is unavoidably several levels deep
in nested loops, and splitting it into separate functions would actually
obscure the structure of the algorithm.

Besides, in the OP's case:


;-/
I'll make a couple of other points on this overall discussion.

1) Personal Project Taste

This is an approach I have chosen to adopt for a particular project. It is
used consistently throughout the project.

I see it as a matter of personal taste, not as an issue of fundamental
importance that anyone should take an entrenched position over.

This is in contrast with principles such as good use of modularisation,
information hiding, minimising dependencies, appropriate use of inheritance
and polymorphism. These are issues that "really matter", and over which it
is worth arguing to get the approach right.

I am reminded of the item "Don't Sweat The Small Stuff" in Sutter and
Alexandrescu's C++ Coding Standards.

2) Tolerance for Different Approaches

I started re-reading Stroustrup's "The Design and Evolution of C++" over the
weekend. Here is a quote from section 1.3 (General Background):-

"Often when I was tempted to outlaw a feature I personally disliked, I
refrained from doing so because I did not think I had the right to force my
views on others. ..... A high degree of tolerance and acceptance that
different people think in different ways and strongly prefer to do things
differently is to me far preferable"

I think this is a good general principle, particularly in a case such as
this which is a matter of taste rather than one of fundamental importance.

Chris Gordon-Smith
www.simsoup.info
 
R

Richard Herring

Hendrik Schober said:
Richard said:
In message <[email protected]
roups.com> said:
[...] The one point I'd disagree with. The usual solution is to
write:
}
, correctly indented, and if the { is so far away that it isn't
evident, then to break the function up into smaller, more
manageable chunks.
I suspect I write more multidimensional numerical code than you do.
Sometimes the "most manageable chunk" is unavoidably several levels
deep in nested loops, and splitting it into separate functions would
actually obscure the structure of the algorithm.

I have never seen an algorithm that wouldn't benefit from
giving parts of them names and calling it by those.

Only if a meaningful name for the part is shorter than the code it
contains ;-)
Would
you care to give an example?

Just look at FFT or matrix inversion code, or something similar. Here's
a fragment taken from a simple one-dimensional FFT:

int j = 0;
for (int i = 0; i<n; ++i)
{
if (j>i)
{
for (int k=0; k<span; ++k)
{
swap(a[span*i+k], a[span*j+k]);
}
}
int m = n/2;
while (m>=2 && j>=m)
{
j -= m;
m /= 2;
}
j += m;
}
 
H

Hendrik Schober

Richard said:
Hendrik Schober said:
Richard said:
In message <[email protected]
[...] The one point I'd disagree with. The usual solution is to
write:
}
, correctly indented, and if the { is so far away that it isn't
evident, then to break the function up into smaller, more
manageable chunks.
I suspect I write more multidimensional numerical code than you do.
Sometimes the "most manageable chunk" is unavoidably several levels
deep in nested loops, and splitting it into separate functions would
actually obscure the structure of the algorithm.
I have never seen an algorithm that wouldn't benefit from
giving parts of them names and calling it by those.

Only if a meaningful name for the part is shorter than the code it
contains ;-)
Would
you care to give an example?

Just look at FFT or matrix inversion code, or something similar. Here's
a fragment taken from a simple one-dimensional FFT:

int j = 0;
for (int i = 0; i<n; ++i)
{
if (j>i)
{
for (int k=0; k<span; ++k)
{
swap(a[span*i+k], a[span*j+k]);
}
}
int m = n/2;
while (m>=2 && j>=m)
{
j -= m;
m /= 2;
}
j += m;
}

This doesn't apply. Neither do I see the need to mark all } with
the keyword that required it nor do I see a need to move parts
of this into its own functions. So I remain not convinced.
Do you have any better example?

Schobi
 
R

Richard Herring

Hendrik Schober said:
Richard said:
Hendrik Schober said:
Richard Herring wrote:
In message <[email protected]
[...] The one point I'd disagree with. The usual solution is to
write:
}
, correctly indented, and if the { is so far away that it isn't
evident, then to break the function up into smaller, more
manageable chunks.
I suspect I write more multidimensional numerical code than you do.
Sometimes the "most manageable chunk" is unavoidably several levels
deep in nested loops, and splitting it into separate functions would
actually obscure the structure of the algorithm.
I have never seen an algorithm that wouldn't benefit from
giving parts of them names and calling it by those.
Only if a meaningful name for the part is shorter than the code it
contains ;-)
Would
you care to give an example?
Just look at FFT or matrix inversion code, or something similar.
Here's
a fragment taken from a simple one-dimensional FFT:
int j = 0;
for (int i = 0; i<n; ++i)
{
if (j>i)
{
for (int k=0; k<span; ++k)
{
swap(a[span*i+k], a[span*j+k]);
}
}
int m = n/2;
while (m>=2 && j>=m)
{
j -= m;
m /= 2;
}
j += m;
}

This doesn't apply.
?

Neither do I see the need to mark all } with
the keyword that required it nor do I see a need to move parts
of this into its own functions.

But it has three levels of nesting, which some people seem to think is
too many. Yet you agree that it:

and I submit that you would find it difficult to give any of those inner
blocks a meaningful name.
So I remain not convinced.
Do you have any better example?
No, that's just a fragment of code that was to hand. I'm not inclined to
go digging for the perfect example, in the hope that I might eventually
find something that will "apply".
 
H

Hendrik Schober

Richard said:
Hendrik Schober said:
Richard said:
In message <[email protected]>, Hendrik Schober
Richard Herring wrote:
In message <[email protected]
[...] The one point I'd disagree with. The usual solution is to
write:
}
, correctly indented, and if the { is so far away that it isn't
evident, then to break the function up into smaller, more
manageable chunks.
I suspect I write more multidimensional numerical code than you do.
Sometimes the "most manageable chunk" is unavoidably several levels
deep in nested loops, and splitting it into separate functions would
actually obscure the structure of the algorithm.
I have never seen an algorithm that wouldn't benefit from
giving parts of them names and calling it by those.
Only if a meaningful name for the part is shorter than the code it
contains ;-)

Would
you care to give an example?
Just look at FFT or matrix inversion code, or something similar.
Here's
a fragment taken from a simple one-dimensional FFT:
int j = 0;
for (int i = 0; i<n; ++i)
{
if (j>i)
{
for (int k=0; k<span; ++k)
{
swap(a[span*i+k], a[span*j+k]);
}
}
int m = n/2;
while (m>=2 && j>=m)
{
j -= m;
m /= 2;
}
j += m;
}
This doesn't apply.

?

see below:
But it has three levels of nesting, which some people seem to think is
too many. Yet you agree that it:

It hasn't even 20 lines, and thus would even fit on an
ancient monochrome amber monitor. If it is an algorithm
that's well-known in the problem domain (I wouldn't know)
and if this is a whole function which is properly named,
I see no problem with this. And I see this as one of these
cases I thought James would refer to when he said proper
brace alignment would suffice.

Schobi
 
J

Jorgen Grahn

[#define ELSE ... etc]
I'll make a couple of other points on this overall discussion. ....
2) Tolerance for Different Approaches

I started re-reading Stroustrup's "The Design and Evolution of C++" over the
weekend. Here is a quote from section 1.3 (General Background):-

"Often when I was tempted to outlaw a feature I personally disliked, I
refrained from doing so because I did not think I had the right to force my
views on others. ..... A high degree of tolerance and acceptance that
different people think in different ways and strongly prefer to do things
differently is to me far preferable"

I think this is a good general principle, particularly in a case such as
this which is a matter of taste rather than one of fundamental importance.

It's (in my opinion) the correct approach for someone designing a
language like C++. I interpret it as "Do not try to guess what's good
practice or not; the users will do a better job at finding that out."

But it does not mean that everyone else should approve of every C++
macro trick people can come up with. It just means Bjarne won't show
up at your door and take your C++ compiler away.

regards,
/Jorgen
 

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

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,222
Latest member
patricajohnson51

Latest Threads

Top