www.digitalmars.com         C & C++   DMDScript  

D - Macros

reply "Richard Krehbiel" <rich kastle.com> writes:
Okay, why is it that everybody thinks the C preprocessor is terrible and
needs to be avoided?  C++ only has it for compatability; Java and C# and D
don't have one.  I just don't get this one.

I personally have wished for *more* macro processing power.

Not for typedefs.  Not for constant definitions.  Not for #include files or
guards.  For *macros*.

By "macros" I mean something that lets a programmer add power to the
language translator.  Something with access to the type system of the
compiler.  So I could write a generic macro that iterates through the
members of any given structure and generate code to print them in context.
So that I can write a package of macros that simplify binding SQL
parameters, because it can detect data types.  So that I can write generics
and templates using macros.

Cut from the language document:

"But [macros] have a downside:
Macros have no concept of scope; they are valid from the point of definition
to the end of the source. They cut a swath across .h files, nested code,
etc. When #include'ing tens of thousands of lines of macro definitions, it
becomes problematicalto avoid inadvertent macro expansions."

So, invent reasonable scoping and naming rules.  I don't need cpp
specifically; I just want macros.

"Macros are unknown to the debugger. Trying to debug a program with symbolic
data is undermined by the debugger only knowing about macro expansions, not
themacros themselves."

This need not be true, even in C.

"Macros make it impossible to tokenize source code, as an earlier macro
change can arbitrarilly redo tokens."

Um - I don't understand this at all.

"The purely textual basis of macros leads to arbitrary and inconsistent
usage, making code using macros error prone. (Some attempt to resolve this
was introduced with templates in C++.)"

Take the "purely textual basis" away, and give the macro language access to
the type system.

"Macros are still used to make up for deficits in the language's expressive
capabiltiy, such as for "wrappers" around header files."

But since you're fixing those language deficits, macros won't be used for
that anymore.

--
Richard Krehbiel, Arlington, VA, USA
rich kastle.com (work) or krehbiel3 home.com (personal)
Aug 16 2001
next sibling parent Richard Burk <sfentress home.com> writes:
As far as providing some sort of macro language to the system I would
recommend that generics be used modelled after generics in Ada.  I programmed in

Ada83 for three years solid.  Generics did full type checking and allowed for
rapid
development of lists, stacks, etc of various types.  I highly recommend the
generics
model from Ada.  I have little experience with Ada95, but it extended the power
of generics and what little experience I had with it was quite impressive.
Unfortunately the project I was on was killed.  I have been doing C, C++, and
Java mostly since.  I agree that the template implementation in C++ is horribly
implemented.  In fact I used macros to do the same as templates in C++, but it
was
really more like using generics in Ada except without the strong type checking
of
Ada.  I believe that Java suffers from the lack of generics/templates.
Hopefully
when they add it, it will be modelled from Ada.  For D I believe that it would
be
wise to add generics.  When they are done well as in Ada they are most
powerful.

Richard Burk


Richard Krehbiel wrote:

 Okay, why is it that everybody thinks the C preprocessor is terrible and
 needs to be avoided?  C++ only has it for compatability; Java and C# and D
 don't have one.  I just don't get this one.

 I personally have wished for *more* macro processing power.

 Not for typedefs.  Not for constant definitions.  Not for #include files or
 guards.  For *macros*.

 By "macros" I mean something that lets a programmer add power to the
 language translator.  Something with access to the type system of the
 compiler.  So I could write a generic macro that iterates through the
 members of any given structure and generate code to print them in context.
 So that I can write a package of macros that simplify binding SQL
 parameters, because it can detect data types.  So that I can write generics
 and templates using macros.

 Cut from the language document:

 "But [macros] have a downside:
 Macros have no concept of scope; they are valid from the point of definition
 to the end of the source. They cut a swath across .h files, nested code,
 etc. When #include'ing tens of thousands of lines of macro definitions, it
 becomes problematicalto avoid inadvertent macro expansions."

 So, invent reasonable scoping and naming rules.  I don't need cpp
 specifically; I just want macros.

 "Macros are unknown to the debugger. Trying to debug a program with symbolic
 data is undermined by the debugger only knowing about macro expansions, not
 themacros themselves."

 This need not be true, even in C.

 "Macros make it impossible to tokenize source code, as an earlier macro
 change can arbitrarilly redo tokens."

 Um - I don't understand this at all.

 "The purely textual basis of macros leads to arbitrary and inconsistent
 usage, making code using macros error prone. (Some attempt to resolve this
 was introduced with templates in C++.)"

 Take the "purely textual basis" away, and give the macro language access to
 the type system.

 "Macros are still used to make up for deficits in the language's expressive
 capabiltiy, such as for "wrappers" around header files."

 But since you're fixing those language deficits, macros won't be used for
 that anymore.

 --
 Richard Krehbiel, Arlington, VA, USA
 rich kastle.com (work) or krehbiel3 home.com (personal)

Aug 16 2001
prev sibling next sibling parent Charles Hixson <charleshixsn earthlink.net> writes:
I don't really like macros.  Perhaps that should be "I really don't like 
macros".
However ..., perhaps instead:
1) OTOH, generics are quite useful.  They have been shown to work well 
when designed into a language.
2) And "some sort" of preprocessing would be useful.  However, since the 
language is designed to be embedded in HTML, perhaps it could also be 
embedded in XML.  This would allow any XML aware tool to act as a 
pre-processor.  It wouldn't need to be a basic part of the language 
definition, but could just be a ... reccomended practice?  Annex? 
Optional extra?  It would really be more a part of the "IDE" than of the 
language, but it could do type-aware substitutions creating "temporary 
files" that were fed to the compiler as needed.
Aug 16 2001
prev sibling next sibling parent reply Russell Bornschlegel <kaleja estarcion.com> writes:
Richard Krehbiel wrote:
 
 Okay, why is it that everybody thinks the C preprocessor is terrible and
 needs to be avoided?  C++ only has it for compatability; Java and C# and D
 don't have one.  I just don't get this one.

As you rightly note, the C preprocessor isn't powerful enough for general macro work. I think the usual position is that if you want macros, you should be using a dedicated macro processor that's better than C's, and that typedefs, constants, and inclusion should be part of the language instead of a bag on the side.
 I personally have wished for *more* macro processing power.
 
 Not for typedefs.  Not for constant definitions.  Not for #include files or
 guards.  For *macros*.

Have you looked into m4? -Russell B
Aug 16 2001
parent "Richard Krehbiel" <rich kastle.com> writes:
"Russell Bornschlegel" <kaleja estarcion.com> wrote in message
news:3B7C44FB.CC45479D estarcion.com...
 Richard Krehbiel wrote:
 Okay, why is it that everybody thinks the C preprocessor is terrible and
 needs to be avoided?  C++ only has it for compatability; Java and C# and


 don't have one.  I just don't get this one.

As you rightly note, the C preprocessor isn't powerful enough for general macro work. I think the usual position is that if you want macros, you should be using a dedicated macro processor that's better than C's, and that typedefs, constants, and inclusion should be part of the language instead of a bag on the side.

I want a macro language that is *more* tightly integrated, with access to the type system, and a macro language that looks more like the subject language than an add-on. So I can write a macro something like this: macro trace_var(indent, var) { printf("%*s%s %s=", indent, "", typename(var), name(var)); if(promoted(typeof(var)) == typeof(int)) printf("%d", var); else if(promoted(typeof(var)) == typeof(double)) printf("%g", var); else if(typeof(var) == typeof(struct)) { foreach(void m in membersof(arg)) { trace_var(indent+2, m); } } }
 I personally have wished for *more* macro processing power.

 Not for typedefs.  Not for constant definitions.  Not for #include files


 guards.  For *macros*.

Have you looked into m4?

Actually, I've done a bit of work using m4. I think it's really powerful :-) and really difficult to use. :-( The quoting rules always confuse me. -- Richard Krehbiel, Arlington, VA, USA rich kastle.com (work) or krehbiel3 home.com (personal)
Aug 17 2001
prev sibling next sibling parent reply "Kent Sandvik" <sandvik excitehome.net> writes:
"Richard Krehbiel" <rich kastle.com> wrote in message
news:9lgk0b$243j$1 digitaldaemon.com...
 By "macros" I mean something that lets a programmer add power to the
 language translator.  Something with access to the type system of the
 compiler.  So I could write a generic macro that iterates through the
 members of any given structure and generate code to print them in context.
 So that I can write a package of macros that simplify binding SQL
 parameters, because it can detect data types.  So that I can write

 and templates using macros.

I agree, there's something good about having the power to override certain restrictions put in place in the language. Yes it's like a dangerous knife, but sometimes a sharp knife is needed, as well. So I do miss the option of having some macro-processing, LISP has this power, and it's been used for very interesting solutions. This is more concerning the power to re-define statements and meta data, and not about the classical use of macros, i.e. smart inlining in order to try to produce tight code... --Kent
Aug 16 2001
parent reply "Richard Krehbiel" <rich kastle.com> writes:
"Kent Sandvik" <sandvik excitehome.net> wrote in message
news:9lhobc$at8$1 digitaldaemon.com...
 "Richard Krehbiel" <rich kastle.com> wrote in message
 news:9lgk0b$243j$1 digitaldaemon.com...
 By "macros" I mean something that lets a programmer add power to the
 language translator.  Something with access to the type system of the
 compiler.  So I could write a generic macro that iterates through the
 members of any given structure and generate code to print them in


 So that I can write a package of macros that simplify binding SQL
 parameters, because it can detect data types.  So that I can write

 and templates using macros.

I agree, there's something good about having the power to override certain restrictions put in place in the language. Yes it's like a dangerous

 but sometimes a sharp knife is needed, as well. So I do miss the option of
 having some macro-processing, LISP has this power, and it's been used for
 very interesting solutions. This is more concerning the power to re-define
 statements and meta data, and not about the classical use of macros, i.e.
 smart inlining in order to try to produce tight code... --Kent

Well, frankly, LISP is not the language for me. :-/ The greatest exposure I've had to LISP is some programming in Emacs-LISP. But what I do appreciate is that LISP's macros are very powerful, and that they look like LISP. -- Richard Krehbiel, Arlington, VA, USA rich kastle.com (work) or krehbiel3 home.com (personal)
Aug 17 2001
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
Richard Krehbiel wrote:
 ...I've had to LISP is some programming in Emacs-LISP.
 
 But what I do appreciate is that LISP's macros are very powerful, and that
 they look like LISP.
 
 --
 Richard Krehbiel, Arlington, VA, USA
 rich kastle.com (work) or krehbiel3 home.com (personal)
 

same. But they don't act the same. Their rules for parameter passing, e.g., are different. And their run-time behavior is different. Now of course, if it weren't different, there wouldn't be any reason to need it. But it damages the internal unity of the language at the same time that it makes it more powerful. If you're going to have macros as a distinct part of the language, then you need to enable them to be recognized at a glance, without being so obtrusive that it's hard to see anything else. Syntax markers can be a good choice, but references as well as definitions need to be easily recognizable (and I find all upper case names QUITE UGLY), also, the marker needs to be linguistic rather than conventional. Perhaps having macro names start with . followed by a letter (or an underscore?). The hash mark for definitions is good. But it would be better to design a language that didn't need macros.
Aug 17 2001
parent "Richard Krehbiel" <rich kastle.com> writes:
"Charles Hixson" <charleshixsn earthlink.net> wrote in message
news:3B7D31A6.6020008 earthlink.net...
 But it would be better to design a language that didn't need macros.

IMHO that language is necessarily an interpreted one, because I ask specifically for full access to the type system. Java comes pretty close; you can query class definitions, but the primitive types are troublesome. You can make "generic" collections of Object, but the primitive types aren't objects. And you can't do type checking at compile time either. Java executables (.class files) carry their symbol tables, so that in the unlikely event that they're needed, they can be queried. A purely compiled-to-native-code language shouldn't have that property. So if the programmer's going to write code to inspect the type system, it'll need to execute during the compile phase - and that's what I call a macro language.
Aug 17 2001
prev sibling next sibling parent reply "Tim Sweeney" <tim epicgames.com> writes:
 Okay, why is it that everybody thinks the C preprocessor is terrible and
 needs to be avoided?

Because it's terrible and needs to be avoided, of course!
 C++ only has it for compatability; Java and C# and D
 don't have one.  I just don't get this one.

Historically (beginning with C), macro preprocessors have served as a kludge to compensate for a lack of language power and optimizer ability. Macros were good an necessary in the C days, because you could often come pretty close to C++ style template programming if you were clever enough, using macros for casts and other tricks. You could also use them to construct optimized code (i.e. by defining the body of a loop in a macro, and unrolling the loop 100 times with the macro). With a modern language, these kludges should not be necessary. If there is any particular case where you feel you could express a program more cleanly by using macros, then I recommend looking at that as a language or optimizer flaw to be fixed, and not a need for macros. Unreal (the game) is probably a good production-code example. It's around 250,000 lines of code and uses macros for the following: 1. To expose metaclass information (i.e. class names, default constructors that a serializer can call) -- like MFC's techniques. All of this code would be unnecessary if the language supported classes as first-class objects (i.e. you can pass around a classref* which "represent" the class and exposes its static functions), static virtual functions, and static constructors. 2. To comment out large blocks of code. Would be unnecessary if /*...*/ comments could be nested. 3. To implement debug-specific code. This is actually unnecessary, a bad old habbit. We would be just as well off having a global constant debug=0 or 1, and having if(debug) {...} instead of #if debug. 4. To implement platform-specific headers. Only necessary because headers are necessary. 5. To perform template-style tricks. If the language has a great facility for type dependency (whether like C++ templates, or more general like Haskell), all of these things would be unnecessary. Even C++ templates aren't complete enough, i.e. there are no template typedefs (true type synonyms), and most production compilers have bizarre template bugs limiting what you can do. I'm 100% sure the Unreal code would be simpler and cleaner if the language supported the above and all preprocessor support were eliminated. -Tim
Aug 17 2001
next sibling parent "Brent Schartung" <bschartung home.com> writes:
All this talk reminds me (no offense to the Unreal developers!) of the Win32
API.  Basically, you have some struct xyz, and XYZ is a pointer to an xyz
struct.  Sometimes.  Or maybe it's just a UINT32.  Or a PASCAL FAR.  Who
knows?

I don't know about you guys, but I've certainly wasted a lot of time digging
through MSVC documentation trying to figure out what in the world the API's
macros map to!  Win32 in and of itself stands out--in my mind at least--as a
terrible misuse of the preprocessor, and makes me really want a language
that completely lacks macros and makes abuses like these at least
inconvenient, compared to the Right Way. <wink>

You guys who want to lecture us about how _good_ the Win32 API is, or how
great it was for its time or whatever, flame away, I guess I've baited the
hook...

 - Brent
Aug 17 2001
prev sibling next sibling parent reply "Rajiv Bhagwat" <dataflow vsnl.com> writes:
Here is one more use: Hide the complexities which you can't change..

int main(ARGS){
    if( ! ARG_PRESENT(1) )fatal("Usage: crlfd infile [outfile]");
    SepFileName in_name = ARG(1), out_name;
    if(!ARG_PRESENT(2) ){
        out_name = in_name;
        in_name.prepareBackup();    // Delete old .bak, rename this to .bak
        in_name.ChangeExt("bak");
        }
    else out_name = ARG(2);

I guess similarly the preprocessor can be used to build an efficient
'facade' for a readymade library. (Deriving a class just to redefine a few
inline functions is too much work, plus this might require casting to base
class...)

Again, consider the following use to hide ugly initilisers: (I have even
forgotton the underlaying structures:)

#define CFNAME "cards.dat"
#define LOGFILE "c:\\cust.log"
#define PRODUCT "Unknown Product"

#define DTLANG  "dtlang.h"
#define DTCUST  "dtcust.c"

char *CustLog;
char *custdbase, *makecmd, *makeparam1, *makeparam2, *makeparam3=0;
char *orgname, *newname, *product, *hdrout, *dataout;

INITABLE it[] = {
    INISTR( "Files",    "log",      CustLog,    LOGFILE , 0),
    INISTR( 0,          "custdbase",custdbase,  CUSTDBASE , 0),
    INISTR( 0,          "orgname",  orgname,    0 , 0),
    INISTR( 0,          "newname",  newname,    0 , 0),
    INISTR( 0,          "makecmd",  makecmd,    MAKECMD , 0),
    INISTR( 0,          "make1",    makeparam1, MAKEPARAM1 , 0),
    INISTR( 0,          "make2",    makeparam2, MAKEPARAM2 , 0),
    INISTR( 0,          "product",  product,    PRODUCT, 0),
    INISTR( 0,          "header",   hdrout,     DTLANG, 0),
    INISTR( 0,          "datafile", dataout,    DTCUST, 0),
    INIEND(),
    };

int main(ARGS){
    if( ! processini( CFNAME, it)){
        printf("Ini processing failed..");
        return 0;
        }
    ....


Tim Sweeney <tim epicgames.com> wrote in message
news:9lkf0r$2nh0$1 digitaldaemon.com...
 Okay, why is it that everybody thinks the C preprocessor is terrible and
 needs to be avoided?

Because it's terrible and needs to be avoided, of course!
 C++ only has it for compatability; Java and C# and D
 don't have one.  I just don't get this one.

Historically (beginning with C), macro preprocessors have served as a

 to compensate for a lack of language power and optimizer ability.  Macros
 were good an necessary in the C days, because you could often come pretty
 close to C++ style template programming if you were clever enough, using
 macros for casts and other tricks.  You could also use them to construct
 optimized code (i.e. by defining the body of a loop in a macro, and
 unrolling the loop 100 times with the macro).

 With a modern language, these kludges should not be necessary.  If there

 any particular case where you feel you could express a program more

 by using macros, then I recommend looking at that as a language or

 flaw to be fixed, and not a need for macros.

 Unreal (the game) is probably a good production-code example.  It's around
 250,000 lines of code and uses macros for the following:

 1. To expose metaclass information (i.e. class names, default constructors
 that a serializer can call) -- like MFC's techniques.  All of this code
 would be unnecessary if the language supported classes as first-class
 objects (i.e. you can pass around a classref* which "represent" the class
 and exposes its static functions), static virtual functions, and static
 constructors.

 2. To comment out large blocks of code.  Would be unnecessary if /*...*/
 comments could be nested.

 3. To implement debug-specific code.  This is actually unnecessary, a bad
 old habbit.  We would be just as well off having a global constant debug=0
 or 1, and having if(debug) {...} instead of #if debug.

 4. To implement platform-specific headers.  Only necessary because headers
 are necessary.

 5. To perform template-style tricks.  If the language has a great facility
 for type dependency (whether like C++ templates, or more general like
 Haskell), all of these things would be unnecessary.  Even C++ templates
 aren't complete enough, i.e. there are no template typedefs (true type
 synonyms), and most production compilers have bizarre template bugs

 what you can do.

 I'm 100% sure the Unreal code would be simpler and cleaner if the language
 supported the above and all preprocessor support were eliminated.

 -Tim

Aug 20 2001
parent reply weingart cs.ualberta.ca (Tobias Weingartner) writes:
In article <9lqfvs$8pm$1 digitaldaemon.com>, Rajiv Bhagwat wrote:
 Here is one more use: Hide the complexities which you can't change..
 
 int main(ARGS){
     if( ! ARG_PRESENT(1) )fatal("Usage: crlfd infile [outfile]");
     SepFileName in_name = ARG(1), out_name;
     if(!ARG_PRESENT(2) ){
         out_name = in_name;
         in_name.prepareBackup();    // Delete old .bak, rename this to .bak
         in_name.ChangeExt("bak");
         }
     else out_name = ARG(2);

This is ugly. *PLEASE* don't teach this to anybody. This *hides* necessary things, things which should be seen and understood. As an aside. I've worked at a certain company (who shall remain nameless), where macros were used in C, to provide certain OO things. Among them were macros for almost anything imaginable. The record number of characters per line (after macro expansion) was in excess of 4K worth of characters. Needless to say, these expressions were neither free of side-effects, nor particularly fast (the original intention), nor bug-free. I've had compilers silently truncate such long lines. And by pure luck, have them compile, and the program largely work (1 failure case in 10000's of test cases). That being said, macros can be good, and they can be evil. The above is the beginning of evil. If you need macros to hide that sort of inline complexity, write a new function to abstract the behaviour. Give it a reasonable name, and use it. In that way someone coming along in 5 years will be able to understand what you did, and will not have to worry about side-effects, etc. --Toby.
Aug 20 2001
parent reply Russell Bornschlegel <kaleja estarcion.com> writes:
Tobias Weingartner wrote:
 
 In article <9lqfvs$8pm$1 digitaldaemon.com>, Rajiv Bhagwat wrote:
 Here is one more use: Hide the complexities which you can't change..

 int main(ARGS){
     if( ! ARG_PRESENT(1) )fatal("Usage: crlfd infile [outfile]");
     SepFileName in_name = ARG(1), out_name;
     if(!ARG_PRESENT(2) ){
         out_name = in_name;
         in_name.prepareBackup();    // Delete old .bak, rename this to .bak
         in_name.ChangeExt("bak");
         }
     else out_name = ARG(2);

This is ugly. *PLEASE* don't teach this to anybody. This *hides* necessary things, things which should be seen and understood.

Funny, I was just about to make a case for command-line parameter access to be built into the language, to hide even the need for these macros. I don't see the above example as being any uglier than the traditional argc/argv mess. -Russell B
Aug 20 2001
next sibling parent reply "Walter" <walter digitalmars.com> writes:
Russell Bornschlegel wrote in message <3B814102.B41B493E estarcion.com>...
I don't see the above example as being any uglier than the
traditional argc/argv mess.

The D way of doing command lines: import stdio; int main(char[][] args) { for (int i = 0; i < args.length; i++) { printf("Argument %d = '%.*s'\n", i, args[i]); } } The .*s is a hack to get C printf to print D strings that don't have a terminating 0. The char[][] is an array of strings.
Aug 21 2001
parent reply Russell Bornschlegel <kaleja estarcion.com> writes:
Walter wrote:
 
 Russell Bornschlegel wrote in message <3B814102.B41B493E estarcion.com>...
I don't see the above example as being any uglier than the
traditional argc/argv mess.

The D way of doing command lines: import stdio; int main(char[][] args) { for (int i = 0; i < args.length; i++) { printf("Argument %d = '%.*s'\n", i, args[i]); } } The .*s is a hack to get C printf to print D strings that don't have a terminating 0. The char[][] is an array of strings.

Hm, I don't know what you have in mind for the internal representation of a string, but I'd recommend allocating one more character than the length of the string and keeping it zero-terminated, even if you're tracking the length separately -- it could save a lot of trouble in compatibility. Is it out of the question to support an automatic conversion from D strings to zero-terminated (w)char* in parameter lists of functions declared with C calling conventions? -RB
Aug 21 2001
parent "Walter" <walter digitalmars.com> writes:
Russell Bornschlegel wrote in message <3B828FB7.9821FE49 estarcion.com>...
Walter wrote:
 Russell Bornschlegel wrote in message


I don't see the above example as being any uglier than the
traditional argc/argv mess.

The D way of doing command lines: import stdio; int main(char[][] args) { for (int i = 0; i < args.length; i++) { printf("Argument %d = '%.*s'\n", i, args[i]); } } The .*s is a hack to get C printf to print D strings that don't have a terminating 0. The char[][] is an array of strings.

Hm, I don't know what you have in mind for the internal representation of a string, but I'd recommend allocating one more character than the length of the string and keeping it zero-terminated, even if you're tracking the length separately -- it could save a lot of trouble in compatibility. Is it out of the question to support an automatic conversion from D strings to zero-terminated (w)char* in parameter lists of functions declared with C calling conventions?

Arrays are implemented as: int length; void *data; There is a (char*) cast supported. I toyed with the idea of always making them 0 terminated anyway, but it would up requiring lots of array copying.
Aug 21 2001
prev sibling parent reply "Rajiv Bhagwat" <dataflow vsnl.com> writes:
Russell Bornschlegel <kaleja estarcion.com> wrote in message
news:3B814102.B41B493E estarcion.com...
 Tobias Weingartner wrote:
 In article <9lqfvs$8pm$1 digitaldaemon.com>, Rajiv Bhagwat wrote:
 Here is one more use: Hide the complexities which you can't change..

 int main(ARGS){
     if( ! ARG_PRESENT(1) )fatal("Usage: crlfd infile [outfile]");
     SepFileName in_name = ARG(1), out_name;
     if(!ARG_PRESENT(2) ){
         out_name = in_name;
         in_name.prepareBackup();    // Delete old .bak, rename this to



         in_name.ChangeExt("bak");
         }
     else out_name = ARG(2);

This is ugly. *PLEASE* don't teach this to anybody. This *hides* necessary things, things which should be seen and understood.


It certainly simplifies the use. The capitalisation clearly marks the use of macros. I have used getarg(), even classes to parse the command lines and ultimately found that for simple cases, the use of these macros is best. (BTW, I don't recollect from where I have picked them). What is wrong about hiding the complexities? The whole of OO paradigm is based on it. It is not necessary to fret about every implementation detail - I just need to know if the user has supplied the 2nd argument or not. Using a class or a function for a simple filter would be overkill.
 Funny, I was just about to make a case for command-line parameter
 access to be built into the language, to hide even the need for
 these macros.

 I don't see the above example as being any uglier than the
 traditional argc/argv mess.

 -Russell B

Also, no one has commented about the use of macros to init data structures as presented in the second part. Maybe the use is not common enough. Oh, I think MFC does something similar all the time to declare the message map data structures. -- Rajiv
Aug 21 2001
parent "Walter" <walter digitalmars.com> writes:
Rajiv Bhagwat wrote in message <9lte82$2297$1 digitaldaemon.com>...
Also, no one has commented about the use of macros to init data structures
as presented in the second part. Maybe the use is not common enough. Oh, I
think MFC does something similar all the time to declare the message map
data structures.

I use macros to initialize data structures in C all the time. That's why D has specifiable defaults for member initializers, and named initializers for structs.
Aug 21 2001
prev sibling next sibling parent reply "Richard Krehbiel" <rich kastle.com> writes:
(Interesting to see you in here, Tim!)

"Tim Sweeney" <tim epicgames.com> wrote in message
news:9lkf0r$2nh0$1 digitaldaemon.com...
 Okay, why is it that everybody thinks the C preprocessor is terrible and
 needs to be avoided?

Because it's terrible and needs to be avoided, of course!

:-)
 C++ only has it for compatability; Java and C# and D
 don't have one.  I just don't get this one.

Historically (beginning with C), macro preprocessors have served as a

 to compensate for a lack of language power and optimizer ability.  Macros
 were good an necessary in the C days, because you could often come pretty
 close to C++ style template programming if you were clever enough, using
 macros for casts and other tricks.  You could also use them to construct
 optimized code (i.e. by defining the body of a loop in a macro, and
 unrolling the loop 100 times with the macro).

 With a modern language, these kludges should not be necessary.  If there

 any particular case where you feel you could express a program more

 by using macros, then I recommend looking at that as a language or

 flaw to be fixed, and not a need for macros.

Here's one: compile time macros as a substitute for carrying a freight-train-load of object type information into the executable. I was just reading about C#'s printf function, which works because everything is an object carrying it's type information around at run time. It doesn't need format specifiers. If this trend continues, I see C remaining as dominant an implementation language as it is today, because it's the only popular language that concentrates on run-tim efficiency.
 Unreal (the game) is probably a good production-code example.  It's around
 250,000 lines of code and uses macros for the following:

 1. To expose metaclass information (i.e. class names, default constructors
 that a serializer can call) -- like MFC's techniques.  All of this code
 would be unnecessary if the language supported classes as first-class
 objects (i.e. you can pass around a classref* which "represent" the class
 and exposes its static functions), static virtual functions, and static
 constructors.

Java.
 2. To comment out large blocks of code.  Would be unnecessary if /*...*/
 comments could be nested.

..or if your editor had a function that would insert or remove // comment markers over a selected range of text (emacs can do this). Still more ways to alleviate language issues...
 3. To implement debug-specific code.  This is actually unnecessary, a bad
 old habbit.  We would be just as well off having a global constant debug=0
 or 1, and having if(debug) {...} instead of #if debug.

What about: class NastyClass { #if DEBUG int tracehistory[512]; #endif
 4. To implement platform-specific headers.  Only necessary because headers
 are necessary.

Yeah, well, I agree some things shouldn't be preprocessor jobs; #include'd common definitions, #define'd types and constants are among them.
 5. To perform template-style tricks.  If the language has a great facility
 for type dependency (whether like C++ templates, or more general like
 Haskell),

I'll have to go read up on Haskell.
 all of these things would be unnecessary.  Even C++ templates
 aren't complete enough, i.e. there are no template typedefs (true type
 synonyms), and most production compilers have bizarre template bugs

 what you can do.

 I'm 100% sure the Unreal code would be simpler and cleaner if the language
 supported the above and all preprocessor support were eliminated.

My main issue is that the macro language should give compile-time power to the programmer, with access to the type system and symbol tables. So code can be generated depending on variable types, on aggregate membership, etc. -- Richard Krehbiel, Arlington, VA, USA rich kastle.com (work) or krehbiel3 home.com (personal)
Aug 20 2001
parent Russell Bornschlegel <kaleja estarcion.com> writes:
Richard Krehbiel wrote:
 What about:
 
 class NastyClass
 {
 #if DEBUG
     int tracehistory[512];
 #endif

FWIW, already addressed in the existing D spec: class NastyClass { debug { int tracehistory[512]; } ... -Russell B
Aug 20 2001
prev sibling next sibling parent reply Charles Hixson <charleshixsn earthlink.net> writes:
Tim Sweeney wrote:
...
 
 2. To comment out large blocks of code.  Would be unnecessary if /*...*/
 comments could be nested.
 
...
 
 -Tim
 

Then it might be a good idea. Otherwise the tag deletions could become quite confusing if any mistakes were made. consider the possibility of: /*!* ... /*&* ... *&*/ ... *!*/ etc. however. Practically any character should be useable in the "flag" position. And one letter is probably sufficient, though if it weren't excessive I suppose one could extend it to be any run of non-whitespace not including an asterisk. That would let one say, e.g.: /*NoFileFound* ... /*FileOpenFailed* ... /*IOError* ... *IOError*/ ... *FileOpenFailed*/ ... *NoFileFound*/ But use of this would require specialized tools. IDEA!! Since the program text can already contain embedded html (XML ??) code anyway, what about using html/XML comment tags to comment out code? Or, if XML is used, and it is desired that commented out code be visible, then one could specify a labelled XML tag for the comment boundaries. It's a bit more complex than the simple scheme of above, but it would allow more or less standard tools to do the processing.
Aug 20 2001
parent reply Russell Bornschlegel <kaleja estarcion.com> writes:
Charles Hixson wrote:
 
 Tim Sweeney wrote:
...

 2. To comment out large blocks of code.  Would be unnecessary if /*...*/
 comments could be nested.

...

 -Tim

Then it might be a good idea. Otherwise the tag deletions could become quite confusing if any mistakes were made. consider the possibility of: /*!* ... /*&* ... *&*/ ... *!*/

Eeek! I'm gonna say it one more time: the One True Way to comment out large blocks of code is with // at the beginning of the line. You can even tag and nest these: //none of this works// codecode(); //none of this works// morecodecode(); //none of this works////this doesn't work yet// stillmorecodecode(); //none of this works////this doesn't work yet// blah(); //none of this works////this doesn't work yet////was:// otherkindofblah(); //none of this works////this doesn't work yet// finish(); In practice, I use shorter tags than this; typically things like: //ref// code or declarations from some other part of the program, //ref// kept around for quick reference //obs// obsolete code kept for reference or rollback //RAB// my initials; "I have a truly marvelous reason for commenting //RAB// this out, which this margin is too narrow to contain." //no// any other random comment-out reason // very temporary comment-outs A good configurable editor should let you make this sort of comment- out easy to do; a syntax-highlighting editor will make it clear that this is all commented out, which most don't do with an #if 0 block. If your editor (or hard copy) isn't syntax-highlighted, this is also clearer than commenting out a large block with /* ... */. -Russell B
Aug 20 2001
parent reply "Sean L. Palmer" <spalmer iname.com> writes:
"Russell Bornschlegel" <kaleja estarcion.com> wrote in message
news:3B81647C.25270C5A estarcion.com...
 Eeek!

 I'm gonna say it one more time: the One True Way to comment out large
 blocks of code is with // at the beginning of the line. You can even
 tag and nest these:
...
 If your editor (or hard copy) isn't syntax-highlighted, this is also
 clearer than commenting out a large block with /* ... */.

 -Russell B

If your editor supports syntax highlighting, there isn't a problem with /* */ style comments. Sean
Oct 26 2001
parent Axel Kittenberger <axel dtone.org> writes:
 If your editor supports syntax highlighting, there isn't a problem with /*
 */ style comments.

first /* */ comments are not nestable in normal C, are very bad attribute. If you make them nestable it's still not easy to see where a comment really ends. second I've no idea why the original C authors thought that /* is an available token sequence, whats with devided by content of? a = b/*c; // that should be a valid operation. - Axel -- |D) http://www.dtone.org
Oct 28 2001
prev sibling parent "Sean L. Palmer" <spalmer iname.com> writes:
"Tim Sweeney" <tim epicgames.com> wrote in message
news:9lkf0r$2nh0$1 digitaldaemon.com...

 2. To comment out large blocks of code.  Would be unnecessary if /*...*/
 comments could be nested.

Yeah... why on earth did they ever decide that /* */ comments shouldn't nest? Since we may end up having to block comment out huge chunks of code since conditional compilation will require grammatically correct code, if your code isn't (yet) grammatically correct, you can't even get rid of it. If it contains any C block comments, you can't even comment it out properly. So I'd have to vote for nesting of C block comments. Sean
Oct 26 2001
prev sibling next sibling parent Roland <rv ronetech.com> writes:
Richard Krehbiel a écrit :

 I personally have wished for *more* macro processing power.

I agree. The most powerfull macros i know are MASM assembly langage macro. I used it two much in my young time but it is very very powerfull. well i can understand it is not really what walter have in mind creating a simpler and safer langage.. Congratulations Roland
Aug 23 2001
prev sibling next sibling parent "Ben Cohen" <bc skygate.co.uk> writes:
In article <9lgk0b$243j$1 digitaldaemon.com>, "Richard Krehbiel"
<rich kastle.com> wrote:

 Okay, why is it that everybody thinks the C preprocessor is terrible and
 needs to be avoided?  C++ only has it for compatability; Java and C# and
 D don't have one.  I just don't get this one.
 
 I personally have wished for *more* macro processing power.
 
 Not for typedefs.  Not for constant definitions.  Not for #include files
 or guards.  For *macros*.

Here is an example of a use of macros which I don't think has been mentioned here or in the spec. (If it did, I missed it, anyway.) Suppose you want a macro which uses a variable local to the function in which you call it. You can do this in D by simply defining a function and passing the variable as a parameter (as suggested in the spec). E.g.: int X(int i) { return i + i / 3; } int my_function(int v) { return X(v) * X(v); } For some reason you don't want to pass the parameter each time -- perhaps because you want to use several parameters and the macro will be called lots of times. This can be solved by using nested functions. (I'm not sure whether D supports these.) E.g.: void my_function(int v, int w) { int X() {return v + w/3; } return X() * X(); } Now suppose you have several functions which each want to call the nested function. You could redefine the nested function each time, but this would duplicate effort and might make errors more likely. Perhaps there should be a macro construct, similar to that of functions, which can only be called within a function (and where the variable names used in the macro must be in scope wherever the macro is used). E.g.: int w = 24; macro int X() {return v + w/3;} int my_function(int v) { return X() * X(); } int another_function() { int v; return X(); } int yuk() { return X(); /* This isn't allowed because there is no v in scope.*/ } This is a reasonably common use of macros, and one of their powers. Of course, it is arguably a Bad Thing because it could be used unwisely, but it would also be handy. Do you think this would be useful in the language? If not, then the example should probably be added to the spec with an explanation. What about if the macro has side-effects, e.g.: macro int X() {v++; return v + w/3;}
Sep 28 2001
prev sibling parent reply "Ben Cohen" <bc skygate.co.uk> writes:
In article <9lgk0b$243j$1 digitaldaemon.com>, "Richard Krehbiel"
<rich kastle.com> wrote:

 Okay, why is it that everybody thinks the C preprocessor is terrible and
 needs to be avoided?  C++ only has it for compatability; Java and C# and
 D don't have one.  I just don't get this one.
 
 I personally have wished for *more* macro processing power.
 
 Not for typedefs.  Not for constant definitions.  Not for #include files
 or guards.  For *macros*.

Another thing: This is what the spec says about inlining macros/lightweight functions: 8. Macros as lightweight inline functions: #define X(i) ((i) = (i) / 3) In D: int X(int i) { return i = i / 3; } The compiler optimizer will inline it; no efficiency is lost. What happens if the macro is in another package or module? Say X() is defined in module A. I write module B which includes/imports module A; a function F() in module B calls X(). If you do this in C, the function X() will be expanded and hence inlined (from the header file) in the function F(). What happens in D?
Sep 28 2001
parent "Walter" <walter digitalmars.com> writes:
It still gets inlined. The function body gets imported along with its
declaration. -Walter

Ben Cohen wrote in message <9p1eei$1k5t$1 digitaldaemon.com>...
In article <9lgk0b$243j$1 digitaldaemon.com>, "Richard Krehbiel"
<rich kastle.com> wrote:

 Okay, why is it that everybody thinks the C preprocessor is terrible and
 needs to be avoided?  C++ only has it for compatability; Java and C# and
 D don't have one.  I just don't get this one.

 I personally have wished for *more* macro processing power.

 Not for typedefs.  Not for constant definitions.  Not for #include files
 or guards.  For *macros*.

Another thing: This is what the spec says about inlining macros/lightweight functions: 8. Macros as lightweight inline functions: #define X(i) ((i) = (i) / 3) In D: int X(int i) { return i = i / 3; } The compiler optimizer will inline it; no efficiency is lost. What happens if the macro is in another package or module? Say X() is defined in module A. I write module B which includes/imports module A; a function F() in module B calls X(). If you do this in C, the function X() will be expanded and hence inlined (from the header file) in the function F(). What happens in D?

Sep 28 2001