Topic: Qualified macro names?


Author: Steve Clamage <clamage@eng.sun.com>
Date: Mon, 18 Mar 2002 21:57:09 GMT
Raw View
On Sun, 17 Mar 2002, Gennaro Prota wrote:
>
> for the few uses were macros are necessary in C++, what about
> introducing facilities for macros with qualified names?
>
> Let's say something like:
>
> // MY_MACRO not defined so far
>
> #scope SCOPE_NAME1
> #   define MY_MACRO 2
> #end_scope
>
> #scope SCOPE_NAME2
> #   define MY_MACRO 3
> #end_scope
>
> int n = MY_MACRO; // error
>
> int n = SCOPE_NAME1::MY_MACRO; // ok
>
>
> Would it require strong changes to the language?

It would require strong changes to the preprocessor. The next
thing you would ask for would be #using!

#scope S1
#define MAC1 11
#end_scope
#using MAC1
int x = MAC1;


C++ has a preprocessor phase for compatibility with C, not because
the preprocessor is considered a good idea. The trend of C++
language development is to find ways to reduce the use of the
preprocessor, not to add features to it.

The more you use the preprocessor, the less understandable your
code becomes. Program development tools (browsers, syntax-directed
editors, etc) also have problems with the preprocessor, since you
can't know what the program text looks like until you process all
the macros and conditional compilation.

--
Steve Clamage, stephen.clamage@sun.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: res0oqmv@verizon.net
Date: Mon, 18 Mar 2002 23:28:45 GMT
Raw View
I think the majority of the changes would be to the preprocessor, not
the language compiler. You could probably achieve close to what you
want by using c++ namespaces with inlined routines rather than
preprocessor macros.

willy

On Sun, 17 Mar 2002 19:24:41 GMT, Gennaro Prota
<gennaro_prota@yahoo.com> wrote:

>Hi everybody,
>
>for the few uses were macros are necessary in C++, what about
>introducing facilities for macros with qualified names?
>
>Let's say something like:
>
>// MY_MACRO not defined so far
>
>#scope SCOPE_NAME1
>#   define MY_MACRO 2
>#end_scope
>
>#scope SCOPE_NAME2
>#   define MY_MACRO 3
>#end_scope
>
>int n = MY_MACRO; // error
>
>int n = SCOPE_NAME1::MY_MACRO; // ok
>
>
>Would it require strong changes to the language?
>
>Genny.
>
>
>
>
>
>
>---
>[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
>[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
>[              --- Please see the FAQ before posting. ---               ]
>[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Leavings" <leavings@attbi.com>
Date: Tue, 19 Mar 2002 09:27:57 GMT
Raw View
"Steve Clamage" <clamage@eng.sun.com> wrote in message
news:Pine.SOL.4.33.0203181330050.22372-100000@taumet...
> It would require strong changes to the preprocessor. The next
> thing you would ask for would be #using!
>
> #scope S1
> #define MAC1 11
> #end_scope
> #using MAC1
> int x = MAC1;
>
>
> C++ has a preprocessor phase for compatibility with C, not because
> the preprocessor is considered a good idea. The trend of C++
> language development is to find ways to reduce the use of the
> preprocessor, not to add features to it.

In that case, you have to add to the language proper facilities to perform all
that the preprocessor can currently do.

Take, for example, a function_traits type of class (or an is_function
meta-programming construct).  To properly implement these things, you must make
a specialization for a conceivably infinite number of function types.  This
causes a huge amount of code repetition, so any changes to the root idea cause
possibly hundreds (or thousands) of changes in all of the specializations.
Basically, this is all because the C++ template mechanism cannot make this type
of syntax:  T1, T2, T3.  However, the preprocessor *can* do this, it just
requires a plethora of macros, but those macros can be designed to be
reusable--see the Boost preprocessor library for examples.

I designed my own version of this type of thing a while back.  This is what I
have *instead* of a hundred partial specializations of 'is_function':

template<class T> struct is_function {
    enum { value = false };
};

??=include ENABLE(linearize.h)

#include MACRO(C) \
    template<class R INSERT_PUNC(C, COMMA) LIST_CLASS_T(C)> \
    struct is_function<R (LIST_T(C))> { \
        enum { value = true }; \
    }; \
    template<class R INSERT_PUNC(C, COMMA) LIST_CLASS_T(C)> \
    struct is_function<R (LIST_T(C) ...)> { \
        enum { value = true }; \
    };

#include MAKE(100)

??=include DISABLE(linearize.h)

The template mechanism *cannot* beat that, because it is inherently token
oriented rather than syntaxual ( oh my, is that even a word? ).

But, because of the lack of any template scoping mechanism, I have to #undef all
of the macros used to make the above work.  That is the purpose of the
ENABLE/DISABLE macros above.  Worse yet, these macros ENABLE/DISABLE are forced
to do a reference-counted inclusion, so that the implementation itself can use
other facilities that a user might be using already.  The "linearize.h" file
above uses another preprocessor-type file "decr.h" (which does decrementing), so
if a user does this...

#include ENABLE(decr.h)
// ...
#include ENABLE(linearize.h)
// ...
#include DISABLE(linearize.h)
// ...
#include DISABLE(decr.h)

...everything still works correctly and is defined and undefined correctly.
This is a really terrible mechanism that I'm forced to use because I'm deathly
afraid of leaving all those macros around defined.  With some sort of scoping
mechanism, I wouldn't have to undef everything.

Besides, adding such a facility would not over-complicate the preprocessor, even
if you *did* have #using directives (or similar).  On a further note, the C++
standard library itself defines macros, those names effectively become unusable
*anywhere* else.  Take 'assert' for example.  How many 'assert' names do I have
in any of my code?  None, because it is unsafe to use it--precisely because it
is totally unscoped.

> The more you use the preprocessor, the less understandable your
> code becomes. Program development tools (browsers, syntax-directed
> editors, etc) also have problems with the preprocessor, since you
> can't know what the program text looks like until you process all
> the macros and conditional compilation.

I have yet to see a text editor or browser that doesn't get horribly confused
and choke to death on any kind of full use of the template mechanism anyway.

Also, the more you use the template mechanism (and C++ proper) to simulate what
the preprocessor does, the less understandable your code becomes.  It works both
ways, it just moves it from 'token-mode' to 'syntax-mode'.  I agree that there
are certain 'old-fashioned' uses of the preprocessor that can be better
implemented with C++ language features, such as inlined functions or constants,
etc., yet there are others that are completely unavoidable, that the C++
language proper can't even come close to simulating.  What it really comes down
to, is whether one uses a feature appropriately or not.  For instance, I have a
header file called 'closure.h' that implements a closure class template and some
related facilities.  I consider this to be an excellent example of proper use.
This header can be used to implement operator->* for smart_ptr-like classes, and
it uses the preprocessor extensively, because there is *no other reasonable
way*.

// e.g.

#include "closure.h"

template<class T> class smart_ptr {
    private:
        T* m_obj;
        // ...
    public:
        smart_ptr(T* obj) : m_obj(obj) {
            return;
        }
        ~smart_ptr() {
            delete m_obj;
        }
        template<class U> inline typename closure<U>::return_type operator->*(U
ptr) {
            return make_closure(m_obj, ptr);
        }
};

This is a *very* simple to use facility.  Also, there are 'zero' macros left
defined from 'closure.h'.  By the way, the above implements operator->* for
pointer-to-data-members and pointer-to-member-functions (including const,
volatile, const volatile) from 0 to 100 arguments.  The only thing it doesn't
handle (besides > 100 arguments) is ellipsis member functions, since that is
more-or-less impossible in a generic way.

I certainly don't think that this makes the code above less understandable.  In
fact, I think that it makes it significantly more understandable than an
equivalent C++ proper only implementation (even the header itself is better,
though granted the preprocessor mechanisms that the header uses are a nightmare,
but they are localized).  So, like I said before, the preprocessor is not good
or evil, it is how you use it.  If used appropriately, for the types of things
that a preprocessor should be used for, it can be a very effective and useful
tool to which there is no analog in a language itself.  I can only think that
C++ would be improved with a macro-scoping mechanism.

Also, this 'avoid the preprocessor' mentality is a direct result of the
primitiveness and *lack* of features of the preprocessor not the inherent
properties of 'preprocessors' (i.e. token-mode compilers) themselves.

If you take the Win32 headers (which I agree are not a good example) or you take
the ATL headers (ATL being a 'relatively' new thing as opposed to the Win32
headers), they use macros a great deal--though not in ways that I think are
justifiable.  But, justifiable or not, you can't say 'the trend' is away from
the preprocessor, when more preprocessor-like tools, more preprocessor-like
libraries, etc. become available all the time (i.e. Boost).  It is unreasonable
to say there is no good justification for token-mode interpretation other than
inheriting it from C, though that is obviously why we have the one that we have.

For instance, what is the template mechanism but a really complicated
preprocessor (i.e. compile-time only mechanism)?  I'm certainly not knocking the
template mechanism, but the only reason that template mechanism is better than
the preprocessor is because of its tighter integration with the language
(scoping, type-checking, etc.) and set of facilities (i.e. feature set).  In
other words, it is better *because* it has *more* features and is *less*
primitive, the C++ preprocessor could be improved in this regard also.

Paul Mensonides


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: gennaro_prota@yahoo.com (Gennaro Prota)
Date: Tue, 19 Mar 2002 16:45:11 GMT
Raw View
Steve Clamage <clamage@eng.sun.com> wrote in message news:<Pine.SOL.4.33.0203181330050.22372-100000@taumet>...
> On Sun, 17 Mar 2002, Gennaro Prota wrote:
> >
> > for the few uses were macros are necessary in C++, what about
> > introducing facilities for macros with qualified names?
> >
> > Let's say something like:
> >
> > // MY_MACRO not defined so far
> >
> > #scope SCOPE_NAME1
> > #   define MY_MACRO 2
> > #end_scope
> >
> > #scope SCOPE_NAME2
> > #   define MY_MACRO 3
> > #end_scope
> >
> > int n = MY_MACRO; // error
> >
> > int n = SCOPE_NAME1::MY_MACRO; // ok
> >
> >
> > Would it require strong changes to the language?
>
> It would require strong changes to the preprocessor. The next
> thing you would ask for would be #using!

I swear I won't! :) Since there's no scoping mechanism related to
macros I wouldn't mimic in toto what we have for declarations. The
word "scope" I used in

#scope

is itself improper; what I'd like (as a palliative to actually remove
preprocessing from the compilation) is a facility to control macro
substitution: at the moment replacement is required, in each
translation unit, for each occurrence of a (not #undef'd) macro name
that follows its definition. With something like "def-sections" in the
grammar of    16 we could add to the plain "each occurrence" (for macros
defined "out of sections") an "each occorrence [...] preceded by
section-name ::, where section-name is...".

I know that this will never go into the standard, and that the current
thread is to totally remove preprocessing (on which I agree, provided
that we find a superior alternative, expecially for conditional
compilation), but I'm curious about what changes this could require
(or could have required). After all, I wonder why something like this
hasn't been introduced in the language since its creation.


Thanks for your reply :)
Genny.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "leavings" <leavings@attbi.com>
Date: Wed, 20 Mar 2002 11:04:11 CST
Raw View
(moderators:  I apologize for any double posts, I'm using attbi (unfortunately,
that should explain everything)

> Take, for example, a function_traits type of class (or an is_function
> meta-programming construct).  To properly implement these things, you must
make
> a specialization for a conceivably infinite number of function types.  This
> causes a huge amount of code repetition, so any changes to the root idea cause
> possibly hundreds (or thousands) of changes in all of the specializations.
> Basically, this is all because the C++ template mechanism cannot make this
type
> of syntax:  T1, T2, T3.  However, the preprocessor *can* do this, it just
> requires a plethora of macros, but those macros can be designed to be
> reusable--see the Boost preprocessor library for examples.

[snip]

> template<class T> struct is_function {
>     enum { value = false };
> };
>
> ??=include ENABLE(linearize.h)
>
> #include MACRO(C) \
>     template<class R INSERT_PUNC(C, COMMA) LIST_CLASS_T(C)> \
>     struct is_function<R (LIST_T(C))> { \
>         enum { value = true }; \
>     }; \
>     template<class R INSERT_PUNC(C, COMMA) LIST_CLASS_T(C)> \
>     struct is_function<R (LIST_T(C) ...)> { \
>         enum { value = true }; \
>     };
>
> #include MAKE(100)
>
> ??=include DISABLE(linearize.h)

This example has been rendered obsolete by the geniuses over at
comp.lang.c++.moderated, specifically by Rani Sharoni.  There is a new and
better way then the above.  (See the thread 'is_enum<T> ATTN:  Andrei
Alexandrescu' which I started over there.)  It involves a new (as far as I know)
way to overload functions with explicit template parameters.

Nevertheless, something more complicated then a true/false is_function value,
such as a full function_traits class (or is_ptr_to_member_function maybe) still
requires massive repetition.  Happily, this is one less area that I have to use
it in. :)

Paul Mensonides


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Gennaro Prota <gennaro_prota@yahoo.com>
Date: Sun, 17 Mar 2002 19:24:41 GMT
Raw View
Hi everybody,

for the few uses were macros are necessary in C++, what about
introducing facilities for macros with qualified names?

Let's say something like:

// MY_MACRO not defined so far

#scope SCOPE_NAME1
#   define MY_MACRO 2
#end_scope

#scope SCOPE_NAME2
#   define MY_MACRO 3
#end_scope

int n = MY_MACRO; // error

int n = SCOPE_NAME1::MY_MACRO; // ok


Would it require strong changes to the language?

Genny.






---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]