jas@rtech.UUCP (04/30/87)
Henry Spencer (utzoo!henry) notes in passing: > [Function prototypes] have other problems, and I'm not sure they were a > good idea.... This got me curious: what are the problems with function prototypes? The only one I can think of is that an implicit coercion will not be done when there is no function prototype in scope. I would resolve that by requiring compilers to emit a fairly strongly worded warning whenever a program called a function without a prototype in scope. (If we were designing C from scratch at this point, I'd outlaw it altogether; but we're not.) I see nothing wrong with implicit coercion per se, as long as the coercion is well defined. Implicit coercion of one pointer type to another should minimally elicit a warning, like pcc's when doing this implicit coercion on assignment. Are there additional arguments against function prototypes? If so, what are they? -- Jim Shankland ..!ihnp4!cpsc6a!\ rtech!jas ..!ucbvax!mtxinu!/
olson@endor.harvard.edu (Eric Olson) (05/01/87)
In article <796@rtech.UUCP> jas@rtech.UUCP (Jim Shankland) writes: > >Henry Spencer (utzoo!henry) notes in passing: > >> [Function prototypes] have other problems, and I'm not sure they were a >> good idea.... > >This got me curious: what are the problems with function prototypes? ... >Are there additional arguments against function prototypes? If so, >what are they? I have a big complaint about function prototypes. I would very much like all the functions in my code to have prototypes accessible from any other module, essentially so I get lint-like argument checking during compile. (I am using LightSpeed C on the Macintosh-- don't yell at me, but it has no lint. It does have an option to require prototypes). So I can prototype everything in a header file included in all my modules, but then adding a module forces a complete re-make. Am I missing something? Is there a sane way to use prototypes (I already use them on libraries, since they rarely change). Any ideas will be appreciated. -Eric
olson@endor.harvard.edu (Eric Olson) (05/01/87)
In article <1821@husc6.UUCP> olson@endor.UUCP (Eric Olson) writes: >So I can prototype >everything in a header file included in all my modules, but then adding a >module forces a complete re-make. I meant to say that adding a function to a module forces a complete re-make of all modules. Sorry. -Eric
socha@drivax.UUCP (Henri J. Socha (x6251)) (05/02/87)
In article <796@rtech.UUCP> jas@rtech.UUCP (Jim Shankland) writes: >Henry Spencer (utzoo!henry) notes in passing: >> [Function prototypes] have other problems, and I'm not sure they were a >> good idea.... >This got me curious: what are the problems with function prototypes? >The only one I can think of is that an implicit coercion will not be >done when there is no function prototype in scope. I would resolve >that by requiring compilers to emit a fairly strongly worded warning >whenever a program called a function without a prototype in scope. >Are there additional arguments against function prototypes? If so, >what are they? Well, just to back up (give an example) of what you said: The Macintosh Lightspeed C (development environment!) from Think Technologies has an option called "Function Prototypes Required". It can be set as a default that is always enforced (unless explicitly disabled). They also have a non-standardism (which I feel is a bug) in that when a function is defined, the prototype form CAN NOT be used. Therefore if this option is enabled, you must say: int main(int argc, char *argv[]); int main(argc, argv) /* can't use prototype form here! (bug) */ int argc; char * argv[]; { ..... } Or you will get a compile error that the prototype for main was not given. YES, (before you flame me) a prototype declaration at function definition should be allowed but (and finally this is the point): I WOULD RATHER BE FORCED TO DO UNNECESSARY DECLARATIONS THAN NOT KNOW IF ALL FUNCTIONS AND CALLS HAVE BEEN CORRECTLY CODED. I have been burned more than once by the missing declaration of an external LONG returning function or a mis-typed call argument. How about it compiler writers? Will you also install a switch that DEMANDS prototype definitions for all functions so that at least a minimum of type checking can be performed? Disclaimer: This is not (necessarily) the view of my employer. -- -- UUCP:...!amdahl!drivax!socha WAT Iron'75 "Everything should be made as simple as possible but not simpler." A. Einstein
hjg@bunker.UUCP (Harry J. Gross) (05/04/87)
In article <1821@husc6.UUCP> olson@endor.UUCP (Eric Olson) writes: >I have a big complaint about function prototypes. I would very much like >all the functions in my code to have prototypes accessible from any other >module, essentially so I get lint-like argument checking during compile. >(I am using LightSpeed C on the Macintosh-- don't yell at me, but it has no >lint. It does have an option to require prototypes). So I can prototype >everything in a header file included in all my modules, but then adding a >module forces a complete re-make. > >Am I missing something? Is there a sane way to use prototypes (I already >use them on libraries, since they rarely change). > >Any ideas will be appreciated. It's kind of kludgey (sp?), but if you _know_ that the only change to the header was the addition of a prototype that is currently unused in any other module, you could *touch* each of the other modules (.c and .obj). Then make should leave them alone. I have sometimes been forced to do this when I have added a (not currently used, but will be soon) #define to a header file that would otherwise cause 30 modules to recompile. It's a terrible hack, I know, but it beats waiting xx minutes for a completely unnecessary recompile. (Of course, if you have no easy way of updating the modification time on the file, all bets are off - Oh well :-). If there is a better way, I don't know what it is, BUT I SURE WOULD LIKE TO!!! Harry Gross ..!bunker!hjg
tps@sdchem.UUCP (Tom Stockfisch) (05/05/87)
In article <2023@bunker.UUCP> hjg@bunker.UUCP (Harry J. Gross) writes: >In article <1821@husc6.UUCP> olson@endor.UUCP (Eric Olson) writes: >>.... So I can prototype >>everything in a header file included in all my modules, but then adding a >>module forces a complete re-make. > It's kind of kludgey (sp?), but if you _know_ that the only change to >the header was the addition of a prototype that is currently unused in any other >module, you could *touch* each of the other modules (.c and .obj). Then make >should leave them alone. > If there is a better way, I don't know what it is, BUT I SURE WOULD >LIKE TO!!! The way I handle it is to have my declaration/prototype header file contain *only* declarations/prototypes, and then I DON'T MENTION IT IN THE MAKEFILE. I can't think of a single case when this has caused a typing problem. The way you mess up in this case is to change a function's type in its module and forget to change it in the header file. Mentioning the header file in the "Makefile" doesn't catch this error. Header files with defines and macros are a different story and probably should be listed in dependency rules. I think it is a very bad mistake ever to "touch" source files. You are perverting information which you will probably need in the future even if you can't think why now. || Tom Stockfisch, UCSD Chemistry tps%chem@sdcsvax.ucsd.edu or sdcsvax!sdchem!tps
steele@unc.UUCP (05/05/87)
Eric Olson (olson@endor.UUCP) writes: [about putting all the prototypes in a single header file] }.... So I can prototype }everything in a header file included in all my modules, but then adding a }module forces a complete re-make. Harry J. Gross (hjg@bunker.UUCP) writes: ) ) It's kind of kludgey (sp?), but if you _know_ that the only change to )the header was the addition of a prototype that is currently unused in any )other module, you could *touch* each of the other modules (.c and .obj). )Then make should leave them alone. ) If there is a better way, I don't know what it is, BUT I SURE WOULD )LIKE TO!!! Tom Stockfisch tps@sdchemf.UUCP writes: > >The way I handle it is to have my declaration/prototype header file contain >*only* declarations/prototypes, and then I DON'T MENTION IT IN THE MAKEFILE. >I can't think of a single case when this has caused a typing problem. The way I handle it, when I'm being modern and verbose, is to treat each set of functions/globals that implements and abstract type or object Foo as a module 'Foo' contained in two files, 'foo.c' and 'foo.h', which roughly parallel the public and private parts of modules in Modula-2 and Ada (I speak through my hat, not knowing either). Any module that uses a foo then #includes "foo.h". Your price is more files, and more #included files, and maybe more compilation time to #include them all (This overhead will probable be negligible on a real UN*X machine. On a Mac it's expensive to open files, but a 96-128K cache speeds up recompilation enough that I don't worry about it under Lightspeed). Your payoffs are 1) An automatic dependency diagram (either a short shellscript to collate #include-d files or option-click in the title bar to get a list of modules that a given file uses). 2) You only force recompilation of a file iff the interface to a module it uses changes. Their is no easy way to do this automatically if the granularity of header files is any larger than that of code files. >The way you mess up in this case is to change a function's type in its >module and forget to change it in the header file. Mentioning the header file >in the "Makefile" doesn't catch this error. Including a module's header in its code file solves that. The only problems I've run into are in the management of modules large enough to be composes of submodules. ------------------------------------------------------------------------------ Oliver Steele ...!{decfax,ihnp4}!mcnc!unc!steele steele%unc@csnet-relay.csnet "Education and religion are two things not regulated by supply and demand. The less of either the people have, the less they want." - Charlotte Observer, 1897
grodberg@kodak.UUCP (05/06/87)
In article <731@sdchema.sdchem.UUCP> tps@sdchemf.UUCP (Tom Stockfisch) writes: >The way I handle (keeping function prototypes up to date without having make do complete recompiles) is to have my declaration/prototype header file contain >*only* declarations/prototypes, and then I DON'T MENTION IT IN THE MAKEFILE. >I can't think of a single case when this has caused a typing problem. The >way you mess up in this case is to change a function's type in its module >and forget to change it in the header file. Mentioning the header file in >the "Makefile" doesn't catch this error. There is an other way you mess up using Tom's method, which is a serious drawback: if you change a function's type and don't update *ALL* of the files that have calls to that function, you may never here the compiler complaining that you are sending in the wrong type, since those modules won't be recompiled. For example, if you have function foo that calls function bar, and change bar's type from float to double, you won't hear about the fact that you forgot to change foo's function call until you have some other reason to recompile foo. -- Jeremy Grodberg Usenet: ...rochester!kodak!grodberg or kodak!grodberg@cs.rochester.edu Arpa: grodberg@kodak or kodak!grodberg@rochester
hjg@bunker.UUCP (Harry J. Gross) (05/06/87)
In article <731@sdchema.sdchem.UUCP> tps@sdchemf.UUCP (Tom Stockfisch) writes: >In article <2023@bunker.UUCP> hjg@bunker.UUCP (Harry J. Gross) writes: >> It's kind of kludgey (sp?), but [...] >>[...], you could *touch* each of the other modules [much deleted] >I think it is a very bad mistake ever to "touch" source files. You are >perverting information which you will probably need in the future even if >you can't think why now. Actually, I agree with you completely. (After all, I did say that it was a kludge :-) I think your solution is excellent. I don't generally like to leave header files out of Make files, but in this case, it is an excellent solution. Glad I thought of it :-) :-) :-) -- ..!bunker\ | This space reserved for a ..!phri\ \ | particularly funny quotation ..!nyit!gor!hjg (Harry Gross) | ..!helm/ | All donations cheerfully examined
stuart@bms-at.UUCP (Stuart D. Gathman) (05/06/87)
In article <1821@husc6.UUCP>, olson@endor.harvard.edu (Eric Olson) writes: > everything in a header file included in all my modules, but then adding a > module forces a complete re-make. I assume this is because all your modules depend on the header file. In that case, do 'make -t' after adding a module to the header file. -- Stuart D. Gathman <..!seismo!dgis!bms-at!stuartSI
tps@sdchem.UUCP (05/07/87)
In article <839@kodak.UUCP> grodberg@kodak.UUCP (Jeremy Grodberg) writes: >In article <731@sdchema.sdchem.UUCP> tps@sdchemf.UUCP (Tom Stockfisch) writes: >>The way I handle (keeping function prototypes up to date without having make >do complete recompiles) is to have my declaration/prototype header file contain >>*only* declarations/prototypes, and then I DON'T MENTION IT IN THE MAKEFILE. > There is an other way you mess up using Tom's method, which is a serious >drawback.... For example, if you have function foo that calls function bar, and >change bar's type from float to double, you won't hear about the fact that >you forgot to change foo's function call until you have some other reason >to recompile foo. It is very unlikely that you would not change foo() if you changed bar(). For instance, if you change bar() from float to double, you will probably change foo to double as well. If you don't change anything in foo.c, then you will have to remember to 'rm foo.o' before the re-make. When I make a bunch of type changes (which occurs very infrequently) I sometimes 'rm *.o' just to be safe. I don't agree that my method has a "serious drawback" when I have used it for several years in working with makefiles, I rarely waste time doing recompiling all source files, and I have to spend very little time thinking about when an object file will become truly out of date. || Tom Stockfisch, UCSD Chemistry tps%chem@sdcsvax.ucsd.edu or sdcsvax!sdchem!tps
eager@amd.UUCP (mike eager) (05/07/87)
Summary:Too many cross-module connections In article <1822@husc6.UUCP> olson@endor.UUCP (Eric Olson) writes: >>So I can prototype >>everything in a header file included in all my modules, but then adding a >>module forces a complete re-make. Glen Myers' book __Reliable_Software_through_Composite_Design__ gives a list of the features of good programs. He describes several forms of coupling between programs. By having a reference to every function included in every file, you have coupled all of the files together in a low quality fashion. The result is the re-make. The solution is to reference only the functions which are actually used in each file. This will keep unrelated things from interacting. You may need more include files. You may find that the programs document themselves a wee bit better, since they now mention only things which??thes't be
henry@utzoo.UUCP (Henry Spencer) (05/11/87)
> > [Function prototypes] have other problems, and I'm not sure they were a > > good idea.... > > This got me curious: what are the problems with function prototypes? The three that immediately come to mind are: 1. Considerable disaster potential when moving code between environments which differ in how they do prototyping. Remember that many (most?) prototypes will be picked up with header files, not explicitly typed by the programmer. What happens when that code gets moved to a system with a non-prototyping compiler? (Such compilers won't go away overnight.) Less drastic and still more subtle, what happens when the code gets moved to a system which doesn't declare quite the same set of functions in the prototypes in its headers? (Don't tell me this shouldn't happen, it will.) 2. Some of the coercions provided by function prototypes are distinctly unsafe, e.g. the shortening ones. Again, prototypes from header files are a nice way to have this happen without the programmer noticing it -- and it's not clear that even lint will complain. 3. They are a significant change to C, implementation experience with them is distinctly limited, and they aren't vitally needed. There is room for debate about whether X3J11 violated the "standardize the existing language, not a new one" rule, and function prototypes are the most conspicuous evidence for violation. -- "The average nutritional value Henry Spencer @ U of Toronto Zoology of promises is roughly zero." {allegra,ihnp4,decvax,pyramid}!utzoo!henry
brett@wjvax.UUCP (Brett Galloway) (05/11/87)
In article <2023@bunker.UUCP> hjg@bunker.UUCP (Harry J. Gross) writes: > It's kind of kludgey (sp?), but if you _know_ that the only change to >the header was the addition of a prototype that is currently unused in any other >module, you could *touch* each of the other modules (.c and .obj). Then make >should leave them alone. I have sometimes been forced to do this when I have >added a (not currently used, but will be soon) #define to a header file that >would otherwise cause 30 modules to recompile. A drawback of this method is that you can inadvertently touch something that should have been updated because of some *other* change (an error that I have made). I wrote a short program called 'twiddle` to store the modify date of the argument, exec /usr/ucb/vi on it, then restore the modify date after vi exits. Thus, when I want to make an inocuous change to a header file, I just 'twiddle` it. I find that this saves much time *and* much grief. -- ------------- Brett Galloway {pesnta,twg,ios,qubix,turtlevax,tymix,vecpyr,certes,isi}!wjvax!brett
thomas%spline.uucp@utah-gr.UUCP (Spencer W. Thomas) (05/13/87)
Henry Spencer claims that use of function prototypes is dangerous because of what may happen if a function prototype is missing in one environment, but present in another. Lightspeed C for the Macintosh has an option that causes it to require function prototypes for all external functions. Seems to me that use of this option would prevent the type of disaster envisioned by Henry. =Spencer ({ihnp4,decvax}!utah-cs!thomas, thomas@cs.utah.edu)
henry@utzoo.UUCP (Henry Spencer) (05/20/87)
> Henry Spencer claims that use of function prototypes is dangerous > because of what may happen if a function prototype is missing in one > environment, but present in another. Lightspeed C for the Macintosh > has an option that causes it to require function prototypes for all > external functions. Seems to me that use of this option would prevent > the type of disaster envisioned by Henry. Unfortunately, it's not as helpful as one would like: the dangerous problems are the ones where the prototype for xxx is being picked up from a header file, and you assume that the header file is the same in both environments, and it's not. If *both* environments have such a compiler option, fine; the point is that successful compilation with such an option in one environment tells you nothing about what's going to happen in another. -- "The average nutritional value Henry Spencer @ U of Toronto Zoology of promises is roughly zero." {allegra,ihnp4,decvax,pyramid}!utzoo!henry
edw@ius2.cs.cmu.edu (Eddie Wyatt) (05/20/87)
It seems to me that function prototypes violate a basic good rule about high programming language design which is : avoid having the user declare the same information more than once. As I understand, function declarations are still require in all there entirety. The same information is presented in function prototypes. The user is require to state approximately the same thing twice. The functionality of function prototypes is still useful though, to push the information about a function around to other modules. There is an ugly(?) alternative that will provide the same functionality. It will remove the burden from the user to the compiler. A optional approach is have the compiler generate the function prototype information ahead of time. Maybe another preprocessor stage to the compiler. *.fp files could automatically be create with all the function prototype information in them. The user would have a small task of including the appropriate *.fp files (not necessarily using #include). If stronger scoping requirements are needed then maybe a version of import should be adopted. How about: extern foobar() : foobarmodule; or foobar() : foobarmodule; In which case the user wouldn't have to include any new files since the information about what new files to use would be in the import from field of the external statement. I haven't worked out all the details to a feature like this. I'm sure there are some posible bad interactions between already existing features, but it's food for thought. -- Eddie Wyatt e-mail: edw@ius2.cs.cmu.edu
eager@amd.UUCP (mike eager) (06/17/87)
In article <1169@ius2.cs.cmu.edu> edw@ius2.cs.cmu.edu (Eddie Wyatt) writes: It seems to me that function prototypes violate a basic good rule about high programming language design which is : avoid having the user declare the same information more than once. .... > extern foobar() : foobarmodule; >or > foobar() : foobarmodule; > >In which case the user wouldn't have to include any new files since >the information about what new files to use would be in the import from >field of the external statement. > Unless I miss my guess, this is MODULA. Yes, someone else has worked out some of the details. See also ADA.
schmidt@zola.ics.uci.edu (Doug Schmidt) (04/30/89)
I'm about to port a C++ program to C. The original C++ program uses function prototypes heavily. It seems ashame to remove all the extra type checking, but the port must run on both ANSI and non-ANSI C compilers. Therefore, I'd like to know whether anyone has devised a useful set of preprocessor conventions that allow relatively transparent conversion between compilers that accept prototypes and those that don't. Dealing with external declarations seems fairly straight-forward: /* prototype.h */ #ifdef __STDC__ #define P(X) X #else #define P(X) #endif Then all extern decls could look like: #include "prototype.h" int foo (P(int foobar)); and the preprocessor will correctly substitute in a prototype for ANSI compilers or do nothing, for non-ANSI compilers. This should work in general, right? However, for function definitions things get messy. For example, I could use the old: #ifdef __STDC__ int foo (int foobar) #else int foo (foobar) int foobar; #endif trick, but this gets ugly real quick. Does anyone have a set of macros that helps simplify and beautify the process?! thanks, Doug -- On a clear day, under blue skies, there is no need to seek. And asking about Buddha +------------------------+ Is like proclaiming innocence, | schmidt@ics.uci.edu | With loot in your pocket. | office: (714) 856-4043 |
throopw@bert.dg.com (Wayne A. Throop) (05/08/89)
> schmidt@zola.ics.uci.edu (Doug Schmidt) > I'd like to know whether anyone has devised a > useful set of preprocessor conventions that allow relatively > transparent conversion between compilers that accept prototypes and > those that don't. There are many tradeoffs to be made. What I finally ended up using for situations where non-ansi compilers had to be accomodated has some drawbacks in that it requires some redundancy and prevents accurate typechecking of some of it. But it doesn't look too terribly awful, and it allows declaration of routines and contracts. It involves three macros, P, PT, and PP. The first is used in declaring functions. Where one might declare int foo( short bar, long bletch ) { ... } one would write int foo P(( bar, bletch ), short bar PP long bletch ) { ... } And in place of int (*foo)( short, long ); one would write int (*foo) PT(( short, long )); The definitions of the macros is left as an excersize to the reader. It isn't too difficult, basically setting the appropriate separators for PP, deciding whether to expand the argument to PT, and finally deciding whether to expand the first argument to P and what punctuation to put around the second one. -- If it could be demonstrated that any complex organ existed which coult not possibly have been formed by numerous, successive, slight modifications, my theory would absolutely break down. --- Charles Darwin -- Wayne Throop <the-known-world>!mcnc!rti!xyzzy!throopw