[comp.lang.c++] overloading operator . and ->

kearns@softrue.UUCP (Steven Kearns) (03/12/91)

I know it is too late now, but here is my opinion on how operator .
and operator -> should have been overloadable:'


Notice that in the current definition, X->f is really short for
(X->) ->f   .  I find this strange to say the least.  

Really, we should be able to overload not operator ->, but 
operator ->f and operator->g(int x) etc...  In other words, the 
real operation being applied to X in X->f  is "arrow f".  

This provides more flexibility than the current system because you
are not restricted to eventually returning something for which ->f 
makes sense.  It also seems more intuitive to me.  

-steve

********************************************************
* Steven Kearns            ....uunet!softrue!kearns    *
* Software Truth           softrue!kearns@uunet.uu.net *
********************************************************

jimad@microsoft.UUCP (Jim ADCOCK) (03/16/91)

In article <14.UUL1.3#8618@softrue.UUCP> kearns@softrue.UUCP (Steven Kearns) writes:
>Really, we should be able to overload not operator ->, but 
>operator ->f and operator->g(int x) etc...  In other words, the 
>real operation being applied to X in X->f  is "arrow f".  
>
>This provides more flexibility than the current system because you
>are not restricted to eventually returning something for which ->f 
>makes sense.  It also seems more intuitive to me.  

Your suggestion does not provide more flexibility than the current 
system because the current system allows one do what you are asking for --
albeit not exactly with the syntax you are requesting:

-----

extern "C" void printf(const char*, ...);

// probably ought to be nested:
class Xs_arrow_operators
{
public:
	void f() { printf("function X:: ->f()\n"); }
	void g(int i) { printf("function X:: ->g(int i=%d)\n", i); }
};

class X
{
	Xs_arrow_operators arrow;
public:
	Xs_arrow_operators* operator->() { return &arrow; }
};

main()
{
	X x;

	x->f();
	x->g(5);

	return 0;
}

----

Thus, by introducing a dummy helper class [which probably ought to be
nested] to serve as a target for the current operator->, you can
then overload each method in that dummy class as you like.

Likewise, if the ANSI-C++ committee chooses to also allow overloaded 
operator dot, then you'll also be able to meet your needs with operator dot.

However, going the other way, if C++ were to require individual overloading
of each method to be retargeted, then programmers would have to manually
[ or via hack ] implement a forwarding method for each method in order
to be able to create a smart pointer or smart reference classes.  IE
O(N) extra programmer typing -- where N is the number of methods requiring 
forwarding.  This would prevent generally-reusable template versions of 
smart pointer and smart reference classes -- not to mention make such 
onerous to program.  Whereas, going the other way, having to introduce an 
intermediate dummy helper class only requires O(1) extra programmer typing.

A more interesting question [to my mind] is whether C++ should [have]
also allow[ed]:

void operator->(class DispatchStyle) // likewise operator dot

This would allow overriding of the method of dispatch:

void X::operator->(class HashDispatchedMethod method)
{ hashDispatch(method); }

As of today, one can either override the dispatch technique for all
members of a class [albeit with grave restrictions] or you can individually
override the dispatch for each member individually [via an inline function]
but there's no way to break the members of a class into separate categories,
where each category uses a different dispatch technique.

[please note I am not requesting such functionality -- I'm only mentioning
 it as a curiousity.]

rfg@NCD.COM (Ron Guilmette) (03/25/91)

In article <14.UUL1.3#8618@softrue.UUCP> kearns@softrue.UUCP (Steven Kearns) writes:
>
>I know it is too late now, but here is my opinion on how operator .
>and operator -> should have been overloadable:'
>
>
>Notice that in the current definition, X->f is really short for
>(X->) ->f   .  I find this strange to say the least.  

Sorry.  It looks like you are fairly confused.  Don't feel bad.
You are in good company.

As any good book about C will tell you, this:

	ptr->member

is really just a convenient "shorthand notation" for this:

	(*ptr).member

Well... at least that *used* to be true.  Somewhere along the way, it
was decided that this simple relationship was just too clear, too
precise, and too easy to understand to allow it to just continue
unchanged into C++.

So something was added to help muddy the waters.

Rather than treating -> as the bit of "syntactic sugar" that it was
always meant to be, somebody (and I think I know who) got the idea
that it ought to take on a life of its own.

So it was reborn.  (Or should I say "born again"? :-)  And all the
faithful now call it an "operator" (which it clearly isn't, any more
that my aunt Emma is an "operator").

Of course, it would be one thing if we only *called* -> an "operator",
but unfortunately the language (as now defined) further compounds
this sillyness by allowing "->" to be overloaded!

Of course nobody should bother to suggest at this stage that this may
have been a mistake.  As Steven says: "It's too late".  There is too
large of an "installed base" already which depends upon this ill-conceived
"feature".

That reminds me of a quote that I was reading in some trade-rag recently.
Apparently some industry luminary was quoted as saying that Arlington
National Cemetery was a good example of a "large installed base". :-)

-- 

// Ron ("Shoot From The Hip") Guilmette
// Internet: rfg@ncd.com      uucp: ...uunet!lupine!rfg
// New motto:  If it ain't broke, try using a bigger hammer.

mvm@caesun6.harris-atd.com (Matt Mahoney) (03/25/91)

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

>Of course, it would be one thing if we only *called* -> an "operator",
>but unfortunately the language (as now defined) further compounds
>this sillyness by allowing "->" to be overloaded!

Then again, overloading [] (as in a[i]) is useful (IMHO), but in C
that's just syntactic sugar for *(a+i).  Allowing -> to be overloaded
is just being consistent.

-------------------------
Matt Mahoney, mvm@epg.harris.com, 407-727-5431
#include <disclaimer.h>  // disclaimer.hpp in Zortech

wmm@world.std.com (William M Miller) (03/25/91)

rfg@NCD.COM (Ron Guilmette) writes:
> As any good book about C will tell you, this:
>
>         ptr->member
>
> is really just a convenient "shorthand notation" for this:
>
>         (*ptr).member
>
> Rather than treating -> as the bit of "syntactic sugar" that it was
> always meant to be, somebody (and I think I know who) got the idea
> that it ought to take on a life of its own.
>
> So it was reborn.  (Or should I say "born again"? :-)  And all the
> faithful now call it an "operator" (which it clearly isn't, any more
> that my aunt Emma is an "operator").
>
> Of course, it would be one thing if we only *called* -> an "operator",
> but unfortunately the language (as now defined) further compounds
> this sillyness by allowing "->" to be overloaded!

I think the fundamental disagreement is over whether you ought to follow the
implicit relationships among overloadable operators or not.  In the language
as currently defined, there is no relationship among operator+(),
operator+=(), and operator++(), even though according to normal semantics
you could easily implement both operator+() and operator++() in terms of
operator+=().  If you don't supply one of these operators, it's simply
undefined, not inferred from the ones you do supply.

The reason this relates to "operator->()" is because, in the normal C
decomposition "(*ptr).member", it's clear that the "*"  _is_ an operator and
(as I'm sure you would agree) rightly overloadable.  The question is, should
"ptr->member" invoke operator*() if "ptr" is an object of a class with
operator*() defined?  If you think so, then clearly there's no need for a
separate operator->().  However, existing C++ practice is that you only
invoke an overloaded operator if the operator itself appears explicitly in
the text, ignoring the C identities.  In this view, you _can't_ invoke
operator*() for "ptr->member"; therefore, if you want to be able to overload
the conceptual "*" in "ptr->member", you _have_ to allow operator->().

For me, allowing operator->() leads to a more consistent language while
still permitting me the syntactic convenience of writing ptr->member instead
of (*ptr).member.  I agree that the expansion of "ptr->member" to
"(ptr.operator->())->member" is a bit strange, but I think the alternatives
(implicit invocation of operator*() for "->" or not allowing the ptr->member
notation at all) are worse.

-- William M. Miller, Glockenspiel, Ltd.
   wmm@world.std.com

Ari.Huttunen@hut.fi (Ari Juhani Huttunen) (03/26/91)

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

>Of course nobody should bother to suggest at this stage that this may
>have been a mistake.  As Steven says: "It's too late".  There is too
>large of an "installed base" already which depends upon this ill-conceived
>"feature".

It's never too late. And one can't expect a language to change just by
_adding_ things.

For an analogy, take a look at your Swiss knife. Who ever needs that many
blades?
--
Ari Huttunen, email: Ari.Huttunen@hut.fi, phone: 90-7285944

gjditchfield@watmsg.uwaterloo.ca (Glen Ditchfield) (03/26/91)

In article <1991Mar25.154013.4044@world.std.com> wmm@world.std.com (William M Miller) writes:
>For me, allowing operator->() leads to a more consistent language while
>still permitting me the syntactic convenience of writing ptr->member instead
>of (*ptr).member.  I agree that the expansion of "ptr->member" to
>"(ptr.operator->())->member" is a bit strange, but I think the alternatives
>(implicit invocation of operator*() for "->" or not allowing the ptr->member
>notation at all) are worse.

There was another alternative.  Don't treat "->" and "." as infix operators;
treat "->foo" and ".foo" as postfix operators.  That's how the ANSI C
standard defines them.
    struct C { int operator ->foo(); };
This wouldn't have helped programmers who want to define smart pointers.