From: jimad@microsoft.com (Jim Adcock)
Subject: Re: Standard library functions and macros
Date: 12 Jan 93 20:45:03 GMT
Organization: Microsoft Corporation
Keywords: c++, ansi c

In article <1993Jan8.040102.14651@cbnewsk.cb.att.com> hansen@pegasus.att.com (Tony L. Hansen) writes:
|As long as the C functions are permitted to be implemented as macros, it is
|impossible to reliably overload any function name found in the C library.

This statement is incorrect.  A corrected statement would be:

As long as a given C function is permitted to be implemented as a macro, it is
impossible to reliably overload that function name found in that C library
if you include the header file for that C library.  However, if you DO NOT
include that header file, it is indeed possible to reliably overload any
function name.

Note two things:  You try to argue the general from the specific.
This is not and all-or-nothing decision and should not be treated as 
such.  Some ANSI-C function names could be required to be non-macro,
some could be required to be out-of-line, some could even be required to
be declared inline, and some could remain macro implemented as called-out
by ANSI-C.

Secondly, note that there IS a simple solution that allows BOTH overloading
and maintaining the requirements of ANSI-C.  Namely: simply do not include
the ANSI-C header file.  If you do not include the header file, then 
you do not get any possible macro implementations.  This further allows
the possibility that ANSI-C++ define differently named header files,
such header files implementing ANSI-C header file functionality, but
in a guaranteed non-macro manner.  For example, ANSI-C++ could simply
declare that the equivalent C++ header files have an .hpp extension,
said extension implying non-macro implementations, whereas if a programmer
continues to use the file with the .h extension, the programmer continues
to get the behavior permitted by the ANSI-C base document.

|    complex sqrt(complex&);

sqrt is one of my claimed handful of functions that have "attractive"
names that should be returned to the programmer's name space.  .
Excepting one can easily imagine that implementations should be
allowed to provide float, double, long double, complex, int, short, 
unsigned .... versions of this function.  Again, what you give to the
programmer you deny the implementor, so you better think about these
things on a per function basis, rather than just making a blanket statement
returning these names to the programmer space.

|Do you think it's reasonable to be able to overload functions such as
|fprintf() and rewind() for a type such as "File" instead of "FILE"?

"Rewind" is another one of the attractive names.  fprintf is unreasonable
for a C++ programmer.  You are arguing that the C++ programmer should
implement classes with one foot in the present and one foot in the past.
I disagree.  C++ programmers ought to implement new classes using C++
style and capabilities.

The unsafe and ugly C:

	fprintf(pfile, "format", varargs)

becomes:

	file << arg1 << arg2 << arg3;

to a reasonable C++ programmer.

| How
|about a function such as the string functions which all start with str*?
|Would you like to be able to overload those for a String class? 

No.  I would like a reasonably defined standard String class so that
I can avoid using all those functions [actually frequently compiler 
intrinsics] that start with str.  Leave the compiler writers their
intrinsic functions.  They built them into their compiler because
these names were guaranteed them by ANSI-C.

|overloading qsort() or bsearch() as template functions which work on an
|array of T instead of a void* memory area? 

Are you trying to tell me that implementations have implemented these
things as macros?  If not, then where is your argument?  They are not
macros, have not been, and thus do not represent an issue.

|Or how about overloading the time
|functions, such as difftime() and time(), for a Time class?

time() is essentially the ctor for the ANSI-C "time" [actually time_t] class.
One cannot have function names be the same as a class name, because that
name becomes reserved for the class and and its ctors.  This is nothing
new, and is not a macro issue.  When you make your Time class, don't name
it "time" but rather [god forbid] "Time" or something and there is no
conflict.  Or alternately don't include the ANSI-C "time.h" header.

| How about
|overloading the math functions, such as sin() and tan(), using a float
|instead of a double?

Again, these are traditional "attractive" names that should be returned
to the programmer.  Except clearly implementations should be allowed to
overload to implement float and long double versions themselves.  Which
raises the issue again:  When you return this name space to the programmer,
you are denying it to the implementation.  How then can implementations
implement these kinds of reasonable extensions?  Clearly a blanket return
of these name spaces to the programmer is a WRONG decision!  Life is not
so simple.!

|I think all of the above are within reasonable expectations. And guess what?
|You've just covered over half of the list of ANSI C functions. And, as long
|as the C functions are permitted to be implemented as macros, you won't be
|able to overload any of them!

Again, a correct statement would be for any function permitted to be
implemented as a macro, you would not be allowed to overload IFF you
included the corresponding ANSI-C header file.  If you did not include
that header file, you CAN overload.

Further, I count exactly nine functions you mention, which is nowhere
near half of the ANSI-C library definitions.  Of those nine, I agree
that you have identified two that can be reasonably overloaded.  Two
ways that such overloading could be permitted would be to violate the
ANSI-C base document obsolesence agreeement and simply prohibit macro
implementations of these two functions, or alternatively require the
programmer to not include the ANSI-C header files if they want to 
overload these functions.

|I'm not willing to lose that capability.

You DO NOT LOSE that capability!  You CHOOSE that capability by including
or not including the ANSI-C header file.  If you CHOOSE to include the 
ANSI-C header file, then you should get a conforming ANSI-C implementation 
of that header file as has been promised you and your compiler implementor.
If you CHOOSE not to include the ANSI-C header file, then you can use
those names any way you so desire.  If the ANSI-C++ committee cannot abide
by the rules promised by the ANSI-C base document, a solution is for
the ANSI-C++ committee to simply define their own uniquely named header
files implementing the rules that THEY believe should apply.  There is
no reason to break the ANSI-C header files and the rules called out for
implementing those header files.  Again, the ANSI-C document calls out
the rules for obsoleting an ANSI-C feature, and you guys are ignoring
those rules.  If you cannot abide those rules, then do not call ANSI-C
one of your base docs.

Finally, how about a counter-example:  Give me good reason why malloc
should be required to be implemented in a non-macro manner, such that
traditional debugging-malloc libraries can no longer be implemented?