Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.1 6/24/83; site yale-comix.UUCP Path: utzoo!watmath!clyde!burl!ulysses!mhuxl!ihnp4!zehntel!dual!amd!fortune!hpda!hplabs!sdcrdcf!sdcsvax!akgua!mcnc!decvax!yale-comix!leichter From: leichter@yale-comix.UUCP (Jerry Leichter) Newsgroups: net.lang Subject: (Re:)* Modula-2, exceptions, C Message-ID: <4096@yale-comix.UUCP> Date: Fri, 29-Jun-84 10:48:05 EDT Article-I.D.: yale-com.4096 Posted: Fri Jun 29 10:48:05 1984 Date-Received: Fri, 13-Jul-84 23:41:37 EDT Organization: Yale University CS Dept., New Haven CT Lines: 199 A couple of minor points of information regarding Alex Pournelle's comments on C versus Modula2. First, it is true that current C compilers do not allow you to declare the types of the arguments to functions in the "interface" files (i.e. .h files). However, the proposed ANSI C standard DOES allow such declarations; presumably lint's that are compatible with the new spec will appear forthwith (the changes required to support it should be trivial). On VAR parameters: I am personally of two minds about this. On the one hand, I like being able to have such things directly supported by the language. On the otherthere IS a valid argument to be made that requiring an & at the point of call has the salutory effect that it is possible to determine BY LOOKING AT THE CALLING CODE ONLY, what values may potentially be affected by the call. Think about it: In C the ONLY things that can directly change the value of a variable are =, op=, ++, and --, and the only thing that can cause a value to be change indirectly is &. If you are going to be using some function which requires a VAR parameter a lot, you COULD define a macro to put the & on for you - e.g., #define f(x) f_(&(x)) I would generally avoid this kind of construction exactly because readers of C code assume that functions are called by value. At least, you should pro- bably call the macro F, rather than f, since C readers understand that macros may do funny things, and that upper-case "functions" are often macros. BTW, your comment about "& before (right?) the argument" or whatever seems to indicate that you haven't done much C programming. There are certainly obscure points of C syntax, just about all of them having to do with the declaration style C uses (which was a nice experiment but...); however, most of the language's sytax is easy to learn and remember. I almost never had to look at the manual to check syntax after two weeks of using C, and I don't know anyone else who hasn't had the same reaction. (Now, library routines, those I have to look up ALL the time. I'd like to shoot whoever decided to place the file arguments either first or last when there are multiple argu- ments, depending on the phase of the moon.) As to "if (y = 5)": Yup, one of the worst error-producers in C. Fortunately, this is pretty easy for a compiler to flag as "questionable" (flag the args of if, while, and the conditional in for if the operator at the top of the parse tree is an assignment), and some of them do. I prefer the C style, with proper compiler support, to having to put in all the stupid colons in :=; there are typically many more assignments than equality tests in my pro- grams; this is a matter of taste. Actually, as far as I'm concerned the ONLY language that has this right is APL, in which "=" is a comparison and assignment is a left-pointing arrow. (I guess Smalltalk does the same thing.) Too bad you have to make up your own character set to be able to do this; ASCII once had a left arrow, but it was replaced by "_" a long time ago. On PROC versus declaring something as returning void: If ever there was a trivial point, this has GOT to be one. In fact, if I really want to make an argument of it, I can say that using PROC and FUNCTION (or whatever) requires that a user understand two distinct concepts - since there is no relationship in English or computer science between the two words - while the C style has just one concept: int foo() says foo returns a member of the class of int's; void foo() says foo returns a member of the (by definition empty) class of void's. Finally, as to initializers: Yup, this is something missing from the C language as such. In fact, however, it can be added quite handily. I have included below a man page for such a facility that I added to DECUS C a couple of years ago. I quite agree, such a thing is very handy to have. (Actually, I insist on the availability of finalizers, too; Modula 2 is only halfway there...) -- Jerry decvax!yale-comix!leichter leichter@yale The function wrapup() mentioned in the documentation was an earlier version of a program-wide finalizer facility. The C runtime support code would call of function called wrapup() when exit() was called or main() returned. If the programmer did not provide a function of this name, one was found in the library when the program was linked; the one in the library consists of just a return. *********** * initial * *********** File name: initia.h NAME: initial -- Specify Initializers and Finalizers SYNOPSIS: #include INITIAL { initial-code-block }; FINAL { final-code-block }; DESCRIPTION: The macros defined in this module provide a facility for module-specific initialization and finalization code. The code in the initial-code-block is called as a normal C function before main() is called; the final-code-block is called on exit, just after wrapup(). Neither call passes any arguments. Any number of modules - separately compiled files - in an image may independently declare initializers or finalizers; all of them will be called at startup or exit. However, it is impossible to predict what order the calls will be made in, and programs should not rely on any particular ordering. A typical use of initializers and finalizers is the following: Suppose you have a package that supports access to some on-disk data base; a user of the package will call a lookup and an update function. The file containing the data base must be opened before any operations on it can take place, and it should be closed when the program is finished. (Assume that the package maintains some sort of resident buffer which it must flush.) There are two conventional approaches to solving this problem: Have the lookup and update functions check the file on each call, and open it if necessary - which could be quite expensive if they are very small functions, and in any case does not solve the problem of properly closing the file - or have the main program call an initialization and finalization function at the proper time. The problem with this latter approach is lack of modularity - the main program ought not to have to know that the module needs initialization or finalization. The solution using these macros is straightforward. The defining module includes the calls: INITIAL { open-the-data-base }; FINAL { flush-buffers-and-close-the-data-base }; BUGS Requires the DECUS C dsect commands; hence, very non- portable. It may be possible to provide the same func- tionality using different techniques; if not, what's wrong with your implementation? AUTHOR Jerry Leichter For the curious, here is how it is done: INTERNAL The macros operate by leaving a list of (pointers to) functions to be called in psects $INIT$ and $FINL$. In order to be able to determine the beginning and end of these psects, the psects $INIT, $FINL, $INIT. and $FINL., are also reserved. These psects must not actually con- tain any data; they exist solely to provide well-defined endpoints to the initialization and finalization list. The names are consecutive in alphabetical sequence, so the Task Builder will place them in order. The RT11 Linker, however - and the Task Builder with the /SQ switch - place psects in the order they are encountered. Since it impossible to predict what order the various modules will be seen by the linking program, it is essential that EVERY module that refers to any of these psects refer to the two related ones as well, and in the correct order. Here is the code itself, for the REALLY curious: /* )EDITLEVEL=05 * Edit history * 0.0 19-Jul-82 JSL Invention * 0.1 22-Nov-82 JSL Documentation cleanups only; much of the documentation * gets duplicated in initia.mac. */ #define INITIAL dsect"$init ";dsect"$init$";static char *$init_ = &$init$;dsect"$init.";dsect"";static $init$() #define FINAL dsect"$finl ";dsect"$finl$";static char *$finl_ = &$finl$;dsect"$finl.";dsect"";static $finl$() /* * Sorry about the scrunched code; DECUS C has some size limits on #define * lines that are a pain. Here's the code "in the clear": * * #define INITIAL dsect "$init "; \ -- Declare the dsects in the * dsect"$init$"; \ right order * static char *$init_ = &$init$; \ -- Pointer to the function * dsect"$init."; \ -- Another dsect in order * dsect""; \ -- Back to the default * static $init$() -- Declare the function * * The code for FINAL is essentially the same. */