Topic: ARC++ and Automatic Functions
Author: jones@jameson.arclch.com ((Ben Jones))
Date: Tue, 8 Mar 94 11:56:57 EST Raw View
This is the fifth in a series of articles which will explore ideas
for extending the C++ language. These extensions are implemented in
an experimental preprocessor called ARC++ which takes the extended C++
syntax and generates ANSI C++. Those who wish to try out the ideas
being presented here may obtain a copy of ARC++ for the PC, Mac,
Sparcstation, or Iris from the anonymous ftp on: "arcfos1.arclch.com".
Please go to the directory "/pub" and download the file "arc.READ_ME"
for instructions.
AUTOMATIC FUNCTIONS
===================
Ben Jones
(c) 1994 ARSoftware Corporation
jones@jameson.arclch.com
Introduction
============
C++ parameterless functions almost always require an operator to
invoke them. That is, there must be parentheses, an overloaded
operator, or a conversion operator (which is invoked by operators in
an expression). The one exception is the default constructor
function.
Many languages including Ada and Pascal have functions which may be
called without arguments and without parentheses. These are useful
for creating pseudo-variables which are executed every time they are
referenced. They are analogous to device registers on a computer bus
where the mere reference to the right address can trigger a hardware
function.
The hidden functionality provided by conversion operators in C++
classes can be easily broken by passing an object name to a function
defined with ... It can also be broken if the object name is passed
to a function which does not have exactly the right prototype to
trigger the conversion.
ARC++ provides a couple of extensions in this area.
Automatic Function Designator
=============================
Currently in C++, a function name not followed by parentheses is
considered a pointer to a function. Therefore a qualifier is needed
to indicate a function which is to be executed when its name occurs
in an expression. ARC++ allows the "auto" qualifier after the
parameter list for this purpose:
int x() auto; // Make "x" an automatic function
int i = x; // Execute x implicitly
int (*pf)() = x; // Get pointer to x
The only case in which an automatic function is not executed implicitly
is when it occurs in a context where a pointer to a function is expected.
A function with all default arguments can also be designated as automatic:
int y(int a=0) auto; // Make "y" an automatic function
int i = y(1); // Call "y" explicitly
i = y; // Call "y" implicitly
In order for an automatic function to be used as an Lvalue, it would
have to return a reference:
int & z() auto; // Automatic "z" returns reference
z = 100; // It can be used as an lvalue
Automatic Member Functions
==========================
Automatic virtual member functions allow you to create "members" which
only exist in derived classes:
class X
{
public:
virtual int x() auto { return 0; }
};
class Y: public X
{
private:
int _x;
public:
virtual int x() auto { return _x; }
};
X x1;
Y y1;
int i;
i = x1.x; // i = 0;
i = y1.x; // i = y1._x
Automatic Function Pointers
===========================
ARC++ also allows function pointers to be made automatic:
int (*pf)() auto;
int f();
pf = f; // pf is not executed
int i = pf; // pf is executed
Again, the principle is that if an automatic function pointer is used
in an expression where a function pointer is expected, it is not
executed.
Automatic Classes
=================
Of course you would also want the ability for a class to have an
automatic function. Operator functions partially fill this
requirement but they are not always invoked properly. For example, if
they are used as an argument to a function declared with ..., they
will not be invoked at all. If they are used in an expression which
is not quite the right type they may not be invoked either.
So ARC++ allows the "auto" qualifier on the parentheses operator for a
class:
class X
{
int operator () () auto; // Automatic () operator
int f(int a);
};
X x1;
printf("%d\n",x1); // Execute "x1()"
printf("%d\n",x1.f(100)); // Execute "x1.f(100)"
The rule here is that if an object of this class is used in an
expression and if NO members or member functions are otherwised
accessed, the automatic parentheses operator would be invoked.
Modify Detection
================
Hardware device registers detect if data is written to them. It is
desirable for automatic functions to know if they are used as lvalues
(the reference returned is to be modified).
ARC++ declaration syntax for functions recognizes a parameter
declaration beginning with "?" as a special hidden argument. A
keyword (not a reserved identifier) following the "?" identifies the
type of hidden argument. The keyword becomes the name of a value
available to the body of the function. This was previously described
in "ARC++ and Variable Argument Functions".
The function argument "?modify" defines "modify" as an int which is
set to 1 if the return value of the function is to be used as an
lvalue:
int & x(?modify) auto;
int i = x; // i = x(0)
x = 100; // x(1) = 100
This not only detects lvalues but also assignments of the return address
to pointers. "modify" is set to one if the return address is assigned to
a pointer to non-constant and is therefore potentially modifiable:
int *pi = &x; // pi = &x(1)
const int *pci = &x; // pci = &x(0)
This capability will be elaborated upon further in a future article
"ARC++ and Smart Pointers".
Conclusions
===========
Automatic functions can make for much cleaner C++ programs:
* Programs aren't cluttered with lots of ()'s.
* Classes can be made to act as memory management units which gain
accesses to other objects without requiring a lot of complex
overloading.
* Conversion functions can be made idiot-proof.