[comp.lang.c++] Assignments to reference variables [ and operator.

jimad@microsoft.UUCP (Jim ADCOCK) (09/20/90)

In article <8445@jarthur.Claremont.EDU> dfoster@jarthur.Claremont.EDU (Derek R. Foster) writes:

|Is there any way to change the variable referenced by a reference variable
|after the reference variable has been initialized?
|
|In particular, I have a class which is passed a reference to a target
|variable which it is to modify. I would like to be able to simply
|declare a class member variable which would be a reference to the
|target variable, thus allowing my class member operations to access
|the target variable as if it was simply a member variable. In other words,
|I would like to be able to 'forget' that the target variable is actually
|external to the particular class object which has been told to modify it,
|except for in the routines which change to a new target. This seems like
|a perfectly legitimate use of a reference variable, and would work quite
|nicely if I was able to specify the target variable at the time a class
|object was constructed. Unfortunately, I can't.....

/****

In valid C++, references cannot be changed after being initialized.  Compilers
can perform significant optimizations on references, due to the fact that 
references cannot be aliased [they have no address, they can alias what they
refer to, but cannot be themselves aliased]  So, its not "legitimate" to try
to "reassign" references via hackery.  However, one can construct one's own
reference class, that internally uses a pointer to store the reference, but
presents that pointer to the outside world as if a reference.   Then you
just create an access member function to allow the internal pointer to be
reassigned to refer to a new object.  Unfortunately, when you try to do this,
you'll find that while C++ allows pointer classes to overload operator->(),
C++ ***does not*** allow reference classes the equivalent option of overloading 
operator.()  To get around this problem, one is forced to provide a forwarding
definition for all the public members of the class being referenced.  This,
in turn, generally prevents reference classes from being implemented via macros
or templates.

-- Please join me in lobbying the ANSI C++ committee to correct this oversight
in the language definition.  Overloading operator.() makes equal sense for
reference classes as overloading operator->() for pointer classes.  Classes
that naturally follow value semantics need to be implementable using 
reference syntax, not pointer syntax, otherwise the usage becomes 
horrible, as you point out. --

The code below illustrates this problem, and the painful work-around.

****/

extern "C" 
{ 
    #include <stdio.h> 
}

class THING
{
    char* name;
public:
    THING(char* nameT) : name(nameT) {}
    void DoSomething() { printf("%s DoSomething()\n", name); }
    void DoSomething2() { printf("%s DoSomething2()\n", name); }
};

typedef THING* PTHING;
typedef THING& RTHING;

// To make the below classes generally useful, you'd probably want to 
// implement them as templates or macros, so that they can be parameterized
// on the type of object being referred to....

// Yes! it's "trivial" to make a pointer class....

class THING_PTR
{
    PTHING pthing;
public:
    THING_PTR() { pthing = 0; }
    THING_PTR(RTHING rthing) { pthing = &rthing; }

    // ....because operator->() ***is*** overloadable.

    PTHING operator->() { return pthing; }

    RTHING operator*() { return *pthing; }
    operator PTHING() { return pthing; }
    void NowReferences(RTHING rthing) { pthing = &rthing; }
    // ....
};

// But, is it trivial to make a reference class? ....

class THING_REF
{
    PTHING pthing;
public:
    THING_REF() { pthing = 0; }
    THING_REF(RTHING rthingT) { pthing = &rthingT; }

    // ....but nooo, because operator.() ***isn't*** overloadable!

    // RTHING operator.() { return *pthing; }

    operator RTHING() { return *pthing; }
    void NowReferences(RTHING rthingT) { pthing = &rthingT; }
    // ....
};

// So, to make a legitimate reference class one has to write a forwarding method
// for every method in the referenced class -- which in turn means the 
// referencing class can't be implemented using macros or templates! 

class PAINFUL_THING_REF
{
    PTHING pthing;
public:
    PAINFUL_THING_REF() { pthing = 0; }
    PAINFUL_THING_REF(RTHING rthingT) { pthing = &rthingT; }

    operator RTHING() { return *pthing; }
    void NowReferences(RTHING rthingT) { pthing = &rthingT; }
    // ....

    // Now, add a forwarding call definition for ***ALL*** of THING's methods
    // ....In this case, just two, thank god....

    void DoSomething() { pthing->DoSomething(); }
    void DoSomething2() { pthing->DoSomething2(); }
};


main()
{
    THING thing1("thing1");
    THING thing2("thing2");

    thing1.DoSomething();
    thing2.DoSomething();  
    putchar('\n');

    THING_PTR thingPtr(thing1);
    thingPtr->DoSomething();
    thingPtr.NowReferences(thing2);
    thingPtr->DoSomething(); 
    putchar('\n');

// Too bad, **someone** decided you can't overload operator, so you
// can't do this: 

    printf("Sorry: THING_REF doesn't work....\n");
    printf("       ....because operator.() isn't implemented yet!\n\n");
#if 0
    THING_REF thingRef(thing1);
    thingRef.DoSomething();
    thingRef.NowReferences(thing2);
    thingRef.DoSomething(); 
    putchar('\n');
#endif

//  -- Except, via the painful class implementation: 

    PAINFUL_THING_REF thingRef(thing1);
    thingRef.DoSomething();
    thingRef.NowReferences(thing2);
    thingRef.DoSomething(); 
    putchar('\n');
}

rfg@NCD.COM (Ron Guilmette) (09/21/90)

In article <57570@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:
>
>-- Please join me in lobbying the ANSI C++ committee to correct this oversight
>in the language definition.  Overloading operator.() makes equal sense for
>reference classes as overloading operator->() for pointer classes...

Finally, Jim and I have found something to agree on. :-)

I'd say that Jim is correct is saying that treating either `.' or `->' as
if they were OPERATORS (kinda like other operators) makes equal sense,
i.e. *NONE*!  Allowing overloading for either of these makes about as
much sense as allowing overloading for `{' or `}'.

Look folks, just because a particular C++ token contains some non-
alphanumeric characters does not make it an operator!

OK.  Back to basics.  What is `->'?

Well, it is (syntactic sugar) shorthand notation for `*.' (i.e.
dereference and select).  So whenever I write:

	a->b

(in C anyway) that's always equivalent to:

	(*a).b

The meaning is clear and unambiguous.  Apply the prefix unary dereference
operator to the thing on the left, and then select out a member from the
result.

Now I've got no problem with (or objection to) allowing overloading for
the unary prefix dereference operator BECAUSE THAT *IS* AN OPERATOR IN
EVERY SENSE OF THE WORD.

I do object (most violently) however to any attempts to call the selector
`.' a `binary operator' (or to treat it as though it were one).  Obviously,
it isn't.

For all of the binary operators that *I* know of, either the left or the
right operands may be arbitrarily complex *expressions* (so long as these
expressions evaluate to some type of value which is appropriate for the
given category of operator).

This is clearly *not* true in the case of the selector `.'.  For the
selector, the thing on the right *must* be a (qualified or unqualified)
identifier which designates a some member belonging to the type of the
thing on the left.  The thing on the right *cannot* be an arbitrarily
complex expression.  It must be an identifier.  Furthermore, the identifier
*cannot* refer to any complete *object*.  Rather, it must refer to a
*member*.

So the selector is *not* an operator.  Period.  Allowing overloading for
it would make about as much sense as allowing overloading for `{' or `}'
or `::' or `"'.

Likewise, since `->' is just a shorthand notation for a combination of
an operator (i.e. unary prefix dereference) and the selector, allowing
overloading for `->' make as little sense as allowing it for the selector
all by itself, i.e.  none whatsoever.

I can't understand why Bjarne and Jim and others have so much difficulty
seeing the fundamental irrationality of allowing operator overloading 
to be done to things which are clearly not operators.

If they really think that this is such a swell idea, then I challenge them
to tell me (and everyone) why they are not suggesting allowing `operator{'
to be overloaded.

If there are any rules for what should be called an operator and what should
not, and what should be overloadable and what should not, I'd like to see
them!  If these rules are at all consistant, if they make any sense
whatsoever, and if they still would seem to permit -> to be overloaded,
I'll eat my hat.
-- 

// Ron Guilmette  -  C++ Entomologist
// Internet: rfg@ncd.com      uucp: ...uunet!lupine!rfg
// Motto:  If it sticks, force it.  If it breaks, it needed replacing anyway.

ark@alice.UUCP (Andrew Koenig) (09/22/90)

In article <1677@lupine.NCD.COM>, rfg@NCD.COM (Ron Guilmette) writes:

> In article <57570@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:
> >
> >-- Please join me in lobbying the ANSI C++ committee to correct this oversight
> >in the language definition.  Overloading operator.() makes equal sense for
> >reference classes as overloading operator->() for pointer classes...

> Finally, Jim and I have found something to agree on. :-)

> I'd say that Jim is correct is saying that treating either `.' or `->' as
> if they were OPERATORS (kinda like other operators) makes equal sense,
> i.e. *NONE*!  Allowing overloading for either of these makes about as
> much sense as allowing overloading for `{' or `}'.

I can't resist this one.

Of course . and -> aren't operators -- their right `operand' isn't
an expression.  However, one can view . or -> followed by an identifier
as being a postfix unary operator.

That is, writing a.b might be considered as applying the .b postfix
operator to a.  In other words, a.b could in principle be interpreted
as a.operator .b()  .

I think this notation is consistent, at least in principle.  It does,
however, have a few problems:

	1. How does one extend it to the -> symbol?  Is p->b equivalent
	to (*p).operator .b()?  Or is it necessary to define operator->b,
	which would be ambiguous (I think the first case is right)?

	2. It is too easy to confuse operator.b() with operator b().

	3. (perhaps this should be 0.) Is it really necessary?

I'm reluctant to propose new features of this sort because C++ has
enough stuff already, so this is not a proposal.  It's just a sketch
of what it might mean to `overload the . operator' if it were really
necessary to do it.
-- 
				--Andrew Koenig
				  ark@europa.att.com

bobatk@microsoft.UUCP (Bob ATKINSON) (09/24/90)

In article <1677@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
>In article <57570@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:
>>
>>-- Please join me in lobbying the ANSI C++ committee to correct this oversight
>>in the language definition.  Overloading operator.() makes equal sense for
>>reference classes as overloading operator->() for pointer classes...
>OK.  Back to basics.  What is `->'?
>Well, it is (syntactic sugar) shorthand notation for `*.' (i.e.
>dereference and select).  So whenever I write:

This is true in C.  Similar arguments apply in C to += -= <<= *= &=, etc.
C++ is not C.  See below.

>	a->b
>
>(in C anyway) that's always equivalent to:
>
>	(*a).b
>
>The meaning is clear and unambiguous.  Apply the prefix unary dereference
>operator to the thing on the left, and then select out a member from the
>result.
>
>Now I've got no problem with (or objection to) allowing overloading for
>the unary prefix dereference operator BECAUSE THAT *IS* AN OPERATOR IN
>EVERY SENSE OF THE WORD.
>
>I do object (most violently) however to any attempts to call the selector
>`.' a `binary operator' (or to treat it as though it were one).  Obviously,
>it isn't.
>
>For all of the binary operators that *I* know of, either the left or the
>right operands may be arbitrarily complex *expressions* (so long as these
>expressions evaluate to some type of value which is appropriate for the
>given category of operator).
>
>This is clearly *not* true in the case of the selector `.'.  For the
>selector, the thing on the right *must* be a (qualified or unqualified)
>identifier which designates a some member belonging to the type of the
>thing on the left.  The thing on the right *cannot* be an arbitrarily
>complex expression.  It must be an identifier.  Furthermore, the identifier
>*cannot* refer to any complete *object*.  Rather, it must refer to a
>*member*.

These last two sentences would ban pointers to members, which clearly
exist today and are useful. 

>So the selector is *not* an operator.  Period.  Allowing overloading for
>it would make about as much sense as allowing overloading for `{' or `}'
>or `::' or `"'.

Actually, the thing on the right hand side of a dot operator is precisely
a "reference to member."  References to members don't actually
exist in C++ as defined, but they would bear the same relationship
to "pointers to members" (which do exist) as a "reference to a non-member"
bears to a "pointer to a non-member." I can elaborate in more detail
if you or others would find that helpful.

>Likewise, since `->' is just a shorthand notation for a combination of
>an operator (i.e. unary prefix dereference) and the selector, allowing
>overloading for `->' make as little sense as allowing it for the selector
>all by itself, i.e.  none whatsoever.

Here is my understanding:

Overloading of -> was put in to enable the creation of "smart pointers:"
objects that clients use like pointers but in which the implementation
programmer has control over the dereferencing operation. Such pointers have
been found to be valuable in a number of contexts, which I will not
explore here. Syntactically, there are two ways that a (normal) pointer can be 
dereferenced: with '*' and '->'. Writing smart pointers therefore requires
that we be able to hook the dereferincing operation of both of these. I see
only two ways of doing that:
	
	1) declare that the use of -> is exactly the same as the
	   use of (*).  To hook dereferencing, a programmer need only
	   implement the * operation, since this will be used by ->
	2) give the programmer ways of hooking * and -> separately.

(Both * and -> must be hookable; either you hook them in the same place, or
you don't.) C++ has chosen 2).  This is the more general of the two, since
clearly you can do the same thing in each place. Moreover, 1) flies in the
face of the C++ decision to separate the meaning of += from + and =, along
with -=, *=, <<=, etc. I believe this was a sound decision, particuarly 
given the lack of ability to define new operators.

>I can't understand why Bjarne and Jim and others have so much difficulty
>seeing the fundamental irrationality of allowing operator overloading 
>to be done to things which are clearly not operators.

I guess there is disagreement as to what is "clearly" an operator. 

>If they really think that this is such a swell idea, then I challenge them
>to tell me (and everyone) why they are not suggesting allowing `operator{'
>to be overloaded.

The root of the difference I claim is that all operators (as so defined) 
are part of the expression language of C++, where { is solely related to
the statement constructs. A more elaborate explanation would require
an examination of the detailed syntactic structure of the language.

>// Ron Guilmette  -  C++ Entomologist

	Bob Atkinson
	Microsoft

bdsz@cbnewsl.att.com (bruce.d.szablak) (09/25/90)

In article <1677@lupine.NCD.COM>, rfg@NCD.COM (Ron Guilmette) writes:
> I can't understand why Bjarne and Jim and others have so much difficulty
> seeing the fundamental irrationality of allowing operator overloading 
> to be done to things which are clearly not operators.

Operator overloading is just syntatic sugaring to permit succinct and
readable expression of the programmer's intent. Being able to overload
the "->" construct works well with C++s user type system. I used it to
implement a reference counting pointer type for example, and the code
written using that type was much more readable as a result.
That is a justification for permitting it to be overloaded.

> If they really think that this is such a swell idea, then I challenge them
> to tell me (and everyone) why they are not suggesting allowing `operator{'
> to be overloaded.

Off hand, I can't think of a user defined type that using '{' construct would
result in more readable programs, but since it is used in the definition of
initialized data I wouldn't discount that there is one...

> If there are any rules for what should be called an operator and what should
> not, and what should be overloadable and what should not, I'd like to see
> them!  If these rules are at all consistant, if they make any sense
> whatsoever, and if they still would seem to permit -> to be overloaded,
> I'll eat my hat.

Prolog permits any legal identifier to be defined as an operator with
a precedence and associativity. Other languages choose to do things in other
ways. In the end, the "rules" are found in the manual. Perhaps
"operator" is an unfortunate choice of terminology, but were stuck with
it.

jimad@microsoft.UUCP (Jim ADCOCK) (09/25/90)

In article <1677@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
|In article <57570@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:
|>
|>-- Please join me in lobbying the ANSI C++ committee to correct this oversight
|>in the language definition.  Overloading operator.() makes equal sense for
|>reference classes as overloading operator->() for pointer classes...
|
|Finally, Jim and I have found something to agree on. :-)
|
|I'd say that Jim is correct is saying that treating either `.' or `->' as
|if they were OPERATORS (kinda like other operators) makes equal sense,
|i.e. *NONE*!  Allowing overloading for either of these makes about as
|much sense as allowing overloading for `{' or `}'.

I kind of agree, but I am not one for suggesting that "features" be removed
from the C++ language.  I am therefor one who suggests trying to make
"features" of the language as self consistent as possible.  Lacking overloaded
op. forces a gratuitous lack of symmetry between usages of pointers and 
references.  I think the best solution to the pointer verses reference 
syntax dilemma in C++ is just to give the user of the language the choice
to use either in a given situation.  If we had history to do over, it
might have been better if compilers were allowed to apply . directly to 
pointers, implicitly dereferencing the pointer first, rather than introducing
a separate -> syntax for pointers.  However, that's water long gone under the
bridge, and we need to try to make the best out of the situation today.
If we can fully enable the use of references in everyday programming,
then perhaps we can de-emphasize some of the alias problems with pointers 
that have never been resolved, and are re-rearing their ugly heads in C++.

|Look folks, just because a particular C++ token contains some non-
|alphanumeric characters does not make it an operator!

Right.  For that to happen the author[s] of the language has to say: "This 
particular token is an operator."  Said comment has been made for "->",
has not been made for "."  I jump the gun in referring to "op.", because
I am persuing an analogy to op-> -- an analogy that Ron seems to buy into.

Does Ron seriously suggest that overloaded op-> be removed from the language?

|OK.  Back to basics.  What is `->'?
|
|Well, it is (syntactic sugar) shorthand notation for `*.' (i.e.
|dereference and select).  So whenever I write:
|
|	a->b
|
|(in C anyway) that's always equivalent to:
|
|	(*a).b
|
|The meaning is clear and unambiguous.  Apply the prefix unary dereference
|operator to the thing on the left, and then select out a member from the
|result.

Likewise foo[n] is [was] "syntactic sugar" for *(foo+n).  When operator
overloading was first allowed in C++, the choice was made that the
decision to keep or not keep the historical equivalences from C in the
overloaded operators was up to the class programmer's discretion.

Given that the appropriate "operator" overloadings are permitted, a class
programmer can choose to copy these historical equivalences from C --
implicitly assuming that the C++ class user comes from a C background, and
thus has these equivalences ingrained on their consciousness -- Or a class
programmer can choose to ignore these historical meanings, possibly confusing
and pissing off the "C" audience for those classes.

But is it good to prohibit the operator overloadings necessary to enable
a class programmer from making these "C" analogies, for fear that a class
programmer might abuse these new found freedoms?

|I do object (most violently) however to any attempts to call the selector
|`.' a `binary operator' (or to treat it as though it were one).  Obviously,
|it isn't.

Why not rather, allow me to call it what I like [perhaps you'd be happier
if I call it a "rose?"] and argue for or against the feature based on its
impact on C++ programmers, as opposed to its impact on C++ language lawyers?

|For all of the binary operators that *I* know of, either the left or the
|right operands may be arbitrarily complex *expressions* (so long as these
|expressions evaluate to some type of value which is appropriate for the
|given category of operator).

When I was arguing for "op." by analogy to "op->", I was hoping that
people would realize that both would be unary operators [as op-> is now]

op-> is a member function of the type of its lhs, returning an object or 
primitive of type known at compile time, that the compiler can then reapply 
either an overloaded op-> to, or failing to find such, then perform the 
traditional compile-time binding to the rhs.

|This is clearly *not* true in the case of the selector `.'.  For the
|selector, the thing on the right *must* be a (qualified or unqualified)
|identifier which designates a some member belonging to the type of the
|thing on the left.  The thing on the right *cannot* be an arbitrarily
|complex expression.  It must be an identifier.  Furthermore, the identifier
|*cannot* refer to any complete *object*.  Rather, it must refer to a
|*member*.

No more true nor less true than op->

|So the selector is *not* an operator.  Period.  Allowing overloading for
|it would make about as much sense as allowing overloading for `{' or `}'
|or `::' or `"'.

"." is not an operator until it can be overloaded.  It is then an operator.
Like op->, it can make sense to turn "." into a unary operator, because it
certainly has an object on the lhs to bind to.

Other combinations of tokens with an object on one side, or the other, or
both sides, could also be candidates for similar promotion to "operator"
status, but I leave it to someone more flame resistant than myself to
make such proposals, if they feel so motivated.

In particular, it might be interesting to allow an extension to the 
language of:

object1 -> object2  and
object1 . object2

[IE allow binary overloading of op-> and op. where both the lhs, and the rhs
 are unambiguously objects, not field selectors]

This would allow programmers a reasonable option for implementing message
dispatch algorithms [such as hashed dispatch] other than that built into the
C++ compiler, while hiding the exact mechanisms of such dispatch from the
class user.  [Alternately, the class programmer with a need for non-
standard dispatch mechanisms must expose the class user to those dispatch
mechanisms via non-standard method invocation syntax.  Thus we're back to
the standard dilemma:  The overloading proponent says that this or that
overloading is necessary so that I can appropriately encapsulate details
of my class implementation.  The overloading opponent says that each new
overloaded feature of the language is yet another opportunity for hacks to
write code that confuses and confounds]

--But, this would entail larger changes to the language, and *I* am not making
such a proposal.  I am suggesting that allowing unary op. like unary op->
would fix a lot of the current syntax problems for users exposed to confusing
mixtures of pointers and references with no apparent rhyme nor reason.

|Likewise, since `->' is just a shorthand notation for a combination of
|an operator (i.e. unary prefix dereference) and the selector, allowing
|overloading for `->' make as little sense as allowing it for the selector
|all by itself, i.e.  none whatsoever.
|
|I can't understand why Bjarne and Jim and others have so much difficulty
|seeing the fundamental irrationality of allowing operator overloading 
|to be done to things which are clearly not operators.

Probably because if one looks at the problem from a different angle, the
fundamental irrationality goes away.

|If they really think that this is such a swell idea, then I challenge them
|to tell me (and everyone) why they are not suggesting allowing `operator{'
|to be overloaded.

1) Unlike op. , no one has presented a reasonable proposal why it might be
   good to allow doing so.

2) Unlike op. , one cannot argue that either the lhs or the rhs of "operator{"
   is an object such that the appropriate overloaded "operator{" can be 
   selected.

|If there are any rules for what should be called an operator and what should
|not, and what should be overloadable and what should not, I'd like to see
|them!  If these rules are at all consistant, if they make any sense
|whatsoever, and if they still would seem to permit -> to be overloaded,
|I'll eat my hat.

My proposal for such a set of rules is simply:

1) One or both sides of the proposed "operator" needs to be certainly an
   object, so that a member function can be unambiguously selected based on
   the type[s] of those object[s].

2) Someone needs to make a strong argument for how allowing such to be
   an overloaded operator is going to solve real-world programming problems.

3) It better not cause wide-spread changes throughout the language.

bobatk@microsoft.UUCP (Bob ATKINSON) (09/26/90)

In article <57684@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:
>In article <1677@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
>|Look folks, just because a particular C++ token contains some non-
>|alphanumeric characters does not make it an operator!
>
>Right.  For that to happen the author[s] of the language has to say: "This 
>particular token is an operator."  Said comment has been made for "->",
>has not been made for "."  I jump the gun in referring to "op.", because
>I am persuing an analogy to op-> -- an analogy that Ron seems to buy into.

But see E&S, 13.4, pg 330: 
"The following *operators* cannot be overloaded: 
	
	.  .*  :: ?:

nor can the preprocessing symbols # and ## (Sect 16)."
[Emphasis mine]


>Likewise foo[n] is [was] "syntactic sugar" for *(foo+n).  When operator
>overloading was first allowed in C++, the choice was made that the
>decision to keep or not keep the historical equivalences from C in the
>overloaded operators was up to the class programmer's discretion.


The reason that operators exist *at all* in C or C++ is for notational
convenience. Clearly, the language could have used, say, a purely
functional syntax, but this was deemed (correctly, in my opinion) to 
have been far too cumbersome.  Therefore, convenient notation was 
invented to manipulate *the data types that were present in the language*.
Of course, there are some relationships between the different notations.
Examples of these include the relationships between -> and (*). and 
[] vs *(+).

An important change occurred in C++. The programmer is now building *new*
data types that he would like to manipulate with as much ease and simplicity
as he can manipulate the built-in types. If good notations were important
for the ease of use of C's types, then there is every reason to believe
that they are important to the ease of use of programmer-defined types.  

Here is an exercise:

	Imagine you have an object which represents a range on a 
	spreadsheet.  Three very imporant operations that exist in
	today's macro languages are range construction (return a 
	rectangular range from its upper left and lower right corners),
	range union, and range intersection. Today, Microsoft Excel
	uses ':', ',', and ' ' (space) respectively for these operations.
	Because of their frequency, it is *absolutely essential* that 
	range construction and union be done in C++ with an operator.
	Functional notation (our only other alternative) is just 
	too cumbersome.  The desire for an operator for 
	intersection lies in it symmetry w/ union.

	You have some constraints:

		precedence construction 
			> precedence intersect 
			> precedence union

		ranges (cells) also respond to arithmetic and 
			comparision operators.

	Question: what C++ operators would you choose for these operations?	
		  (I believe there are two, maybe three, appropriate choices.)


The point of this exercise is twofold:

	1) to illustrate a user-defined data type for which notational
	   convenience is very important, and

	2) to illustrate the difficulty of providing that convenience
	   given the limited choice of operators and their fixed 
	   precedences.


There is very little reason that I can see for believing that the notation
appropriate and efficient for manipulating the built-in data types of C
will be appropriate and efficient for manipulating user-defined data types.

There is even less reason to believe that the relationships between 
the existing notations will be appropriate for the built-in types.
Sure, these relationships are a starting point for learning about
operators, but when a programmer encounters an interface to a new data
type that involves operators, he has to *realize* that unless the data
tyep is just a number-like thing (such as Complex, Fraction, or Matrix
might be), then the choice of operator notation for that class is 
a delicate exercise in compromise. *Many* of his preconceived notions
about the semantics of operators will simply not apply.


I personally believe that in the long term, this need for better notation 
for manipulating user-defined types will lead C++ to allow user-defined
operators.  In the mean time, given that we have to work with a fixed set
of operators at fixed precedences and associativities, I believe that 
we'll have to make do as best we can.  The more flexibility, the better
job we can do of providing appropriate efficient notation.



>|So the selector is *not* an operator.  Period.  Allowing overloading for
>|it would make about as much sense as allowing overloading for `{' or `}'
>|or `::' or `"'.
>
>"." is not an operator until it can be overloaded.  It is then an operator.
>Like op->, it can make sense to turn "." into a unary operator, because it
>certainly has an object on the lhs to bind to.

I disagree. I don't see the necessity of something being overloadable
before being labled an operator.  See below.


>Other combinations of tokens with an object on one side, or the other, or
>both sides, could also be candidates for similar promotion to "operator"
>status, but I leave it to someone more flame resistant than myself to
>make such proposals, if they feel so motivated.
>
>In particular, it might be interesting to allow an extension to the 
>language of:
>
>object1 -> object2  and
>object1 . object2
>
>[IE allow binary overloading of op-> and op. where both the lhs, and the rhs
> are unambiguously objects, not field selectors]

A neat idea. A particularly useful form for such a RHS happens in the case
where object2 is of a particular enum type, say type IEnum. This provides
the programmer with the ability to implement what look syntactically like 
data members but are implemented with a function for access.  This *might*
look something like:

	class C {
	enum IEnum { foo, bar, baz };
	public: int operator.(IEnum);
	};

	int C::operator.(anIEnum IEnum) {
		// return some integer
		}

	someClient {
		//...
		int anInt = someC.foo + someC.bar;
		//..
		}

Just a thought...


>|If they really think that this is such a swell idea, then I challenge them
>|to tell me (and everyone) why they are not suggesting allowing `operator{'
>|to be overloaded.
>
>1) Unlike op. , no one has presented a reasonable proposal why it might be
>   good to allow doing so.
>
>2) Unlike op. , one cannot argue that either the lhs or the rhs of "operator{"
>   is an object such that the appropriate overloaded "operator{" can be 
>   selected.

I think there is a more simple answer. All the tokens currently described
as operators can be found in strings derivable from "expression" as 
defined on pg 388 of E&S. { cannot be found in strings derived from
expression.  This is a fundamental distinction.


>|If there are any rules for what should be called an operator and what should
>|not, and what should be overloadable and what should not, I'd like to see
>|them!  If these rules are at all consistant, if they make any sense
>|whatsoever, and if they still would seem to permit -> to be overloaded,
>|I'll eat my hat.
>
>My proposal for such a set of rules is simply:
>
>1) One or both sides of the proposed "operator" needs to be certainly an
>   object, so that a member function can be unambiguously selected based on
>   the type[s] of those object[s].
>
>2) Someone needs to make a strong argument for how allowing such to be
>   an overloaded operator is going to solve real-world programming problems.
>
>3) It better not cause wide-spread changes throughout the language.


A cursory examination of 17.2 of E&S leads me to *conjecture* the 
following precise definition for the general notion of "operator."

	A operator is a token which is not an indentifier but 
	which can be found in _some_ string legally derivable
	from the non-terminal "expression" in the grammar.

(This definition must be modified to accomodate "parenthetical" operators.
I shall not do that here. It merely pairs into one operator tokens which
by this naive definition would be considered separate operators.)

My brief examination indicates that all such tokens derivable from
expression are today considered operators, and that conversely, all 
tokens considered operators today can be found in such strings.

For this purpose, I will not consider a reserved word to be an identifier.
This definition therefore encompasses the definition of "new", "delete", 
and "sizeof" as operators.

	
	Bob Atkinson
	Microsoft

tma@osc.COM (Tim Atkins) (09/27/90)

	As I see it there is a very pragmatic reason for not allowing
	operator . in C++.  Namely that it would be very difficult to
	distinquish normal use from the redefined use.  For instance:

	class schitzy {
	  	int a;
	    public:
		operator . () { /* do something different here */ }
		schitzy( schitzy& s){
			a = s.a;  // what do I really mean???
		}

	};

	I see no sane way to get back to the original operator . meaning
	in the above case.  Any takers?

dfoster@jarthur.Claremont.EDU (Derek R. Foster) (09/30/90)

In article <3833@osc.COM> tma@osc.UUCP (Tim Atkins) writes:
>
>	As I see it there is a very pragmatic reason for not allowing
>	operator . in C++.  Namely that it would be very difficult to
>	distinquish normal use from the redefined use.
> [example deleted for brevity]
>	I see no sane way to get back to the original operator . meaning
>	in the above case.  Any takers?

You might be able to use the global scope operator :: before the operator .
when its use was ambiguous. i.e. 

  object ::. member

or, more verbosely,

  object ::operator. member

I'm fairly certain the second is legal syntax. I'm not sure about the first.
If a redefined version of operator.() existed, it would of course always
override the default definition unless the global scope operator was
specifically used.

Just a side note about my letter which sparked this whole controversy:
About the second or third option I tried in my search for a way to
make my code work/look clean was the one of creating a "reference to
variable" class, as a latter poster suggested. I still think that this would
be a reasonable way to solve my problem, except for one minor detail: it
doesn't work. As this same later poster pointed out, this basically can't
be done due to C++'s inability to overload '.' It was nonetheless one of
the first things I tried, and I was quite surprised to find out that it
couldn't be done. This fact alone says something about the subject, I
think. Refusing to allow operator.() to be overloaded seems an arbitrary
restriction on the language, and forces programmers like me into
very convoluted syntax to get around its absence. The lack of this function
made me have to convert every reference to an object into pointer syntax,
adding perhaps forty extra sets of (* ) into my program for no good reason,
not to mention introducing some nasty bugs in the process. (Since the
operator [] can be applied to a pointer to an object as well as to the
object itself, any place where I forgot to phrase it as (*object)[] and
instead just wrote object[] produced no compiler error, just some highly
creative and sometimes very subtle results at runtime.) I wholeheartedly
support adding overloading of operator.() to the language! Let's do it,
folks!

Derek Riippa Foster

jimad@microsoft.UUCP (Jim ADCOCK) (10/02/90)

In article <3833@osc.COM> tma@osc.UUCP (Tim Atkins) writes:

|	As I see it there is a very pragmatic reason for not allowing
|	operator . in C++.  Namely that it would be very difficult to
|	distinquish normal use from the redefined use.  For instance:
|
|	class schitzy {
|	  	int a;
|	    public:
|		operator . () { /* do something different here */ }
|		schitzy( schitzy& s){
|			a = s.a;  // what do I really mean???
|		}
|
|	};
|
|	I see no sane way to get back to the original operator . meaning
|	in the above case.  Any takers?

This "difficulty" is presumably what lead op. to not be allowed overloading
in the first place.  My proposal is that overloaded op. not be treated any
differently than any other overloaded operator.  Namely: if your code ever
explicitly includes a dot with an instance of an overloading class on the lhs,
you get the overloaded operator.  In your example above, your use of dot
gets you the overloaded version.  How does one avoid getting the overloaded
operator?  By not using the dot.  C/C++ provides synonyms that avoid using
the dot:

instead of:

	a = s.a;

one can say:

	a = (&s)->a;


Note, that like the other overloaded symbol operators, the compiler never 
implicitly calls the function behind your back -- the overloaded function
only gets called when you write the symbol that is overloaded.  So, in the
important case of implicit this, you don't get the overloaded . operator --
anymore than you get the overloaded -> operator.

int schitzy::aValue()
{
    return a;
}

just returns the value of the local member.  It doesn't implicitly call
(*this).operator.().a; and it doesn't implicitly call this->operator->()->a;


In the real domain of applicability of operator.() -- namely in "smart" 
reference classes -- these issues needn't arise in the first place.  
Consider writing a reference counted reference class:

class FooRef
{
private:
    Foo* fooptr;
public:
    FooRef(FOO& foo) : fooptr(&foo) { foo.incrementUsageCount(); }
    ~FooRef() { fooptr->decrementUsageCount(); }
    Foo& operator.() { return *fooptr; }
    Foo* operator&() { return fooptr; }
    // ...
};

[[Note how much simpler and efficient reference counted references are compared 
 to reference counted pointers]]

I suspect that it would be difficult -- and truly schitzoid -- to try to 
write a class that acts simultaneously as a pointer and a reference.  Anyone
attempting such would get their just deserves.

dsouza@optima.cad.mcc.com (Desmond Dsouza) (10/02/90)

In article <57684@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:

   >...
   >"features" of the language as self consistent as possible.  Lacking overloaded
   >op. forces a gratuitous lack of symmetry between usages of pointers and 
   >references.

   >...
   >such a proposal.  I am suggesting that allowing unary op. like unary op->
   >would fix a lot of the current syntax problems for users exposed to confusing
   >mixtures of pointers and references with no apparent rhyme nor reason. 

I agree completely with Jim on this. The "confusing mixtures of
pointers and references" can be somewhat remedied with an overloaded
"."  Assignable references are just one feature which could be
implemented with this.

-- Desmond.





   
--

-------------------------------------------------------------------------------
 Desmond D'Souza, MCC CAD Program | ARPA: dsouza@mcc.com | Phone: [512] 338-3324
 Box 200195, Austin, TX 78720 | UUCP: {uunet,harvard,gatech,pyramid}!cs.utexas.edu!milano!cadillac!dsouza

ronb@burklabs (Ron Burk ) (10/07/90)

bobatk@microsoft.UUCP (Bob ATKINSON) writes:

> 	Because of their frequency, it is *absolutely essential* that 
> 	range construction and union be done in C++ with an operator.
> 	Functional notation (our only other alternative) is just 
> 	too cumbersome.

Eeeeeeehaaaaaa!  A man after my own heart!  You will definitely be
interested in the macro package I've designed for avoiding having to type
those cumbersome C++ keywords.  Here's the flavor:
    #define i   if
    #define f   for
       ...
    #define w   while
Next, I'm going to adapt this package to the "Hungarian" naming convention
so that each keyword has the *type* of data it operates on encoded in its
name!
    pipzyxw(/*condition*/)  { /* stmts */ }
          ^
       remember, "w" means WHILE  !!!


==========>  BIG  :-)