Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!lll-crg!lll-lcc!pyramid!decwrl!sun!guy From: guy@sun.uucp (Guy Harris) Newsgroups: net.lang.c Subject: Re: macro to specify output parameter Message-ID: <6421@sun.uucp> Date: Thu, 21-Aug-86 15:44:56 EDT Article-I.D.: sun.6421 Posted: Thu Aug 21 15:44:56 1986 Date-Received: Thu, 21-Aug-86 22:25:20 EDT References: <522@bunny.UUCP> <6229@sun.uucp> <161@BMS-AT.UUCP> Distribution: net Organization: Sun Microsystems, Inc. Lines: 142 > > foo(c) > > char &c; > > { > > ... > > c = 'a'; /* store 'a' in the "char" referred to by > > "c" */ > I don't like this. It violates the nice consistent way that C expressions > work. 'char *c' means that '*c' is of type char. '&c' is not of type > char in any other context. Well, maybe a keyword like "ref" would have been preferable. However, the "syntax of declaration resembles syntax of use" rule of C may be consistent, but also can be confusing, so I don't consider it particularly holy. Also note that "&c" is not of type "char" in ANY context; inside the body of "foo", "&c" is of type "pointer to char", since it takes the address of the "char" referred to by "c". (The code generated for that would almost certainly just take the value of the pointer that implements "c" and use it.) Dereferencing of reference types is automatic, so "syntax of declaration resembles syntax of use" doesn't apply here. > I don't see any problem with using '*' instead of REF and DEREF. Since reference types and pointer types have different semantics, there are cases, at least in C++, where reference types are, I believe, necessary. Also, there may be cases where writing code using reference types could eliminated the possibility of aliasing and permit better optimization. Also, pointer arguments are overloaded in C; they are used if you actually want to pass a pointer to a routine (because the routine will actually be modifying the pointer value, e.g. "strcpy", where the pointer merely indicates the address of the *first* character to copy to and the *first* location to copy it into), and also if you want to do "call-by-reference". The presence of reference types makes it possible to state your intent more directly in C++ than in C. > In any case, either '*' or 'DEREF' is better than the foo example above > since the uses of the output parameter are marked. It's not clear that marking the *uses* is interesting. Is one just trying to find the places where the item pointed to by the argument is modified? You might want to do that with objects other than formal parameters, so using "*" or "DEREF" doesn't solve the entire problem. One might want to mark the *definition* instead; if the object referred to by the parameter is read-only, one obviously doesn't have to look for the places it's modified. This can be done with the "const" type modifier in ANSI C and C++, both for pointer and reference types. If the routine takes a reference or pointer to something and *doesn't* modify that something, it should be declared as taking "pointer to 'const' whatever" or "reference to 'const' whatever"; the compiler will refuse to compile any code that attempts to modify that something. > I would like to see variable size arrays allowed as local parameters. > This would be a lot more efficient than using malloc(). I presume you mean "local variables", and not "local parameters"; you can already handle variable-sized array parameters by the subterfuge of passing a pointer to the array (or to its first member) along with its length (if you *don't* pass the length, make sure you can't run off the end!). Supporting variable-sized arrays, even just as local variables, adds some complication to the compiler. Consider a function with two such arrays. The address of the second such array (or the first, depending on the order in which they're allocated), is a variable. This would most likely be supported by computing the address at the time it's allocated, stuffing it into an invisible local variable, and replacing references to the array with dereferences of the pointer. If you support them in structures, the complications get worse. > I would like to "operator definition" which would allow you to opdef > say '+' to cause it and its two arguments to be replaced by a macro > called with the two arguments whenever the arguments are of a type > specified in the definition. This allows generalized treatment of > operators on non-native types such as 'complex'. Check out C++; you can do exactly that there. You can overload existing C++ operators, binding them to functions. You can then declare the function to be "inline" so that the code is expanded in-line rather than producing a function call. In fact, one example Stroustrup gives is the addition of the type "complex" to C++, without changing the compiler and without turning all complex arithmetic operations into procedure calls. > Perhaps new operators could be custom defined or the syntax (left/right > association, priority) of existing operators changed (but probably not > except for completeness, changing existing operators is a good way to > make a program unreadable). Probably not even for completeness; the added cost of complication in the compiler doesn't seem worth it. (Isn't there a minor industry producing discussions of implementation of overloading in Ada compilers?) > I would like to see "structure constants" which would allow assignment > to aggregate types. C++ has this, using "constructors". Any "class", and structures are special cases of classes, can have a "constructor" as a member function. A "constructor" can take arbitrary argument lists, and merely need construct an object of the appropriate type. I think if you declare the "constructor" as "inline", it will do the "right" thing (i.e., typedef class complex { double real; double imaginary; public: inline complex(double r, double i = 0) { real = r; imaginary = i; } ... } complex; will cause complex i = complex(1, 0); to generate code like i.real = 0; i.imaginary = 1; I don't know whether it can be set up to do this at compile time for static objects. > Macros would be nicer with "imbedded functions". > > #define foo(x,y) { float a = 0.0; while (x) { a += y * x--; }; \ return a; } See David Chase's recent posting; he proposes more-or-less the same sort of thing, mentioning the similar sort of construct in BCPL. Of course, for this sort of thing, C++ "inline" functions might be better. Give a look at C++; don't let its syntax for reference types put you off. -- Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com (or guy@sun.arpa)