[comp.lang.c++] Overloaded operator dot?

dfoster@jarthur.Claremont.EDU (Derek R. Foster) (03/11/91)

I have heard a few references lately to the possibility of adding to c++
an overloadable operator dot. I have a few questions about this:

1) Is the committee seriously considering this right now, or is this just
   a suggestion? If they are considering it, what are the chances of it
   passing?
2) If this suggestion is actually used, what is the syntax to invoke
   the normal (un-overloaded) dot operator?

Thanks for any information!

Derek Riippa Foster

horstman@mathcs.sjsu.edu (Cay Horstmann) (03/11/91)

In article <11152@jarthur.Claremont.EDU> dfoster@jarthur.Claremont.EDU (Derek R. Foster) writes:
>I have heard a few references lately to the possibility of adding to c++
>an overloadable operator dot. I have a few questions about this:
>
>1) Is the committee seriously considering this right now, or is this just
>   a suggestion? If they are considering it, what are the chances of it
>   passing?

No idea...

>2) If this suggestion is actually used, what is the syntax to invoke
>   the normal (un-overloaded) dot operator?
>
I guess one could always recover the original meaning by writing 
(&x)->m or this->m. Note that the -> applies to a pointer and hence
cannot be redefined. By redefining operator& (unary), the first 
method may no longer work. In that case, the actual class members
could only be used inside other member functions. Even if no member 
functions can be launched explicitly (because x.f() no longer means
to call X::f() on x), some member functions can still be activated
through constructors, destructors, overloaded operators and virtual
functions. Inside those member functions, members can be accessed
as this->m or simply m. Note that only the members of "this" can be
accessed like that, not the members of any other object of the same class.

What are the reasons AGAINST allowing overloading operator.? 

Cay

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

In article <11152@jarthur.Claremont.EDU> dfoster@jarthur.Claremont.EDU (Derek R. Foster) writes:
|I have heard a few references lately to the possibility of adding to c++
|an overloadable operator dot. I have a few questions about this:
|
|1) Is the committee seriously considering this right now, or is this just
|   a suggestion? If they are considering it, what are the chances of it
|   passing?

I wrote this up as a formal request for review some months ago.  Bjarne
wrote me last week saying that the idea was still under consideration,
and that he likes the idea.  How seriously anyone else takes the idea
I cannot say.  I am encourage by the number of people finding good uses
for it recently.

|2) If this suggestion is actually used, what is the syntax to invoke
|   the normal (un-overloaded) dot operator?

Operator dot works very similarly to operator point, as a starting point.
Like the other overloaded operators, operator dot isn't ever implicitly
invoked -- if you don't explicitly type a dot, you don't get an invocation
of operator dot.  Smart reference classes, like smart pointer classes,
are typically pretty simple things.  Thus, the easiest way to keep from
invoking operator dot when you don't want it [during the construction
of your smart reference class] is simply to specify the required members
without adornment -- which gives you the standard implicit "this->"
prefix.  Other "tricks" to avoid "accidentally" getting the overloaded
operator dot include implementing some of your smart reference class in 
a private superclass, and only introduce the operator dot in the subclass,
or perhaps doing a (&smartRef)->doSomething();

steve@taumet.com (Stephen Clamage) (03/17/91)

dfoster@jarthur.Claremont.EDU (Derek R. Foster) writes:

>I have heard a few references lately to the possibility of adding to c++
>an overloadable operator dot. I have a few questions about this:

>1) Is the committee seriously considering this right now, or is this just
>   a suggestion? If they are considering it, what are the chances of it
>   passing?
>2) If this suggestion is actually used, what is the syntax to invoke
>   the normal (un-overloaded) dot operator?

The ANSI C++ Committee (X3J16) met from 11-15 March, and the issue of
overloading the dot operator was discussed.  The working group
responsible for evaluating extensions to the language presented a summary
of their deliberations, and concluded that the issue requires more study.

For any suggested addition or change, an important set of questions:
Q1. Will any currently-legal programs be affected?
Q2. What current functionality will be lost?
Q3. What functionality will be added to the language which is not now
    conveniently available?  (What problem does this solve?)
Q4. Do the benefits in Q3 make up for the costs in Q1 and Q2?
(This is not a formal Committee procedure, but just some things which
need to be considered.)

The working group said it had not reached a conclusion on Q3 in particular.

If adopted, operator dot would probably be analogous to operator arrow.
It would have to return a class or reference to a class on which either
operator dot was defined, or which had a member corresponding to the name
on the right side of the original dot.  Given this, there would be no
way to use the ordinary dot on a class with operator dot, just as there
is no way to use the ordinary arrow on a class with an operator arrow.

In particular, you would not define both operator dot and operator arrow
for the same class.  The result would be unmanageable.  Defining either
affects the normal guarantee that given
	class C { ... public: int m; ... } c, *pc;
then
	(&c)->m
	c.m
	pc->m
	(*pc).m
are all equivalent.
p->m and (*p).m are equivalent.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

horstman@mathcs.sjsu.edu (Cay Horstmann) (03/18/91)

In article <624@taumet.com> steve@taumet.com (Stephen Clamage) writes:
>
>In particular, you would not define both operator dot and operator arrow
>for the same class.  The result would be unmanageable.  

I don't think that is true at all. First of all, inside a MEMBER FUNCTION
of X (a class with both operators . and -> overloaded), you could still access
the members. That should be sufficient for implementing such very specialized
classes. Furthermore, if X::operator& is not redefined, member access is
still possible through (&x)->m, since -> cannot be overloaded for the pointer
type X*. 

I am NOT saying that operator. should necessarily be overloadable just because
it can be done. Just that the most common argument ("it would be a mess to
access members") doesn't hold water. Just out of curiosity: has the working
group identified any code that would break if operator. overloading was 
permitted? (Stephen cited that as one important task of the working group.)

The most important question is of course: Does it solve any problems? Recently
it was generally agreed that it would be useful for defining an access class
which can be both an lvalue and an rvalue. Is anyone aware of another use for
it?

Cay

dsr@mir.mitre.org (Douglas S. Rand) (03/18/91)

In article <1991Mar17.184122.717@mathcs.sjsu.edu>, horstman@mathcs.sjsu.edu (Cay Horstmann) writes:
> In article <624@taumet.com> steve@taumet.com (Stephen Clamage) writes:
> >
> >In particular, you would not define both operator dot and operator arrow
> >for the same class.  The result would be unmanageable.  
> 
> I don't think that is true at all. First of all, inside a MEMBER FUNCTION
> of X (a class with both operators . and -> overloaded), you could still access
> the members. That should be sufficient for implementing such very specialized
> classes. Furthermore, if X::operator& is not redefined, member access is
> still possible through (&x)->m, since -> cannot be overloaded for the pointer
> type X*. 
> 
> I am NOT saying that operator. should necessarily be overloadable just because
> it can be done. Just that the most common argument ("it would be a mess to
> access members") doesn't hold water. Just out of curiosity: has the working
> group identified any code that would break if operator. overloading was 
> permitted? (Stephen cited that as one important task of the working group.)
> 
> The most important question is of course: Does it solve any problems? Recently
> it was generally agreed that it would be useful for defining an access class
> which can be both an lvalue and an rvalue. Is anyone aware of another use for
> it?
> 
> Cay

Yes,  it would allow the creating of true persistent objects where there was
little, if any, programmer overhead of dealing with them.

To explain;  the persistent object implementations I've done all require me to
explicitly force the loading of an object either at construction time or before
the first access.  Lazy loading of objects is then very difficult and for a large
system one definitely wants to load objects on a "as needed" basis.

When a programmer modifies an object one needs to update a writeback list or directly
store the instance.

With overloaded "." one can check for the load state of the persistent instance on
access and automatically load the instance.  This is much cleaner.  With overloaded
"." as an lvalue one can increment writeback lists automatically or store through to
the database.

-- 
Douglas S. Rand 
Internet:   <dsrand@mitre.org>
Snail:	    MITRE, Burlington Road, Bedford, MA 
Disclaimer: MITRE might agree with me - then again...
Amateur Radio: KC1KJ

jbuck@galileo.berkeley.edu (Joe Buck) (03/21/91)

In article <624@taumet.com>, steve@taumet.com (Stephen Clamage) writes:
> The ANSI C++ Committee (X3J16) met from 11-15 March, and the issue of
> overloading the dot operator was discussed.  The working group
> responsible for evaluating extensions to the language presented a summary
> of their deliberations, and concluded that the issue requires more study.

> For any suggested addition or change, an important set of questions:
> Q1. Will any currently-legal programs be affected?
> Q2. What current functionality will be lost?

No and no.  The change has no effect on any working program (but I suppose you
knew that and are just asking the "standard set of questions") since
existing programs call "operator ." a syntax error.

|> Q3. What functionality will be added to the language which is not now
|>     conveniently available?  (What problem does this solve?)

The new functionality is the ability to have "smart references".  The
semantics parallels the semantics for "smart pointers" obtained by overloading
operator -> and should have the same restrictions.

The new text would read

"Class member access using .

	primary-expression . primary-expression

is considered a unary operator.  An expression x.m is interpreted as
(x.operator.()).m for a class object x (here the first "." is the
builtin "." -- perhaps I should write ((&x)->operator.()).m to be
unambiguous).  It follows that operator.() must return either a reference
to a class or an object of, or reference to a class for which
operator.() is defined.  operator.() must be a nonstatic member function."

|> Q4. Do the benefits in Q3 make up for the costs in Q1 and Q2?

Since there are no costs in Q1 and Q2, obviously.  Of course, there is
a cost for compiler writers, and a cost for the standards committee.

|> If adopted, operator dot would probably be analogous to operator arrow.
|> It would have to return a class or reference to a class on which either
|> operator dot was defined, or which had a member corresponding to the name
|> on the right side of the original dot.  Given this, there would be no
|> way to use the ordinary dot on a class with operator dot, just as there
|> is no way to use the ordinary arrow on a class with an operator arrow.

I agree.  The wording should be the same as what appears in 13.4.6 of the ARM,
except that where "pointer" appears "reference" should be substituted.

|> In particular, you would not define both operator dot and operator arrow
|> for the same class.  The result would be unmanageable.

I agree that in practice, an object will either behave as a smart reference
or a smart pointer and not both, but I don't think the compiler should
enforce this restriction.  It's still possible for an object to refer
to its own members within member functions without mentioning either the
. or -> operator.  When teaching someone the language, though, I'd discourage,
STRONGLY, redefining both for the same object.

Smart references will make it easier to write garbage collectors (though
the C-compatible array semantics can leave holes in the scheme).


--
Joe Buck
jbuck@galileo.berkeley.edu	 {uunet,ucbvax}!galileo.berkeley.edu!jbuck	

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

jbuck@galileo.berkeley.edu (Joe Buck) writes:
> |> Q3. What functionality will be added to the language which is not now
> |>     conveniently available?  (What problem does this solve?)
>
> The new functionality is the ability to have "smart references".  The
> semantics parallels the semantics for "smart pointers" obtained by overloading
> operator -> and should have the same restrictions.

That doesn't answer the question -- all you've done is to give the new
feature a name.  The real issue is whether the technique solves any major
problems that can only be addressed awkwardly or not at all in the existing
language.  In other words, give some specific applications that demonstrate
that "smart references" aren't just another of the hundreds of nifty ideas
floating around that are cute and interesting but don't really expand the
power of the language to address real-world problems.

To give an example, exception handling was added to the language because
there simply is no way without it safely to employ a non-local goto to
terminate a failing operation.  As a negative example, generalized
overriding (aka "renaming") was a very attractive feature that was rejected
in large measure because a fairly straightforward programming technique was
discovered that solved the problem to which the extension was originally
addressed.

For instance, one proposed use of operator.() given in this newsgroup a
short while ago was to implement auxiliary classes used as the return type
of operator[]().  It's not apparent to me, at least, that defining
operator.() in such a class is sufficiently superior to the alternate
technique of coding any necessary forwarding functions directly into the
auxiliary class.  In fact, addressing the original problem (detecting the
difference between lvalue and rvalue use of the result of operator[]()) will
require coding some glue functions into the intermediate class to allow the
desired separation between lvalue and rvalue operations, so the relative
value of operator.() for such an application is reduced even further.

> |> Q4. Do the benefits in Q3 make up for the costs in Q1 and Q2?
>
> Since there are no costs in Q1 and Q2, obviously.  Of course, there is
> a cost for compiler writers, and a cost for the standards committee.

Actually, those aren't the only costs; some of the conceptual unity of the
language will be lost if operator.() is adopted.  For one thing, it is
currently absolutely guaranteed that, if you see "foo.bar" in a program,
"bar" is a member of the class of which "foo" is an object.  That guarantee
will be broken if operator.() is adopted; you'll have to look at the
definition of the class of "foo" in order to know what the expression means.

Perhaps more important is the fact that a fundamental identity in the
language will be broken.  In at least the form of the proposal I have seen
(although there are others, I believe), "p->m" and "(*p).m" are no longer
equivalent by definition if "p" is a pointer to a class in which operator.()
is defined.  This is the only case in which a fundamental C identity is
broken for a non-class type (a pointer to a class object is a built-in type,
not a user-defined type).

These are non-trivial costs, at least to me, even if they can't be evaluated
in terms of number of lines of code requiring modification.  Don't get me
wrong, here; I'm not fundamentally or irrevocably opposed to the idea of
operator.(), I just want to be sure that there are good, solid reasons for
adopting it beyond "it sure is a nifty idea."

> Smart references will make it easier to write garbage collectors (though
> the C-compatible array semantics can leave holes in the scheme).

This sounds promising, like what I was asking for above.  What do smart
references buy that smart pointers don't with respect to garbage collection?

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

steve@taumet.com (Stephen Clamage) (03/22/91)

jbuck@galileo.berkeley.edu (Joe Buck) writes:

>In article <624@taumet.com>, steve@taumet.com (Stephen Clamage) writes:
>|> Q3. What functionality will be added to the language which is not now
>|>     conveniently available?  (What problem does this solve?)

>The new functionality is the ability to have "smart references".  The
>semantics parallels the semantics for "smart pointers" obtained by overloading
>operator -> and should have the same restrictions.

Aha!  But is this in fact "new functionality"?  What is the difference
between a smart pointer and a smart reference in terms of the kinds of
programming you can do and the code you have to write to do it?  It was
not clear to the group looking into the issue that there was a
significant difference, or that it justified the added complexity in
the language.  On the other hand, it was not clear that the idea should
be rejected either.  That is why they recommended further study.

(As an aside, I am not part of the group investigating this issue, nor
do I have strong feelings about it either way.)
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

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

In article <1991Mar17.184122.717@mathcs.sjsu.edu> horstman@mathcs.sjsu.edu (Cay Horstmann) writes:
|The most important question is of course: Does it solve any problems? Recently
|it was generally agreed that it would be useful for defining an access class
|which can be both an lvalue and an rvalue. Is anyone aware of another use for
|it?

Overloaded operator dot is for all practical purposes necessary in order
to be able to make "smart reference classes" just as today one can make
"smart pointer classes."  The question then becomes why would one prefer
to use "smart reference classes" over "smart pointer classes"  ???

[I use the term "smart" here in a very loose sense.  By a "smart pointer
 class" I really mean any class that is implemented to act as if it is 
 a pointer -- whether that class does anything intelligent, or simply
 forwards all requests to the pointed-at object is immaterial to my 
 discussion.  The same holds true for "smart reference classes"]

Two situation where "smart reference classes" are clearly preferrable
to "smart pointer classes" are: 1) when such an object has to act like
a value, and 2) when such an object has to act like a normal object.

[A simpler way to say this would be to state that smart reference classes
 are always preferred to smart pointer classes -- except when you're trying
 to make a pointer class -- but that sounds like a circular argument.]

Lets see how this might be used.  First case is when a smart reference
class has to act like a value.  Matrices have been a hot topic recently --
let's consider how one would make a reference counted matrices class.
Lets call the class that implements the actual storage requirements and
reference count of the matrices the ActualMatrix class, and have the
smart reference class simply called Matrix -- in order to hide implementation
details from the end users.  We want to be able to write code like this:

Matrix ReadANewMatrix(int row, int col)
{
	Matrix A(row, col);

	for (int i=0; i<row; ++i)
		for (int j=0; j<col; ++j)
			A[i][j] = ReadAValue();
	return A;
}

Remember that Matrix is actually a smart reference class -- when a Matrix
is constructed, an ActualMatrix is being created in the background off
of heap.  The Matrix copy-constructor and assignment simply adjust the
reference count in ActualMatrix.  [I'll leave the details of when, if ever,
separate copies of ActualMatrixes are generated to the discretion of the
reader.]

If its not obvious to you why you wouldn't want to use a smart pointer
implementation instead, consider how such an implementation ought to 
look in order to mimic pointers:

MatrixPtr ReadANewMatrix(int row, int col)
{
	MatrixPtr A = new ActualMatrix(10, 20)

	for (int i=0; i<row; ++i)
		for (int j=0; j<col; ++j)
			(*A)[i][j] = ReadAValue();
	return A;
}

Which doesn't do nearly as good a job of hiding the abstraction.  A similar
case would be reference counted string classes.

The second case where "smart reference classes" are preferred to smart
pointer classes is when you want the implementation details to be hidden.
If you make a class Foo which delegates a portion or all of its actual
work to Bar, do you really want to make it clear that this delegation
is being performed, or is the delegation an implementation
detail for Foo that should remain hidden?  If the implementor of Foo want
to hide the delegation [and more than a couple methods are being delegated]
then you really need operator dot, so that you can just say: "delegate 'all'
these methods to Bar."  Consider the case of a named object that's huge,
knows its huge, and thus tries to keep its representation on disc most of
the time:

Class  TryToBeDiscResident : public ThingsProtocol
{
	FileName fileName;	// where to find the object when *its not*
				// in memory!

	Thing* p;		// where to find the object when *it is* in 
				// memory!
public:
	Thing& operator.();
	....
};

Thing& TryToBeDiscResident::operator.()
{
	if (p == NULL)
	{
		p = GoGetThingFrom(fileName);
	}

	return *p;

}

[I'll leave it to the reader to decide when and how Things that 
TryToBeDiscResident take themselves back out of memory and onto disc.]

Note that its possible to create "smart reference classes" today -- even
without overloadable operator dot -- and lots of people are creating
such smart reference classes -- its just that to do so requires the
author to manually write a "trivial" [but annoying] forwarding method
for each and every method in the protocol to be forwarded, and afterwards
to manually provide software maintanence to keep all those forwarding
methods up-to-date.  Whereas is overloadable operator dot is supported,
not only is it not necessary to manually write all the forwarding 
methods -- in many situations one could use a standard "smart reference
class" template to do "all" the work for you.

In summary: I believe overloadable operator dot is *at least* as useful as
overloadable operator->, and is necessary if you want to be able to use
templates to make smart reference classes.

gintera@fsd.cpsc.ucalgary.ca (Andrew Ginter) (03/23/91)

In article <71437@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:
> ... Consider the case of a named object that's huge,
>knows its huge, and thus tries to keep its representation on disc most of
>the time:
>
>Class  TryToBeDiscResident : public ThingsProtocol
>{
>	FileName fileName;	// where to find the object when *its not*
>				// in memory!
>
>	Thing* p;		// where to find the object when *it is* in 
>				// memory!
>public:
>	Thing& operator.();
>	....
>};
>
>Thing& TryToBeDiscResident::operator.()
>{
>	if (p == NULL)
>	{
>		p = GoGetThingFrom(fileName);
>	}
>
>	return *p;
>
>}
>
>[I'll leave it to the reader to decide when and how Things that 
>TryToBeDiscResident take themselves back out of memory and onto disc.]

This implementation of an overloaded "dot" operator may be ultimately
useful.  I'm not arguing that point.  A straightforward implementation
of such an overloading mechanism however, in the style of existing
support for smart pointers, will suffer from the same serious flaws
that existing smart pointer support suffers.  Taking your example, a
programmer may wish to write something which appears perfectly
reasonable:

     int do_stuff ();
     X.a = do_stuff ();

The current C++ language definition does not define the order of
evaluation of the assignment expression.  If the LHS is evaluated
first, the Thing to which X refers is brought into memory (if it
wasn't there already) and the emitted code may obtain a pointer to the
"a" element in this thing.  The intent being that the RHS would then
be evaluated and the result assigned to "X.a" through this pointer
which was perhaps stored in a processor register across the call to
do_stuff.

The problem with this expression is that do_stuff may do something
which causes the Thing to which X refers to be flushed back to disk.
The subsequent assignment through the stored pointer does not update
the disk-resident Thing, it updates the memory the Thing used to
occupy.  

This problem and similar problems which arise in smart pointers can be
solved by further modifying the language definition to correct these
order of evaluation problems.  For a detailed discussion of this
problem and its solution, see my technical report No. 91/417/01.  The
report is available as the compressed ".dvi" file 

  DUA3:[ANONYMOUS.PUB.TECH]CPSC-91-417-01-DVI.Z

from ucnet.ucalgary.ca.  Hard copies can be ordered from the CS dept
at (403) 220-6015.

Andrew Ginter, 403-220-6320, gintera@cpsc.ucalgary.ca

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

In article <1991Mar11.061204.6023@mathcs.sjsu.edu> horstman@mathcs.sjsu.edu (Cay Horstmann) writes:
+In article <11152@jarthur.Claremont.EDU> dfoster@jarthur.Claremont.EDU (Derek R. Foster) writes:
+>I have heard a few references lately to the possibility of adding to c++
+>an overloadable operator dot. I have a few questions about this:
+>
+>1) Is the committee seriously considering this right now, or is this just
+>   a suggestion? If they are considering it, what are the chances of it
+>   passing?

It is being considered seriously by x3j16.

+>2) If this suggestion is actually used, what is the syntax to invoke
+>   the normal (un-overloaded) dot operator?
+>
+I guess one could always recover the original meaning by writing 
+(&x)->m or this->m. Note that the -> applies to a pointer and hence
+cannot be redefined.

In order to understand how this would work, I think that you would have
to look at the whole proposal.  I'm not sure, but I think that the idea
is to allow something like:

	expression.expression

If that is true, then this would be a lot different from the normal way
that thinsg work with ".".  In particular, you normally have to have
the name of a member (or the proper type) to the right of the dot.  The
thing to the right of the dot cannot be a general expression (as of now).
I believe that the "overloadable dot" proposal might change that, but
don't quote me.

+What are the reasons AGAINST allowing overloading operator.? 

I have said this over and over again, but either the "overloadable dot"
proposal is something radically different from what I think it is or
else some people are choosing to ignore some very basic facts.  (If it
is the latter...  well...  there would be nothing particularly new
about that!)

The bare fact of the matter (as I have said many times) is that "." is
plainly not an operator (either unary or binary).  It is a selector.

The C and C++ languages allow the thing on the left of the "." to
be an expression (of some struct/class type) but the thing on the
right is NOT an expression, rather it must be the name of a member
of the thing on the left.

In effect, dot acts a bit like the other "scope opener" that we know
about in C++, i.e. the colon-colon.  These things are plainly NOT
operators.  People who are just learning the language (as well as
experienced users) will just get more and more confused (when trying
to read code) if we start to bend the "normal" rules regarding what may
and may not be overloaded (or treated like an operator).

I have previously noted that allowing overloading for "." makes about as
much sense as allowing overloading for "{".  In both cases the very
idea appears ridiculous, however I actually read a response from one
person who said that (maybe) allowing overloading for "{" would be
a useful and good thing!!!

I guess the bottom line is this.  What is your opinion regarding how
a language should be designed?  Should it be an unbridled, nonsensical
and chaotic mismash of random "bright ideas" which seem like they might
occasionally have some obscure usefulness, or should there be some
rules, some guiding principals, and some *consistancy* in the set of
features provided by a language?

I feel that the design of C++ ought to have followed the simple (and
consistant) rule that overloading would only be allowed for things which
really are "operators".  Some people don't like to be bound by such
trivial concerns as "consistancy" however.  Some folks prefer the
"everything *including* the kitchen sink" approach to language design.
For those people, I have but one question.  Why stop with overloading "."?
Why not allow overloading for "{" and "}"?  What about overloading ":"
and/or "::"?  Come to think of it... why stop at just the tokens formed
from "special characters"?  Why not allow overloading of keywords?

If you are going to have an unconstrained free-for-all, why not go all
the way?
-- 

// 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.

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

In article <12193@pasteur.Berkeley.EDU> jbuck@galileo.berkeley.edu (Joe Buck) writes:
>
>|> Q3. What functionality will be added to the language which is not now
>|>     conveniently available?  (What problem does this solve?)
>
>The new functionality is the ability to have "smart references".  The
>semantics parallels the semantics for "smart pointers" obtained by overloading
>operator -> and should have the same restrictions.

[... stuff deleted ... ]

>Smart references will make it easier to write garbage collectors (though
>the C-compatible array semantics can leave holes in the scheme).

Horse pucky!  Prove it!

I claim that even if you *had* your so-called "smart references" today,
there is absolutely nothing that you could do with them that you could
not do just as well using only "smart pointers".

I also claim that there is nothing that you could do significantly *easier*
with "smart references" than you could with just smart pointers.

If you have a counterexample I encourage you to post it and prove me wrong.
(Post the code please.  Hemming and hawing in flowery prose will not help
to make the point either way.)



-- 

// 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.

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

rfg@NCD.COM (Ron Guilmette) writes:
> In order to understand how this would work, I think that you would have
> to look at the whole proposal.  I'm not sure, but I think that the idea
> is to allow something like:
>
>         expression.expression
>
> If that is true, then this would be a lot different from the normal way
> that thinsg work with ".".  In particular, you normally have to have
> the name of a member (or the proper type) to the right of the dot.  The
> thing to the right of the dot cannot be a general expression (as of now).
> I believe that the "overloadable dot" proposal might change that, but
> don't quote me.

Good advice.  The proposal that is most actively under discussion has the
same restriction on what follows overloaded "." as the current language
places on what follows overloaded "->", i.e., it has to be a member of
whatever class the left-hand side eventually resolves to.  (Like
operator->() might return an object with operator->() defined, operator.()
might return an object with operator.() defined; following the chain of
results must eventually produce something to which the built-in "->" or "."
can be applied.)

> The bare fact of the matter (as I have said many times) is that "." is
> plainly not an operator (either unary or binary).  It is a selector.

The counter argument is that, if you can create a user-defined type that
acts like a pointer, which you can -- even without operator->(), if you're
willing to live only with the unary * notation -- why shouldn't you be able
to create a user-defined type that acts like a reference?  And if you do,
why should the syntax differ from that used with built-in references?  And
if the syntax is the same, what should you write as an operator in your
smart reference class to be invoked when you say "foo.bar"?

I agree that "." is _not_ an operator as I think of operators.  I just don't
have a better suggestion for how to write a smart reference class.

(In case anyone is confused by my postings on the subject, which appear to
blow both hot and cold on the idea of smart references, I have no
insuperable objections to the feature but have not yet been convinced that
there is enough of a need to override the minor concerns I have and my
desire not to fiddle with the language to add every "bright idea" that comes
along.)

>                                               should there be some
> rules, some guiding principals,

There have always been "guiding principals" (Bjarne and crew originally, now
X3J16); I think there have generally been guiding _principles_ as well.
(Sorry for the "principal/principle" pun, but I couldn't resist. :-)

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

gyro@kestrel.edu (Scott Layson) (03/26/91)

In article <4610@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
>I claim that even if you *had* your so-called "smart references" today,
>there is absolutely nothing that you could do with them that you could
>not do just as well using only "smart pointers".
>
>I also claim that there is nothing that you could do significantly *easier*
>with "smart references" than you could with just smart pointers.
>
>If you have a counterexample I encourage you to post it and prove me wrong.
>(Post the code please.  Hemming and hawing in flowery prose will not help
>to make the point either way.)

Here's something I actually tried to do, with encouragement from an
experienced C++ programmer, and ran head-on into the absence of
overloadable `.'.

I wanted to be able to define "active slots" of objects -- sortof like
member variables, but with the option of running arbitrary code when
the slot was read or written.  (This idea was inspired by other
object-oriented systems I have used.)  So, let's say I have an object
`foo', of class `Frob', with a slot `name' of type `symbol'; I want to
be able to use the expression `name(foo)' to read the name, and
`name(foo) = bar' to write it (there was a reason why I used
`name(foo)' rather than `foo.name()', but it doesn't matter here).

The way I went about this was to create a class called `_Frob_name'
(these declarations were being automatically generated, by the way)
such that 1) the implicit conversion from `_Frob_name' to `symbol'
(the type of the `name' slot) would run the "read demons", and 2)
`_Frob_name::operator=' was overloaded to run the "write demons".  The
declarations to accomplish this are not hard to generate, but since
you ask, they look basically like this:

class Frob {
     // whatever private members
  public:
     friend class _Frob_name;
     friend _Frob_name name(Frob);
};

class _Frob_name {
     Frob _Frob;
     _Frob_name(Frob f) { _Frob = f; }
  public:
     friend name(Frob);
     operator symbol();
     symbol operator=(symbol);
};

inline _Frob_name name(Frob f)
{
     return _Frob_name(f);
}

_Frob_name::operator symbol()
{
     // run "read demons"
     symbol& val = // however you get a reference to the `name' of _Frob
     return val;
}

symbol _Frob_name::operator=(symbol s)
{
     // run "write demons"
     symbol& val = // however you get a reference to the `name' of _Frob
     val = s;
     return s;
}


The problem, anyhow, is that (supposing `symbol' has a member function
`hash') I can't say `name(foo).hash()'.

Could I have made this work by using pointers to the intermediate
class `_Frob_name' instead of instances thereof?  No, because then I
couldn't overload `operator='.

-- Scott Layson Burson
Gyro@Reasoning.COM

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

In article <1991Mar21.032937.16534@world.std.com> wmm@world.std.com (William M Miller) writes:
|That doesn't answer the question -- all you've done is to give the new
|feature a name.  The real issue is whether the technique solves any major
|problems that can only be addressed awkwardly or not at all in the existing
|language.  In other words, give some specific applications that demonstrate
|that "smart references" aren't just another of the hundreds of nifty ideas
|floating around that are cute and interesting but don't really expand the
|power of the language to address real-world problems.

I disagree.  On the contrary, I believe Joe Buck, myself, and others
have repeatedly shown what the problem is.  But, when we place all the problems
we've found into one category which we label "smart references" some
people argue that we're just applying a name to a category we've made up.  
And then when we show specific short examples of the problem then people 
argue that the examples we give are academic and give hack work-arounds.

Even if it *were* true that people can do things similar to smart 
references with smart pointers [albeit at the cost of customers having to 
guess whether to use pointer or dot syntax everywhere] why should it be 
that throughout the C++ languages people have the choice  
to either use pointers or references --

-- EXCEPT when it comes to operator overloading?

Why not just make the language orthogonal and say that its up to the 
programmer to decide when its appropriate to use pointers, and when
its appropriate to use references?  Why in this one obscure case in the
language try to mandate some people's preference of pointers over references?
Why defend an exceptional case, when it can be easily removed?

dgil@pa.reuter.COM (Dave Gillett) (03/26/91)

In <1991Mar21.032937.16534@world.std.com> wmm@world.std.com (William M Miller) writes:

>jbuck@galileo.berkeley.edu (Joe Buck) writes:
>> |> Q3. What functionality will be added to the language which is not now
>> |>     conveniently available?  (What problem does this solve?)

>That doesn't answer the question -- all you've done is to give the new
>feature a name.  The real issue is whether the technique solves any major
>problems that can only be addressed awkwardly or not at all in the existing
>language.  In other words, give some specific applications that demonstrate
>that "smart references" aren't just another of the hundreds of nifty ideas
>floating around that are cute and interesting but don't really expand the
>power of the language to address real-world problems.


     Without the facility to overload operator., one must resort to code like

                 (&f)->thing

to get the equivalent, and overload operator->.  Without overloading of 
operator->, we know that this is equivalent to writing

                 f.thing

and it would be "really really nice" (i.e. highly desirable) to be able to
guarantee to users of a class that this equivalence holds, even if the
operators are overloaded.  [i.e.  I would prefer that for any class where
operator-> is overloaded, operator. would be overloaded to preserve this
equivalence; leave it up to the user of the class whether they want to use
an f or an f*.]

                                              Dave

daves@ex.heurikon.com (Dave Scidmore) (03/27/91)

In article <71516@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:
>
>I disagree.  On the contrary, I believe Joe Buck, myself, and others
>have repeatedly shown what the problem is.`

In following this discussion I have noticed that most of these examples
start with the statement "I want to design some set of objects to do X and
I want to do this by using langauge feature Y in this way". It do not believe
that there is any meaning in showing that given a contrived set of
circumstances the language can not meet the needs of your program. To do so
is to expect the language to be all things to all people. What is important
is whether their is a solution set for your problem, without any contrived
conditions or usages of language features, which maps cleanly to your problem.
I believe that with some effort a clean approach that does not require
modification of the language is possible for every one of the examples given
so far. That solution starts with rethinking how you want to achieve the end
result and picking an approach that is a good fit with existing language
features.

>But, when we place all the problems
>we've found into one category which we label "smart references" some
>people argue that we're just applying a name to a category we've made up.

Since "f.thing" and "(&f)->thing are equivilent in a sense smart references
already exist. If you think of "f->thing" as being equivelent to "(*f).thing"
then it becomes clear why "->" is was originaly made overloadable and "."
was not. Since overloading of "*" is allowed how do you overload the implicit
"*" in "f->thing" (i.e. (*f).thing). The method chosen was to allow
overloading of "->". Since "." has not implicit dereference overloading was
not needed.

>And then when we show specific short examples of the problem then people 
>argue that the examples we give are academic and give hack work-arounds.

I for one do not think using "(&f)->thing" is a hack workaround. It is
quite clear to me what is intended.

>Why not just make the language orthogonal and say that its up to the 
>programmer to decide when its appropriate to use pointers, and when
>its appropriate to use references?  Why in this one obscure case in the
>language try to mandate some people's preference of pointers over references?
>Why defend an exceptional case, when it can be easily removed?

One reason I have seen given (you must have missed it) is that it alters
the syntax of the language in ways that make it hard to predict the outcome.
Currently "expression.expression" is not allowed, your change would make
it allowable. If this creates side effects then its removal will be far from
easy.
--
Dave Scidmore, Heurikon Corp.
dave.scidmore@heurikon.com

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

In article <1991Mar22.172215.20521@cpsc.ucalgary.ca> gintera@fsd.cpsc.ucalgary.ca (Andrew Ginter) writes:

|The current C++ language definition does not define the order of
|evaluation of the assignment expression.  If the LHS is evaluated
|first, the Thing to which X refers is brought into memory (if it
|wasn't there already) and the emitted code may obtain a pointer to the
|"a" element in this thing.  The intent being that the RHS would then
|be evaluated and the result assigned to "X.a" through this pointer
|which was perhaps stored in a processor register across the call to
|do_stuff.
|
|The problem with this expression is that do_stuff may do something
|which causes the Thing to which X refers to be flushed back to disk.
|The subsequent assignment through the stored pointer does not update
|the disk-resident Thing, it updates the memory the Thing used to
|occupy.  

Like I said, I leave it to the reader to determine when a good time
to flush X back to disk.

One strategy for when to flush back to disk is to wait till program
termination.  In which case the overloaded operator dot is being
used to implement a deferred load.  [See Wirth's comments regards
deferred loading in the Oberon System, for example]

----

Again, the problem I see is that when I or others post short, acedemic
examples of using operator dot, people attack the examples as being
acedemic, whereas if we generalize the use of operator dot and call
that generalization "smart references" then people accuse us of
applying a name to a "non-problem."

Really, the only significant difference between overloaded operator dot and
operator-> is the syntax presented to the end user.  If ANSI-C++
committee members consider it a "good thing" for end users to have
to guess whether to use "." or "->" in any given situation, then
overloaded operator-> suffices.  However, if the ANSI-C++ committee 
members consider it a "good thing" that the historical use of "."
be maintained when manipulating values, whereas "->" be used when
manipulating "pointed-to" things, then the committee members should
give us overloaded operator dot so that we can make that distinction --
so that we can use "." when we write classes that act like values, and
we can use "->' when we write classes that act like pointers.

But, if the committee members no longer consider the distinction
between "." and "->" important, then how about removing the distinction 
completely from the language, and let the compiler distinguish from context
which is meant [please note that this is a rhetorical argument :-]

I claim the distinction between values and references remains important
in C++, as does the distinction between "." and "->"

Therefore, the ANSI-C++ committee members ought to give us the necessary
tools to write classes using either syntax.

jimad@microsoft.UUCP (Jim ADCOCK) (04/02/91)

In article <1991Mar25.154128.4138@world.std.com> wmm@world.std.com (William M Miller) writes:
Newsgroups: comp.lang.c++
Subject: Re: Overloaded operator dot?
Summary: 
Expires: 
References: <11152@jarthur.Claremont.EDU> <1991Mar11.061204.6023@mathcs.sjsu.edu> <4607@lupine.NCD.COM> <1991Mar25.154128.4138@world.std.com>
Sender: 
Reply-To: jimad@microsoft.UUCP (Jim ADCOCK)
Followup-To: 
Distribution: 
Organization: Microsoft Corp., Redmond WA
Keywords: 

In article <1991Mar25.154128.4138@world.std.com> wmm@world.std.com (William M Miller) writes:
|There have always been "guiding principals" (Bjarne and crew originally, now
|X3J16); I think there have generally been guiding _principles_ as well.
|(Sorry for the "principal/principle" pun, but I couldn't resist. :-)

Okay, I'll bite:

I claim one of those guiding principles ought to be that whenever we
have a chance to 1) change the definition to make the language more orthogonal, 
removing a special case "wart" WITHOUT negatively impacting existing
code, verses 2) leaving the language the same, arguing the change is not
worth the effort, that we should "almost always" make that effort.
IE the burden of proof ought to be on the supporters of the "wart", not
on the people who want to remove the unnecessary special case.

It may take a little extra effort to remove these "warts" from existing
compilers, but over the lifetime of the language, its going to make
10s of thousands of programmers lives easier.

----

Another second guiding principle ought to be:  The ANSI-C++ spec specifies
*language* not *implementation.*

----

And "my" third guiding principle would be, the ANSI-C++ specification
either calls out *one* behavior for a compiler regards a particular 
feature, or leaves *all* interpretation of that feature "implementation
dependent" BUT DOES NOT specify two contradictory *implementations*
either of which [but no other] is acceptible.  [IE either agree to agree,
or agree to disagree, but *don't* agree to try to lock out future 
implementations!]

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

In article <4610@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
|Horse pucky!  Prove it!

What would such a "proof" consist of Ron?  I'd post an example using
references, you'd post an example using pointers, you'd claim your
code is "better" and I'd claim my code is "better."  Lets be honest,
some people think C++ shouldn't have had references in the first
place, but are still fighting a read guard to cripple them now that
they're in the C++ language.

|I claim that even if you *had* your so-called "smart references" today,
|there is absolutely nothing that you could do with them that you could
|not do just as well using only "smart pointers".

One counter-example to this claim already posted is the example of 
a ref-counted element of a matrix.  Matrix::operator[] needs to 
return a "smart reference" class because it needs to do reference
counting, and it needs to follow value semantics because it in turn 
needs to have operator[] applied to it in order to get to the individual
element.

|I also claim that there is nothing that you could do significantly *easier*
|with "smart references" than you could with just smart pointers.

Show me how you do the reference counted element of a matrix example?

Also, I claim "smart pointers" today are frequently used in situations where
the "smart pointer" class does not support the full contigency of pointer
operations -- but rather can only be used to refer to a single object.
Such is not properly a pointer -- it doesn't support pointer operations
such as increment, decrement, operator[], etc.  If its a "reference
counting smart pointer" chances are it doesn't even support assignment
of null -- because reference counting smart pointers need to target an
actual objec that keeps track of the reference count.  So, much of the
time "smart pointers" are actually implementing "smart references" today --
but are using inappropriate syntax.  Since these people are actually
implementing references, why can't they use reference syntax????

|If you have a counterexample I encourage you to post it and prove me wrong.
|(Post the code please.  Hemming and hawing in flowery prose will not help
|to make the point either way.)

Again, people have already posted examples of returning an instance of
some class from a matrix via operator[].  Such class is naturally a 
"smart reference" since it in turn needs to follow "value semantics"
in order that operator[] can in turn be applied to it.

Show me how you solve this problem using "smart pointers" ???

Also, Ron is using a a circular argument.  While doing his best to keep
people from having compilers that support operator-dot, Ron complains that
people don't have good examples of using operator-dot.  We haven't exactly
had a flood of good examples of using templates or exceptions posted to
notes either -- because most people don't have compilers supporting such
yet.  How about if Ron posts his favorite "smart pointer" code, I'll do my
best to convert it to "smart reference" code, and then we'll argue about
which is inferior?

Again, why are some people so vested in maintaining a minute non-orthogonal
wart in the language???  Why not just make the language orthogonal, and
say "all operators can be overloaded"???

If some C++ programmers consider overloading operator-dot a "bad" idea --
**** THEN DONT DO IT! ****

Why is it necessary to force your prejudices of what constitutes "good
programming" onto others?

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

In article <275@heurikon.heurikon.com> daves@ex.heurikon.com (Dave Scidmore) writes:
|In following this discussion I have noticed that most of these examples
|start with the statement "I want to design some set of objects to do X and
|I want to do this by using langauge feature Y in this way". It do not believe
|that there is any meaning in showing that given a contrived set of
|circumstances the language can not meet the needs of your program. 

I agree.  C++ could have been done entirely without any overloadable
operators.  However, I think that would have made it a less desirable
language.  I am only asking that a "wart" -- an unnecessary restrictive
case -- be removed from the language.  Let's just say "all operators
are overloadable" and get it over with.

|To do so 
|is to expect the language to be all things to all people. 

On the contrary, people who wish to not allow overloadable operator dot
wish to force all people to their point of view that pointers
are preferable to references.  Such people expect the language to help them
restrict what other people can do.  I just ask that such a simple and
needless restriction be removed.  People can decide for themselves whether
to use pointer or reference syntax.  They don't need a small group of
self-appointed experts to decide that for them.

|What is important
|is whether their is a solution set for your problem, without any contrived
|conditions or usages of language features, which maps cleanly to your problem.

I disagree.  I believe what is important is that the language be
clean and orthogonal.  Due to its "C" history C++ includes a concept of
pointers, whereas other OOPLs have shown that having only references
is sufficient.  But, due to history, C++ has both pointers and references.
Given that the vast majority of operators can already be overloaded, 
all should be overloadable.   Why place a needless non-orthogonal 
restriction on the language?  Why not allow programmers to choose whether
to use pointers or to references?  Why not allow programmers to choose
what operator overloadings are appropriate for their programming?  Why
allow 40 operators to be overloaded -- but not operator dot ???

|I believe that with some effort a clean approach that does not require
|modification of the language is possible for every one of the examples given
|so far. That solution starts with rethinking how you want to achieve the end
|result and picking an approach that is a good fit with existing language
|features.

Agreed.  The entire concept of pointers in needless in C++ and could
be removed.  This has already been shown in a half dozen other OOPLs.
But such is water under the bridge.  C++, due to history, has both
pointers and references.  I only ask that the choice of which to use
be left to the C++ programmer.  Why deny this choice?  -- C/C++ have
historically left the choice to the end programmer to be intelligent 
enough to decide for themselves how to best do their jobs -- they don't
need some "experts" needlessly restricting their choices in a few obscure
and non-orthogonal cases.

|>But, when we place all the problems
|>we've found into one category which we label "smart references" some
|>people argue that we're just applying a name to a category we've made up.
|
|Since "f.thing" and "(&f)->thing are equivilent in a sense smart references
|already exist. If you think of "f->thing" as being equivelent to "(*f).thing"
|then it becomes clear why "->" is was originaly made overloadable and "."
|was not. Since overloading of "*" is allowed how do you overload the implicit
|"*" in "f->thing" (i.e. (*f).thing). The method chosen was to allow
|overloading of "->". Since "." has not implicit dereference overloading was
|not needed.

By such an argument operator+ should not exist because its possible to 
accomplish the same thing through:

	Matrix A = B  - (-C);

|>And then when we show specific short examples of the problem then people 
|>argue that the examples we give are academic and give hack work-arounds.
|
|I for one do not think using "(&f)->thing" is a hack workaround. It is
|quite clear to me what is intended.

Tell me which of the following you consider "quite clear" :

example A: ["smart references"]

	Matrix a[100, 200];
	
	Vector v = a[20];

	double d = v[40];

example B: ["the 'quite clear' work-around of explicitly converting to 
		smart pointer"]

	Matrix a[100, 200];
	// ....

	Vector v = (&a)->operator[](20);

	double d = (&v)->operator[](40);

example C: ["smart pointers" used instead of "smart references"]

	Matrix a[100, 200];
	// ....

	Vector v = (*a)[20];

	double d = (*v)[40];

|One reason I have seen given (you must have missed it) is that it alters
|the syntax of the language in ways that make it hard to predict the outcome.
|Currently "expression.expression" is not allowed, your change would make
|it allowable. If this creates side effects then its removal will be far from
|easy.

I believe you misunderstand me:

My proposal is for unary operator dot, just as today there is unary
operator->().  Neither allows an expression for the selector.  My
proposal only requires that which is already required because of
opeartor->().  The only change to the language is to allow programmers
to choose between writing smart reference classes or smart pointer classes.
Expression.expression is not allowed, neither today is expression->expression
allowed.  The only change is adding the appropriate syntax to allow
programmers to program smart reference classes if they so choose, just
as today we allow programmers to program smart pointer classes, if they
so choose.

steve@taumet.com (Stephen Clamage) (04/04/91)

jimad@microsoft.UUCP (Jim ADCOCK) writes:

>I claim one of those guiding principles ought to be that whenever we
>have a chance to 1) change the definition to make the language more orthogonal, 
>removing a special case "wart" WITHOUT negatively impacting existing
>code, verses 2) leaving the language the same, arguing the change is not
>worth the effort, that we should "almost always" make that effort.

Aha!  A hidden argument for 'operator dot'.  Nice try, but I see through it!

>Another second guiding principle ought to be:  The ANSI-C++ spec specifies
>*language* not *implementation.*

There was never any question that the spec must refer to language and not
to any specific implementation.  However, any language feature, and the
resulting totality of the language, must be implementable with current
technology with reasonable efficiency; it must not force all users to
pay a high price for a feature which they do not use.  Thus, we will
not see type 'int' required to represent all integers, but only those
in an implementation-defined set.

>And "my" third guiding principle would be, the ANSI-C++ specification
>either calls out *one* behavior for a compiler regards a particular 
>feature, or leaves *all* interpretation of that feature "implementation
>dependent" BUT DOES NOT specify two contradictory *implementations*
>either of which [but no other] is acceptible.

Consider the right-shift operator in ANSI C.  It has one of two specified
behaviors: it may, but need not, sign-extend signed integers.  It was left
with this choice because on some systems it was considered too onerous to
require sign extension.  By your criterion, >> would be extremely expensive
on some systems, or else would be left entirely up to the implementation --
a conforming implementation could just return 0 for any >> operation.
Is this what you had in mind?  Remember that the standardization effort
is cooperative, and many diverse ideas and requirements must be
reconciled.

The "0, 1, infinity" criterion is often a good guiding principle, but
does have its limitations when it collides with the real world.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

lord@plasm.esd.sgi.com (the toomlrd) (04/06/91)

This is about the ongoing discussion of an overloadable 
operator dot.

>In order to understand how this would work, I think that you would have
>to look at the whole proposal.  I'm not sure, but I think that the idea
>is to allow something like:

>	expression.expression


>The bare fact of the matter (as I have said many times) is that "." is
>plainly not an operator (either unary or binary).  It is a selector.


If I had to write down the semantics for the dot syntax, I would
assume two subexpressions.  The type of the right hand expression
would be (essentially) `name'.


As it stands now, C++ has no run-time representation for names.
Consequently, it seems like a big deal to overload dot.  If you
accept my view -- there is no problem.  Its just that all the dot 
expressions you've ever seen have had lots of constants.

The extension I would imagine for . will not really expand the concept,
just remove restrictions about what can be done at compile time
vs. what can wait till run-time.

>In effect, dot acts a bit like the other "scope opener" that we know
>about in C++, i.e. the colon-colon.  These things are plainly NOT
>operators.  People who are just learning the language (as well as
>experienced users) will just get more and more confused (when trying
>to read code) if we start to bend the "normal" rules regarding what may
>and may not be overloaded (or treated like an operator).

The advantage of the view I suggest (first class names) is that
the resulting language has fewer, though more general rules.

>I have previously noted that allowing overloading for "." makes about as
>much sense as allowing overloading for "{".  In both cases the very
>idea appears ridiculous, however I actually read a response from one
>person who said that (maybe) allowing overloading for "{" would be
>a useful and good thing!!!

Funny you should say that.  Syntacticly, I hope there will never be
an operator { -- in fact, it takes a few translations before blocks
look like functions at all.

On the other hand, blocks are objects with definable types and
run time representations.  Why not let users define some of the
functionality normally implicit in blocks?  This leads to many excellent
programming techniques usually impossible in C++.


>I guess the bottom line is this.  What is your opinion regarding how
>a language should be designed?  Should it be an unbridled, nonsensical
>and chaotic mismash of random "bright ideas" which seem like they might
>occasionally have some obscure usefulness, or should there be some
>rules, some guiding principals, and some *consistancy* in the set of
>features provided by a language?

There are fewer computer languages than people like to think.  A lot
of languages that seem similar to C++ really are and if you build
clean semantic models of them you see that most bright language ideas
capture special cases of an almost universal semantics and give them
special names.

My conclusion is that what you (the original poster) means by
language design is really syntax design.  Here the issues are much
less `what is the meaning of programs, what programs are possible'
much more `which meanings are used most often, and how are those
uses best expressed?'.

-t

ark@alice.att.com (Andrew Koenig) (04/12/91)

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

> Lets be honest,
> some people think C++ shouldn't have had references in the first
> place, but are still fighting a read guard to cripple them now that
> they're in the C++ language.

Without references, the language would need some other way of identifying
copy constructors.  I can think of no other place where referenes are
structurally necessary, though it would be much harder to define
input operators conveniently without them.
-- 
				--Andrew Koenig
				  ark@europa.att.com

adk@sdl.scs.com (Ajay Kamdar) (04/13/91)

This is a little digression from the regulary scheduled arguments for and
against overloading operator-dot.


In article <71650@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:
>In article <4610@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
>|Horse pucky!  Prove it!
>
	- Arguments and counter arguments deleted -
>
>If some C++ programmers consider overloading operator-dot a "bad" idea --
>**** THEN DONT DO IT! ****
>

That is a supercilious argument. If Ron is right, and if overloading 
operator-dot is indeed a "bad" idea, advice to not do it just doesn't cut.
Most people who have had to support(work with) somebody else's badly written
code will testify to that.

>Why is it necessary to force your prejudices of what constitutes "good
>programming" onto others?

Are you really asking that?

If you want a simple example of people's prejudices of what constitutes
"good programming" and how it affects somebody else's work, read on.



Consider the case of function prototypes.

I prefer that parameters in function prototypes be named. Some others
perfer otherwise. I consider it "bad programming" to not name the function
parameters. Some others don't.

Now assume that I am the consumer of a class library developed by somebody
else, and I just have the object code and some header files.

Assume that a .h file has the following prototype for a function: 

	void do_something(int, int);

Notice that the function prototype does not have parameter names.

If I need to use the function, how do I figure out what arguments it
takes? Maybe I can figure out from the context that it takes the arguments
something_1 and something_2. But how do I figure out in what order?
If I am lucky, the function definiton is in the header file, and I can
look at it. But what if it is not?

In fact, even if the function definition is available, it is irritating to
have to look at the function definition to figure such details out.

This is a very simple example of a common problem. The problem becomes really
serious when one encounters such situations with complex libraries. Sigh...

One can continue ad nauseum with similar examples.

Anyway, back to the regularly schedule programming.

- Ajay

-- 
Standard disclaimers apply.

Ajay Kamdar                                           
Mentor Graphics, IC Group			Email : ...uunet!sdl!adk