dld@F.GP.CS.CMU.EDU (David Detlefs) (07/26/89)
I would like to make an argument that #pragma once is unnecessary, and perhaps even dangerous. First, calling "#pragma once" a "pragma" conveys the impression that it affects only efficiency, never correctness. This is not true; if foo.h contains ifdefs that depend on the state of preprocessor variables, separate includes might produce different results. A user could put a #pragma once in such a foo.h, not realizing that it would affect the semantics of his program. (Note that when I say "conveys the impression" I do not mean to say that it is written in the Ansi C standard that pragmas shall never affect the meaning of an Ansi C program, rather that the term "pragma" has been used often in other contexts with that meaning, so that programmers might expect that to be true.) An alternative, gleaned from discussion on various netnews groups: why is "#pragma once" preferable to the #ifndef convention? The standard argument is that if we use #ifndef's, we still have to open and process a file on inclusions after the first, to find out that it's body is #ifndef'd. Instead, we could modify cpp to keep a table of the files it has processed. When a file is read for the first time, cpp checks to see if it is of the form foo.h: -------------------------------------------------- <comments and whitespace>* #ifndef FOO_H <anything>* #endif <comments and whitespace>* -------------------------------------------------- If so, then it is associated in the table with the variable FOO_H. Each included file name is looked up in this table before the file is opened. If found, we check the the current value of the associated variable; if it is defined, we skip the include without opening and processing the file. This seems like it should be just as efficient as "#pragma once," without changing any semantics, and preserving compatibility with existing code. I stand of course eager to hear reasons I have overlooked that make "#pragma once" preferable. NOTE: this is not my idea; I just don't know who to credit it to. If the person who made the post that I read it in (perhaps in this newsgroup?) will send me mail, I will credit him/her in any subsequent discussion, because I think this is a great idea. -- Dave Detlefs Any correlation between my employer's opinion Carnegie-Mellon CS and my own is statistical rather than causal, dld@cs.cmu.edu except in those cases where I have helped to form my employer's opinion. (Null disclaimer.)
grunwald@flute.cs.uiuc.edu (Dirk Grunwald) (07/26/89)
hacking cpp to recognize #ifndef sounds like even more of a problem; people have different conventions on where they place the #ifndef, the #define and so on. Rather than play tricks like this, I think that having #requires and #provides would be a lot cleaner, albeit less portable. One could have syntax akin to include, e.g: bar.c: #require <foo.h> ... foo.h: #provide <foo.h> where the #provides is really redundant. You could also play more elaborate games with such a mechanism, e.g., allow arbitrary strings to be required and provided: bar.c: #require "valid machine description" which would be a cleaner way of barfing on bad configurations than; #ifndef VALID_MACHINE_DESCRIPTION You don't have a valid description! #endif Since gnu CPP can be easily distributed, portability isn't much of an issue -- if someone uses your library, tell them to also use gnu CPP. -- Dirk Grunwald -- Univ. of Illinois (grunwald@flute.cs.uiuc.edu)
dld@F.GP.CS.CMU.EDU (David Detlefs) (07/26/89)
In response to my suggestion about modify cpp to get the efficiency of "#pragma once" without the change in semantics, Dirk Grunwald writes: >hacking cpp to recognize #ifndef sounds like even more of a problem; >people have different conventions on where they place the #ifndef, >the #define and so on. I don't see the problem. cpp can certainly distinguish between comments and actual program text. If you write a foo.h file of the form -------------------------------------------------- <comments and whitespace>* #ifndef FOO_H <anything at all -- note that it doesn't matter where, or even *if*, the #define FOO_H occurs> #endif <comments and whitespace>* -------------------------------------------------- then cpp is certainly safe in disregarding subsequent includes of foo.h that occur while FOO_H is defined. If you have anything other than a comment or whitespace before the #ifndef, or after the corresponding #endif, then cpp might not be safe in ignoring subsequent includes. There is certainly no difficulty in recognizing file of this form, and I believe that pretty much all files using the #ifndef convention fit it. As for #requires and #provides, I think we have to recognize that we're going to exist for a long time in a sea of previously existing code, and we shouldn't change a perfectly good mechanism without good reason. I fail to see adequate advantages with #requires and #provides (though this does not of course imply thay such advantages do not exist.) -- Dave Detlefs Any correlation between my employer's opinion Carnegie-Mellon CS and my own is statistical rather than causal, dld@cs.cmu.edu except in those cases where I have helped to form my employer's opinion. (Null disclaimer.)
dld@F.GP.CS.CMU.EDU (David Detlefs) (07/28/89)
Because I really admire whoever thought of this idea, I'll continue to try to explain it better: John Plocher (plocher@sun.Eng.Sun.Com?) writes >But what if I don't write it in the magic form you describe? Then your >cute trick breaks. > >You seem to use FOO_H as the token used for the #ifndef - I use _FOO_H_. >curses.h may well use #ifndef mvwputc, and serialio.h may use #ifndef IOGETBAUDRATE I'm sorry: in my example, I intended FOO_H to stand for any preprocessor variable name at all, not literally "FOO_H." I thought this would be clear. The first time through, you associate the variable name with the file name; on subsequent inclusios, you see if the variable is defined before opening the file. >then how can you distinguish between this and something that happens to have a #ifndef >at the beginning which is NOT intended to be used as a Only One Inclusion flag? The point is that the intention doesn't matter; if a file is of this form, then it only needs to be included once (if the #ifndef variable is defined at the time of later inclusions): subsequent inclusions will result in no non-comment text. Which is exactly why #ifndef is used this way. You are right that "#pragma once" says the same thing more succintly; my objections are (again) 1) that a "pragma" is usually taken to mean something that affects performance and not semantics, while pragma once may definitely affect semantics, and 2) that in the absence of really good reasons such as performance, which my proposal solves, we shouldn't arbitrarily abandon existing mechanisms. -- Dave Detlefs Any correlation between my employer's opinion Carnegie-Mellon CS and my own is statistical rather than causal, dld@cs.cmu.edu except in those cases where I have helped to form my employer's opinion. (Null disclaimer.)