Could C++ do this without the #pragma

S

Steven T. Hatton

Stroustrup says this:

http://www.research.att.com/~bs/bs_faq2.html#macro

"So, what's wrong with using macros?"

[...Macros are really bad (I paraphrase - STH)...]

"And yes, I do know that there are things known as macros that doesn't
suffer the problems of C/C++ preprocessor macros. However, I have no
ambitions for improving C++ macros. Instead, I recommend the use of
facilities from the C++ language proper, such as inline functions,
templates, constructors (for initialization), destructors (for cleanup),
exceptions (for exiting contexts), etc."

The GCC documentation says this:

http://gcc.gnu.org/onlinedocs/gcc-3.4.0/gcc/C---Interface.html#C++ Interface
"Declarations and Definitions in One Header"

"C++ object definitions can be quite complex. In principle, your source code
will need two kinds of things for each object that you use across more than
one source file. First, you need an interface specification, describing its
structure with type declarations and function prototypes. Second, you need
the implementation itself. It can be tedious to maintain a separate
interface description in a header file, in parallel to the actual
implementation. It is also dangerous, since separate interface and
implementation definitions may not remain parallel."

[...use our cool #pragmas and don't mess with source/implementation...(I
paraphrase - STH) ]

Now, my question is, can the same thing GCC is doing with #pragmas be done
with something internal to C++? I can't see how. I understand that
#pragma is basically a way for the implementation to introduce behavior not
specified in the standard, so there really isn't a direct contradiction to
what Stroustrup id saying. Nonetheless, I would like to be sure there is
no way to accomplish this within the C++ language proper.
 
P

Phlip

Steven said:
Stroustrup says this:

http://www.research.att.com/~bs/bs_faq2.html#macro

"So, what's wrong with using macros?"

[...Macros are really bad (I paraphrase - STH)...]

"And yes, I do know that there are things known as macros that doesn't
suffer the problems of C/C++ preprocessor macros. However, I have no
ambitions for improving C++ macros. Instead, I recommend the use of
facilities from the C++ language proper, such as inline functions,
templates, constructors (for initialization), destructors (for cleanup),
exceptions (for exiting contexts), etc."

Newbies coming to C++ from C often write obese macros, unaware that
templates and small methods are preferrable.

Here's a macro written by a non-newbie:

#define TEST_(suite, target) \
struct suite##target: public suite \
{ void runCase(); } \
a##suite##target; \
void suite##target::runCase()

TEST_(TestDialog, first_name)
{
CPPUNIT_ASSERT_EQUAL( "Ignatz",
m_aDlg.getText(IDC_EDIT_FIRST_NAME) );
}

Notice that it uses ## to paste tokens, and that a##suite##target
instantiates a small hidden object at the point where TEST_() got expressed.
You can't do these things with templates, but when you write TEST_() you
must not need to add any cruft or redundancies around it. They go inside the
macro.

Use macros for ## token pasting, # stringerization, and conditional
compilation. But if C++ treated classes as objects we could implement a more
common version of Test Collector, and not need macros.
The GCC documentation says this:

http://gcc.gnu.org/onlinedocs/gcc-3.4.0/gcc/C---Interface.html#C++ Interface
"Declarations and Definitions in One Header"

"C++ object definitions can be quite complex. In principle, your source code
will need two kinds of things for each object that you use across more than
one source file. First, you need an interface specification, describing its
structure with type declarations and function prototypes. Second, you need
the implementation itself. It can be tedious to maintain a separate
interface description in a header file, in parallel to the actual
implementation. It is also dangerous, since separate interface and
implementation definitions may not remain parallel."

[...use our cool #pragmas and don't mess with source/implementation...(I
paraphrase - STH) ]

Now, my question is, can the same thing GCC is doing with #pragmas be done
with something internal to C++? I can't see how. I understand that
#pragma is basically a way for the implementation to introduce behavior not
specified in the standard, so there really isn't a direct contradiction to
what Stroustrup id saying. Nonetheless, I would like to be sure there is
no way to accomplish this within the C++ language proper.

You misunderstand the pragma. It's only talking about the .h file's effect
on the .o files. With #prama interface the .o file only contains the names
of things in the class, so the .o file gets smaller. The pragma doesn't
affect the current translation unit ("module").

The size of .o files, the speed of compiling, and the speed of linking are
all notorious issues in the C languages. You will find many issues that only
macros can address, but they can't cover this one, because they can't
conditionally compile away things like the tables used for virtual method
dispatch.
 
S

Steven T. Hatton

Phlip said:
Steven said:
Stroustrup says this:

http://www.research.att.com/~bs/bs_faq2.html#macro

"So, what's wrong with using macros?"

[...Macros are really bad (I paraphrase - STH)...]
....
Newbies coming to C++ from C often write obese macros, unaware that
templates and small methods are preferrable.

Here's a macro written by a non-newbie:

#define TEST_(suite, target) \
struct suite##target: public suite \
{ void runCase(); } \
a##suite##target; \
void suite##target::runCase()

TEST_(TestDialog, first_name)
{
CPPUNIT_ASSERT_EQUAL( "Ignatz",
m_aDlg.getText(IDC_EDIT_FIRST_NAME) );
} ....
Use macros for ## token pasting, # stringerization, and conditional
compilation. But if C++ treated classes as objects we could implement a
more common version of Test Collector, and not need macros.
Here's an example fo something that does treat classes somewhat like
objects:
http://doc.trolltech.com/3.3/object.html

I believe you are hinting at something along the lines of a UBC (universal
base class) implementation. I don't believe you can sell that to the C++
Comittee. But there is certainly room for a sub-universal base class
implemented as a library. I'm starting to have visions of a development
environment that enforces certain constraints on the code in order to
confine the language to a more manageable form. For example, there would
be a required correspondence between directory structure, namespaces,
header names, and perhaps other things. I believe there is an unnecessary
number of degrees of freedom in C++. That leads to too many open-ended
situations where it is difficult to determine what a program is doing, and
how it is structured without examining a lot of details to determine which
of the equally valid options the developer chose.
http://gcc.gnu.org/onlinedocs/gcc-3.4.0/gcc/C---Interface.html#C++ Interface

You misunderstand the pragma. It's only talking about the .h file's effect
on the .o files. With #prama interface the .o file only contains the names
of things in the class, so the .o file gets smaller. The pragma doesn't
affect the current translation unit ("module").

My understanding is #pragmas in general are a way to cause the
implementation to behave in an implementation defined manner. Which
basically means, they can do anything the implementation can get away with.
The specific #pragma interface and #pragma implementation do influence the
way a translation unit is processed. They are also intended to be used in
conjunction with a different approach to organizing code in files.
Specifically, the entire body of code, both interface (declaration) and
implementation (definition) are contained in the same header file. The use
of the #pragma preprocessing directives instruct the compiler to produce
object code, or merely to treat the file as a mapping to the actual object
code depending on how they are used.
The size of .o files, the speed of compiling, and the speed of linking are
all notorious issues in the C languages. You will find many issues that
only macros can address, but they can't cover this one, because they can't
conditionally compile away things like the tables used for virtual method
dispatch.

I don't disagree with that, but there is more to the use of these directives
than reducing code size and compile times. I had chosen to focus on the
issues that effect source code organization, rather than compiling and
linking.
 
A

Alf P. Steinbach

* "Phlip said:
Newbies coming to C++ from C often write obese macros, unaware that
templates and small methods are preferrable.

Here's a macro written by a non-newbie:

That doesn't seem to be the case.


#define TEST_(suite, target) \
struct suite##target: public suite \
{ void runCase(); } \
a##suite##target; \
void suite##target::runCase()

TEST_(TestDialog, first_name)
{
CPPUNIT_ASSERT_EQUAL( "Ignatz",
m_aDlg.getText(IDC_EDIT_FIRST_NAME) );
}

Notice that it uses ## to paste tokens, and that a##suite##target
instantiates a small hidden object at the point where TEST_() got expressed.

Exactly.
 
P

Phlip

Alf said:
Phlip schriebt:


That doesn't seem to be the case.


Exactly.

Here's the same macro, from CppUnitLite, published by Object Mentors:

#define TEST(testName, testGroup)\
class testGroup##testName##Test : public Test \
{ public: testGroup##testName##Test () : Test (#testName "Test") {} \
void run (TestResult& result_); } \
testGroup##testName##Instance; \
void testGroup##testName##Test::run (TestResult& result_)

I had never looked at it before, but I see now that it also creates a
very similar small hidden object. I suspect this derives from Mike
Feathers (an author and lecturer from Object Mentor), but I downloaded
this from James Grenning (OM's director of consulting, and also a
journalist and lecturer on programming).

http://www.fitnesse.org/

So me and they seem to have parallel-evolved the same simple solution
to the "Test Collector Pattern" in C++.

Alf, as you value your reputation, please take care not to make such
an idiot of yourself on a public forum.
 
A

Alf P. Steinbach

* (e-mail address removed) (Phlip) schriebt:
Here's the same macro, from CppUnitLite, published by Object Mentors:

#define TEST(testName, testGroup)\
class testGroup##testName##Test : public Test \
{ public: testGroup##testName##Test () : Test (#testName "Test") {} \
void run (TestResult& result_); } \
testGroup##testName##Instance; \
void testGroup##testName##Test::run (TestResult& result_)

The CppUnitLite macro does something that only a macro can, namely
registering the _name_ of the test for use at runtime, and that is
presumably also why it's using a base class with virtual function.

Your macro doesn't do anything that needs a macro, and uses a totally
unnecessary base class with virtual function; it seems you have copied
and modified code without understanding the why's and wherefore's.

Alf, as you value your reputation, please take care not to make such
an idiot of yourself on a public forum.

Are you sure that is a forceful argument?
 
P

Phlip

Alf said:
The CppUnitLite macro does something that only a macro can, namely
registering the _name_ of the test for use at runtime, and that is
presumably also why it's using a base class with virtual function.

Your macro doesn't do anything that needs a macro, and uses a totally
unnecessary base class with virtual function; it seems you have copied
and modified code without understanding the why's and wherefore's.

My macro does the same thing, the same way, using the same code techniques.
Both let you write a test case like this:

TEST(TestCase, something)
{
assert (something());
}

That prevents excess bookkeeping making a list of cases for each suite.

If you think you have an argument to defend here, write the Test Collector
Pattern in C++, with either macros or some other mechanism.
 
A

Alf P. Steinbach

* "Phlip said:
My macro does the same thing, the same way, using the same code techniques.

Compare


(that is, nothing) in your code, to

public: testGroup##testName##Test () : Test (#testName "Test") {}

in the CppUnitLite code.

That is the crucial little bit of code that presumably the Test base
class (and also SimpleString, not shown in these snippets) is meant to
support, and it is the only thing that requires a macro.

It is not present in your code, so your macro does not do the same
thing; in fact it does not do the thing or any comparable thing at all.

Both let you write a test case like this:

TEST(TestCase, something)
{
assert (something());
}

That prevents excess bookkeeping making a list of cases for each suite.

So why do you think you need a macro and a base class and a virtual
function for that? You don't. It is an approach that works, yes, as
zillion other even more convoluted approaches do, but it's not an
example of a macro "written by a non-newbie", as you maintained it is.

If you think you have an argument to defend here

I'm correcting a false impression you have, intentionally or not, put
forward in a public forum, namely that your macro is a good example of
macro usage, "written by a non-newbie" -- which it absolutely is not.

write the Test Collector
Pattern in C++, with either macros or some other mechanism.

The relevant thing to do would instead be to write a macro that gives
the essential effect of the macro you presented, namely a shorthand
notation for declaring and registering a test function, sans the
unnecessary convoluted things.

For that you might find it educational to check out the Boost unit test
framework.

Which provides exactly that.
 
P

Phlip

Alf said:
techniques.

Compare


(that is, nothing) in your code, to

public: testGroup##testName##Test () : Test (#testName "Test") {}

in the CppUnitLite code.

My code was simpler. That line passes the name of the test to the base
class. I have used other ways to introduce the name (and I don't consider
passing it in the constructor necessarily elegant).

Both my code and the published CppUnitLite code used token pasting. To the
newbies: Use #define for token pasting, stringerization (like the
CppUnitLite sample), and conditional compilation.

(And I suspect you decided to dislike my code before finding one silly
line's difference with the other version. Your somewhat vague complaints
have been slipping...)
I'm correcting a false impression you have, intentionally or not, put
forward in a public forum, namely that your macro is a good example of
macro usage, "written by a non-newbie" -- which it absolutely is not.

Okay. Feathers is a newbie too. We are nearing agreement!
The relevant thing to do would instead be to write a macro that gives
the essential effect of the macro you presented, namely a shorthand
notation for declaring and registering a test function, sans the
unnecessary convoluted things.

Pardon my newbescence - what was unnecessary?

(Keep in mind both our macros permit test suite classes with setUp() and
tearDown() methods, but of course you knew that...)
For that you might find it educational to check out the Boost unit test
framework.

Do you mean this?

http://www-eleves-isia.cma.fr/docum...bs/test/doc/unit_test_framework.htm#TestSuite

void test_feature1()
{
...
}
....

ts->add( BOOST_TEST_CASE( &test_feature1 ) );

That's the cruft our macros avoid. In that system, you write
the test case, then go to another location in the code and
add the case to a suite. Our system uses "Test Collector",
which enroles the cases in the suites automatically, without
extra unnecessary convoluted things.

To give each suite's linked list a node, both our systems
create a small unique object, of a polymorphic type,
using token pasting.
 
S

Steven T. Hatton

Phlip said:
Steven said:
Stroustrup says this:

http://www.research.att.com/~bs/bs_faq2.html#macro

"So, what's wrong with using macros?"

[...Macros are really bad (I paraphrase - STH)...]

"And yes, I do know that there are things known as macros that doesn't
suffer the problems of C/C++ preprocessor macros. However, I have no
ambitions for improving C++ macros. Instead, I recommend the use of
facilities from the C++ language proper, such as inline functions,
templates, constructors (for initialization), destructors (for cleanup),
exceptions (for exiting contexts), etc."

Newbies coming to C++ from C often write obese macros, unaware that
templates and small methods are preferrable.

Here's a macro written by a non-newbie:

#define TEST_(suite, target) \
struct suite##target: public suite \
{ void runCase(); } \
a##suite##target; \
void suite##target::runCase()

TEST_(TestDialog, first_name)
{
CPPUNIT_ASSERT_EQUAL( "Ignatz",
m_aDlg.getText(IDC_EDIT_FIRST_NAME) );
}

Notice that it uses ## to paste tokens, and that a##suite##target
instantiates a small hidden object at the point where TEST_() got
expressed. You can't do these things with templates, but when you write
TEST_() you must not need to add any cruft or redundancies around it. They
go inside the macro.

Use macros for ## token pasting, # stringerization, and conditional
compilation. But if C++ treated classes as objects we could implement a
more common version of Test Collector, and not need macros.
The GCC documentation says this:
http://gcc.gnu.org/onlinedocs/gcc-3.4.0/gcc/C---Interface.html#C++ Interface
"Declarations and Definitions in One Header"

"C++ object definitions can be quite complex. In principle, your source code
will need two kinds of things for each object that you use across more than
one source file. First, you need an interface specification, describing its
structure with type declarations and function prototypes.

You misunderstand the pragma. It's only talking about the .h file's effect
on the .o files. With #prama interface the .o file only contains the names
of things in the class, so the .o file gets smaller. The pragma doesn't
affect the current translation unit ("module").

The size of .o files, the speed of compiling, and the speed of linking are
all notorious issues in the C languages. You will find many issues that
only macros can address, but they can't cover this one, because they can't
conditionally compile away things like the tables used for virtual method
dispatch.

I've been discussing this on the gcc mailing list, and the responses I've
received have been along the lines of 'the documentation says _that_?'. It
seems I have not correctly understood what the #pragmas are doing, but may
have correctly understood the documentation. I.e., the documentation is
wrong. If I've accomplished anything, it will be to have the #pragma
interface/implementation deprecated, and/or the documentation corrected.

Oh, and I guess I was able to instigate yet another unseemly knock-down,
drag-out fight on c.l.c++, so it was not all for naught. :)
 
P

Phlip

Steven said:
I've been discussing this on the gcc mailing list, and the responses I've
received have been along the lines of 'the documentation says _that_?'. It
seems I have not correctly understood what the #pragmas are doing, but may
have correctly understood the documentation. I.e., the documentation is
wrong. If I've accomplished anything, it will be to have the #pragma
interface/implementation deprecated, and/or the documentation corrected.

Oh, and I guess I was able to instigate yet another unseemly knock-down,
drag-out fight on c.l.c++, so it was not all for naught. :)

Try this (from VC++):

#import <mso9.dll>

Hours of fun. For example: Is it a valid implementation-defined
extension? I thought those had to begin with str, __, or #pragma!
 

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,995
Messages
2,570,236
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top