[comp.lang.c++] Why doesn't c++ allow overloading member operators?

mckenney@sri.com (Paul E. McKenney) (03/16/88)

Several c++ gurus around here told me that it is usually bad practice
to allow explicit access to instance variables in c++, that it was
better to define member functions to do the job.
This seemed very strange to me until I found that c++ does not allow
redefinition of the `.name' operators.  Of course, if you cannot
redefine these functions, then allowing explicit access to the
instance variables will `freeze' the representation of the object --
bad for software maintenance.

So, why doesn't c++ allow `.name' operators to be redefined?

				Thanx, Paul
				mckenney@sri.com

morrison@eecs.nwu.edu (Vance Morrison) (03/18/88)

    The question is "why doen't c++ allow you to overload the "." operator.

    I asked myself this very question and I don't have a good reason, but
I did realise that the "." operator is fundamentally different from most
other operators.  Namely its right operand MUST BE A COMPILE TIME CONSTANT
DEFINED FOR THAT PARTICULAR CLASS/STRUCTURE.  I don't believe that this
is the case with any other operator.  

    In order for c++ to alow "mimicking" of this operator's semantics,
(which is what all good overloaded operations do) there has to be a facility
in c++ to access this compile time info.  This opens up a whole new set
of problems which are better thought out carefully first.

    The real reason you probably want overloading is to allow "controled
access" to instance variables.  What would meet this need without overloading
the "." is for c++ to REDEFINE the "." operator for the class EXAMPLE so

	example.member 		means 	example.member()

    and if example.member() does not exist, then the "." means what it
used to.  I know for a fact that AT&T c++ does NOT allow member fuctions
and member variables to have the same name so this would not break any
code.

	SO HOW ABOUT IT??


					Vance Morrison
					morrison@accuax.nmu.edu

gjditchfield@violet.waterloo.edu (Glen Ditchfield) (03/22/88)

In article <8180005@eecs.nwu.edu> morrison@eecs.nwu.edu (Vance Morrison) writes:
>
>    The question is "why doen't c++ allow you to overload the "." operator.
>
>    I asked myself this very question and I don't have a good reason, but
>I did realise that the "." operator is fundamentally different from most
>other operators.  Namely its right operand MUST BE A COMPILE TIME CONSTANT
>DEFINED FOR THAT PARTICULAR CLASS/STRUCTURE.

You are treating "." as an infix operator whose right operand must come
from some nameless, magical enumerated type.  I think that the original
writer meant that ".fieldName" would be treated as a postfix operator:
"struct s { int a;};" might create a function named "s::operator .a".
The field reference "anS.a" would be equivalent to "operator .a(anS)".

Next problem: what is the returned type?  "int& s::operator .a()" seems
likely, since field a is normally an lvalue.  But a is not an lvalue if the
structure it is contained in is not an lvalue.  Perhaps two friends are needed:
"int& operator .a(s& someS)" and "int operator .a( (const s)& someS)".

(Digression:  I wish C++'s type system had a good way to express the
concept of "lvalue".  Reference types don't quite do it.  I'd love to see
discussion of the subtleties of this, under another subject heading.)

Another problem is that "." functions are often proposed as a way of
getting lvalue pseudo-members.  A Trellis/Owl paper (in OOPSLA '86?)
gives as an example a thermostat object whose setting is changed by
assigning to the "Celsius" field or to the "Fahrenheit" field.  The value
assigned is treated as a temperature from the appropriate scale.  One (or
both) is a pseudo-member that scales the given temperature and sets other
members.  This won't work in C++, because assignment is an operator that is
evaluated after its left operand.  I haven't decided whether lvalue
pseudo-members are good things or not.  We can argue about that, too.

Glen Ditchfield                              watmath!violet!gjditchfield
Dept of Computer Science, U of Waterloo         (519) 885-1211 x6658
Waterloo, Ontario, Canada			   Office: MC 2006
If you grab the bull by the horns, you at least confuse him -- R.A.Heinlein

mckenney@distek4..istc.sri.com (Paul E. McKenney) (03/22/88)

In article <8180005@eecs.nwu.edu> morrison@eecs.nwu.edu (Vance Morrison) writes:
>    The real reason you probably want overloading is to allow "controled
>access" to instance variables.  What would meet this need without overloading
>the "." is for c++ to REDEFINE the "." operator for the class EXAMPLE so
>	example.member 		means 	example.member()
>    and if example.member() does not exist, then the "." means what it
>used to.  I know for a fact that AT&T c++ does NOT allow member fuctions
>and member variables to have the same name so this would not break any
>code.
>	SO HOW ABOUT IT??
>					Vance Morrison
>					morrison@accuax.nmu.edu

The only problem that I can see with this is if it is legal to pass
member functions as parameters.  The `C++ Programming Manual' claims
that doing this is implementation-dependent (pg 276).  I would have
no problem stealing an implementation-dependent case, but I could imagine
myself having a different attitude if I had written a large c++
application :-).

If there is too much history out there to allow Vance's clever modification,
perhaps the concept of `member operator' could be added to the current
`member variable' and `member function' suite.  

For example, the declaration:
	struct	s
		{
		int	a { return (1) };
		char	b;
		} S;
would declare these objects:
o	a structure `s'.
o	a postfix member operator `.a' that returns `int' when applied to an
	object of type `struct s'.
o	a postfix member operator `->a' that returns `int' when applied to an
	object of type `struct s *'.
o	a member variable `b' of type `char'.
o	a variable of type `struct s' named `S'.
Then the compiler would decide which `.a'  (or `->a') operator was to be
invoked based on the type of the expression that it was applied to (just as for
any other overloaded operator).
Note that the declaration could be distinguished from member functions since
there is no `()' after the name, and it could be distinguished from member
variables because of the curly braces.
This approach makes is unnecessary for the member operators to be in any way
different from other operators.  In particular, there is no need for any
additional access to compile-time info, nor for any special compile-time
constant requirements.

				Thanx, Paul

franka@mmintl.UUCP (Frank Adams) (03/22/88)

In article <8180005@eecs.nwu.edu> morrison@eecs.nwu.edu (Vance Morrison) writes:
>    The question is "why doen't c++ allow you to overload the "." operator.

Actually, the original poster was regarding ".member" as the operator, not
just the ".".

>    The real reason you probably want overloading is to allow "controled
>access" to instance variables.  What would meet this need without overloading
>the "." is for c++ to REDEFINE the "." operator for the class EXAMPLE so
>
>	example.member 		means 	example.member()

The problem is that there are, more or less, two operations associated with
members: access and update.  The above is useless if I want to want to use
statements like: "example.member = foo;".

(It is *not* sufficient to define the member() function as returning a
reference (such as "int &member()"), since in general, one wants to *do*
something for the access/assignment.)
-- 

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Ashton-Tate          52 Oakland Ave North         E. Hartford, CT 06108

lsr@Apple.COM (Larry Rosenstein) (03/23/88)

In article <5868@watdragon.waterloo.edu> gjditchfield@violet.waterloo.edu (Glen Ditchfield) writes:
>
>Another problem is that "." functions are often proposed as a way of
>getting lvalue pseudo-members.  A Trellis/Owl paper (in OOPSLA '86?)
>gives as an example a thermostat object whose setting is changed by
>assigning to the "Celsius" field or to the "Fahrenheit" field.  The value

Trellis/Owl is based on CLU.  In CLU the expression 'x.name' was syntactic
sugar for the invocation 'typeof(x)$get_name(x)'.  The assignment 'y.name :=
q' was sugar for the invocation 'typeof(y)$set_name(x, q)'.  It seems as if
C++ could use the same kind of mechanism.  

-- 
		 Larry Rosenstein,  Object Specialist
 Apple Computer, Inc.  20525 Mariani Ave, MS 32E  Cupertino, CA 95014
	    AppleLink:Rosenstein1    domain:lsr@Apple.COM
		UUCP:{sun,voder,nsc,decwrl}!apple!lsr