From: wmm@world.std.com (William M Miller)
Newsgroups: comp.std.c++
Subject: Re: Alternatives to operator.()
Date: 30 Jul 92 03:31:56 GMT
Organization: Software Emancipation Technology, Inc.

> |expr           addressing context      scope
> |----           ------------------      -----
> |(*xp).i        object to which xp      class X
> |               points (indirection)
> |
> |xp->i          object to which xp      class X
> |               points (indirection)
> |
> |In each case, you look up the name "i" in the implied scope, take the
> |corresponding offset out of the symbol table, and add it to the base
> |address implied by the addressing context.  
> 
> Your statement is incorrect in both the (*xp) and xp-> cases above,

So you assert, but I saw no argument to that effect in your posting.

> I keep making this point, and you keep ignoring it:
> 
> The language ALREADY permits operators *, &, and -> to be overloaded, yet
> you keep making arguments pretending that these overloadable operators
> don't ALREADY exist.

The reason I "ignore" this point is because it is irrelevant to the subject
of the analysis I was making -- that built-in "." is different from built-in
"->" because the former does not have a corresponding run-time operation,
while the latter does.  Since the built-in "." has no runtime operation, it
does not make sense, IMHO, to allow an overloaded operator.(), since
overloaded operators are primarily runtime operations (calling a function to
perform some action).  The built-in "->" _does_ perform a runtime operation
(indirection), so providing an overloaded operator->() does make sense from
this perspective.

>                                    we need overloadable operator.()
> to ALLOW such relationships to continue to be made, in the face of
> ALREADY overloadable operators &, * and ->

This is an unjustified conclusion.  What is needed is smart references,
whether provided by operator.() or some other method.

> Wrong.  If this were my terminology, then in the following:
> 
>         px -> i;
> 
> would mean "i within the object referred to by px"

It does.

> which is clearly a false statement given that the language ALREADY
> allows operator-> to be overloaded.

The action of an overloaded operator->() is irrelevant to this analysis of
the meaning of the builtin operators.

> I have pointed out that there is a tiny fixed set of unary member operators
> where ARM requires the LHS to be a member.

And those are only the beginning of the operators that may require
forwarding functions.  In addition, all the compound assignment operators
(+=, -=, etc.) are generally best provided as member operators.  Other
operators may be included as members as well to prohibit conversions in
operator contexts.  (And don't forget conversion operators, too, which must
be members.)

> That's It.  Since there is such a small fixed set of possible functions, 

No, the set is unlimited because of argument overloading and conversion
targets.

> BUT, what if the class implementor CHOOSES NOT to forward one of these 
> operators?  What if a "smart reference" implementor CHOOSES that operator=()
> should mean -- BY DEFAULT -- assign one smart reference to another
> [such as references are implemented in just about all other OOPLS]
> 
>         ref1 = ref2;    // assign ref2 to ref1 NOT assign refed-ob2 to refed-ob1
> 
> Your position would prohibit such a CHOICE.

No, since my preference is for a solution in which members of the smart
reference are chosen in preference to the target's members.  (Actually, the
special rules for operator=() -- generated by the compiler rather than
inherited from a base class -- require that smart reference classes provide
operator=() regardless of which set of semantics is desired, but the point
still applies to the other operators.)

>                                       Again, rather then keep making 
> vacuous arguments that "my" proposal is "half-empty" why don't *you*
> write down *your* counterproposal for how something, anything else would
> work that is better.  Because right now, your counter-proposal is not
> "half-empty" -- rather it is totally empty, because you have refused to
> counter-suggest any CONCRETE counterproposal
                     
I freely agree that I have no counterproposal.  The reason is not "refusal"
to write one but simple lack of time, both to explore fully the ideas I have
and to write them down comprehensively if the exploration indicates that the
effort of documenting them is warranted.  Perhaps in the fall something will
be possible; in the meantime, part of the role of my criticism is to
establish some of the criteria which a proposal would have to fulfill in
order for me to consider it "better."

I continue to emphasize, though, that I'm not arguing against your proposal
in favor of some other proposal but simply explaining the things I don't
like, regardless of whether any other proposal ever comes down the pike.
The issue is not, at the moment at least, whether your proposal is better
than some other, but whether it's good enough.  Is your proposal better than
the status quo?  Probably.  Is it enough better to warrant changing the
language?  I'm not convinced, and the reasons are my three objections:

1) It requires warping one's model of the language to attribute a runtime
action to "." (to be fair, some people have apparently already acquired this
warped view, so it's not a disadvantage for them :-)

2) It leaves a bunch of forwarding functions still potentially required

3) It requires doing something unobvious to access members of the smart
reference (and, as has been pointed out, there are lots of ways of doing
that, none obviously better than the others).                

The degree of importance one assigns to these issues in comparison to the
benefits of the proposal is obviously a value judgment, but they do have to
be considered.