From: wmm@world.std.com (William M Miller)
Subject: Re: Alternatives to operator.()
Organization: Software Emancipation Technology, Inc.
Date: Tue, 21 Jul 1992 13:16:25 GMT

In article <1992Jul20.235728.29058@microsoft.com>, Jim Adcock writes:
> |That was not my intention in posting this message.  During our earlier
> |exchange a couple of weeks ago, I posted my list of objections to your
> |proposal.  They included, in case you've forgotten:
> 
> In case you've forgotten, I've answered these "objections" repeatedly.

Yes, I've read your "answers" (see, I can use the quote key, too --
can we agree to stop casting aspersions on the validity of one
another's mental processes and just deal with the issues
dispassionately?).  The reason I listed my objections here was to
demonstrate that none of them were comparative, not to elicit further
discussion of them.

> a) it IS an operator, and always has been.  See for example, K&R 1978
> page 49 lists "->" and "." as BOTH being operators of identical precedence.

I've never said that it wasn't an operator -- syntactically it clearly
is.  So is "::".  I contend that "." is more like "::" than like "->".

> b) it DOES perform a runtime operation, essentially identical to "->"
> as anyone knows who has looked at the code generated for reference members
> and "." and pointer members and "->"

We interpret the data differently here.  The dereferencing code to
which you are referring is the result of the use of a reference in an
expression and not of the appearance of ".".  Let me illustrate in the
context of the following example:

	struct X { int i; };

	int i;

	void f() {
		int i;
		X x;
		X* xp;
		X& xr = x;

		// reference expression

	}

Consider each of the following expressions at the location indicated
by the comment "reference expression":

	Expression	Interpretation
	----------	--------------

	i		Fetch the value at the appropriate offset in
			f()'s stack frame

	::i		Fetch the value at the appropriate offset in
			the program's static storage region

	x.i		Fetch the value at the appropriate offset in
			the object "x"

	(*xp).i		Fetch the value at the appropriate offset in
			the object found by indirecting through the
			value of "xp"

	xp->i		Fetch the value at the appropriate offset in
			the object found by indirecting through the
			value of "xp"

	xr.i		Fetch the value at the appropriate offset in
			the object to which "xr" refers, i.e., "x"

Notice that each of these interpretations begins with the same phrase,
regardless of the presence or absence of "." in the expression.  The
only difference is the context in which the offset is applied.  In two
of the cases, (*xp).i and xp->i, there is an explicit indirection,
which is the overloadable operation.  In the case of "xr.i" there is
deliberate ambiguity as to whether an indirection occurs; a reference
may be, but need not be, implemented by a pointer.

The point of this exercise was to demonstrate that, semantically, the
builtin "." only provides qualification for the right hand side --
i.e., an addressing context and a scope in which the right hand side
can be looked up to determine "the appropriate offset" for the
interpretation.  This is exactly what "::" -- or even the absence of
qualification -- does.  I don't imagine this analysis will convince
you, but perhaps you can at least acknowledge that this interpretation
of builtin "." is simple and self-consistent.  To my mind, this
"objection" -- that "." isn't like the overloadable operators -- still
stands.

> |      2) Your operator.() proposal continues to require forwarding functions
> |         for member operators and conversion operators in the target class,
> |         even though the requirement of forwarding functions was one of the
> |         most significant criticisms you advanced against the status quo.
> 
> My operator.() proposal DOES NOT require forwarding functions unless
> the implementor of the reference class DESIRES to use forwarding functions.

But the same can be said of the current situation -- you only have to
provide forwarding functions for those features of the target class
you desire to use.  The "objection" still stands.

> |      3) Your operator.() proposal requires use of circumlocutions to access
> |         members of the smart reference object.
> 
> My proposal DOES NOT require use of circumlocutions to access members of
> the smart reference object.  Circumlocations are POSSIBLE, if the implementor
> of the reference class so desires.

This is the same sort of semantic dancing as the previous point; the
fact is that, under your proposal, you must use a circumlocution to
access members of the smart reference object.  The "objection" still
stands.

> |My position on
> |your proposal is based on these points, not on a comparison with some
> |semi-mythical "better proposal."
> 
> Then I suggest:
> 
> 1) get your facts right, lest your position be based on errors.

Thanks for your concern; my facts are in pretty good shape.

> 2) you stop saying your ideas are "better" than my proposal

That's not what I said.  What I said was that the two alternatives I
mentioned did not have these three particular disadvantages of your
proposal but that I had not fully explored them.  They may, in fact,
have far worse disadvantages than your proposal (indeed, as I pointed
out in my most recent posting, the reference-conversion idea isn't
even completely free of these disadvantages, since it requires
forwarding functions for conversion functions in the target).  That's
why I posted, to get people to shoot holes in the ideas.  It would
definitely be premature to claim that either is "better" than your
proposal, and I haven't done so.

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