Topic: Changing qualifier a.b to a->b and back again


Author: aresrobin@aol.com (Ares Robin)
Date: 14 Sep 1994 11:54:04 -0400
Raw View
In article <CvzA9H.Eyr@borland.com>, pete@genghis.interbase.borland.com
(Pete Becker) writes:

> I still don't understand. Either this posting makes the trivial point
> that there often is more than one way to do something, or it overlooks
the
> differences between pointers and references. In particular, using .
instead of
> -> makes it less likely that the user of a pointer will see the error in
> this function:
>
>  struct Foo
>  {
>  int i;
>  };
>
>  void f( Foo *fp )
>  {
>  // error here, because a pointer is not a reference
>  cout << fp.i << endl;
>  }
>
>  int main()
>  {
>  f(0);
>  return 0;
>  }
>
> Pointers and references have different semantics. Obscuring this
difference
> by using the same notation for each will lead to errors. Different isn't
the
> same

The "reduced" likelihood of seeing an error would be, I'd claim,  more
about unfamiliarity with the different notation than anything else, and
would vanish once the new syntax was widely used.

I may be wrong, but if 'p' is a pointer to a [non-class] structure with a
member 'a', then in any current compiler writing 'p.a' instead of 'p->a'
is *always* a syntax error. So, introducing the notation 'p.a' to mean
what 'p->a' currently does won't cause any problems or ambiguities for the
compiler.

If we agree on this much, then the question that remains is: what will go
wrong for the *user* of the compiler? I say: nothing. You and several
others have said that it's necessary to know whether the variable is a
pointer or not. I don't see why, and would love to hear about a case where
it mattered, something more convincing than the above example.

(And, I would point out, 'p.a' is already "ambiguous", because 'p' could
be a structure or a reference to a structure. Why does that distinction
not require a separate operator, while the structure/pointer distinction
does?)

Regards,
Robin Henson
Ares Software Corp.





Author: aresrobin@aol.com (Ares Robin)
Date: 11 Sep 1994 13:39:01 -0400
Raw View
In article <CvxBHt.E5H@borland.com>, pete@genghis.interbase.borland.com
(Pete Becker) writes:

>Don't confuse concepts with implementations. This is essentially the
>same argument that says that it's OK to use goto's, because that's what
the
>compiler generates anyway. The issue is not what does the compiler do
with
>these things, but what are the legal operations on them and what impact
do
>they have on coding practices.

Really, I understand the difference. My point didn't depend on the
implementation of references. Compare these two for-loops, whose
similarity has nothing to do with implementation:

  struct A {char b; char c};
  A a [10];

  for (i = 0; i < 10; i++) {
    A *p = & a [i];
    p->b = 0;
  }

  for (i = 0; i < 10; i++) {
    A &p = a [i];
    p.b = 0;
  }

In both cases, 'p' clearly "steps through" the array elements in some
sense.

Although too trivial, these examples suggest how '->' can often be
eliminated in favor of '.' within the existing language definition. (With
the qualification "almost", because you can't re-initialize references at
will.) As far as I'm concerned, this means that using '.' directly with
pointer variables would be feasible and sensible.

Of course, you might argue that the second for-loop is "bad" (confusing)
because it's not clear that 'p' refers to a different object each time
through the loop. That may be true, but then the same is true of variable
'i'. Either way, you need to check the start of the loop to understand the
variable's use.

Regards,
Robin Henson
Ares Software Corp.





Author: pete@genghis.interbase.borland.com (Pete Becker)
Date: Sun, 11 Sep 1994 18:34:29 GMT
Raw View
In article <34vfbl$b0c@search01.news.aol.com>,
Ares Robin <aresrobin@aol.com> wrote:
>
>Really, I understand the difference. My point didn't depend on the
>implementation of references. Compare these two for-loops, whose
>similarity has nothing to do with implementation:
>
>  struct A {char b; char c};
>  A a [10];
>
>  for (i = 0; i < 10; i++) {
>    A *p = & a [i];
>    p->b = 0;
>  }
>
>  for (i = 0; i < 10; i++) {
>    A &p = a [i];
>    p.b = 0;
>  }
>
>In both cases, 'p' clearly "steps through" the array elements in some
>sense.
>
>Although too trivial, these examples suggest how '->' can often be
>eliminated in favor of '.' within the existing language definition. (With
>the qualification "almost", because you can't re-initialize references at
>will.) As far as I'm concerned, this means that using '.' directly with
>pointer variables would be feasible and sensible.
>

 I still don't understand. Either this posting makes the trivial point
that there often is more than one way to do something, or it overlooks the
differences between pointers and references. In particular, using . instead of
-> makes it less likely that the user of a pointer will see the error in
this function:

 struct Foo
 {
 int i;
 };

 void f( Foo *fp )
 {
 // error here, because a pointer is not a reference
 cout << fp.i << endl;
 }

 int main()
 {
 f(0);
 return 0;
 }

Pointers and references have different semantics. Obscuring this difference
by using the same notation for each will lead to errors. Different isn't the
same.
 -- Pete







Author: spitzak@hollywood.cinenet.net (Bill Spitzak)
Date: 13 Sep 1994 01:16:18 -0700
Raw View
pete@genghis.interbase.borland.com (Pete Becker) writes:

>In article <34vfbl$b0c@search01.news.aol.com>,
>Ares Robin <aresrobin@aol.com> wrote:
>>
>>Although too trivial, these examples suggest how '->' can often be
>>eliminated in favor of '.' within the existing language definition.

> I still don't understand. Either this posting makes the trivial point
>that there often is more than one way to do something, or it overlooks the
>differences between pointers and references. In particular, using . instead of
>-> makes it less likely that the user of a pointer will see the error in
>this function:

> struct Foo
> {
> int i;
> };

> void f( Foo *fp )
> {
> // error here, because a pointer is not a reference
> cout << fp.i << endl;
> }

> int main()
> {
> f(0);
> return 0;
> }

I absolutely fail to understand!  Replace the 'fp.i' with 'fp->i' above
and explain just exactly how this change has helps you notice or fix
the bug!

The "bug" is that the function f expects a non-null pointer, and
it has been called with null.  The bug is therefore inside main() and
no change in the implementation of f() is going to fix it.

Bill Spitzak




Author: pete@genghis.interbase.borland.com (Pete Becker)
Date: Tue, 13 Sep 1994 15:36:06 GMT
Raw View
In article <353n4i$5ld@hollywood.cinenet.net>,
Bill Spitzak <spitzak@hollywood.cinenet.net> wrote:
>pete@genghis.interbase.borland.com (Pete Becker) writes:
>
>>In article <34vfbl$b0c@search01.news.aol.com>,
>>Ares Robin <aresrobin@aol.com> wrote:
>>>
>>>Although too trivial, these examples suggest how '->' can often be
>>>eliminated in favor of '.' within the existing language definition.
>
>> I still don't understand. Either this posting makes the trivial point
>>that there often is more than one way to do something, or it overlooks the
>>differences between pointers and references. In particular, using . instead of
>>-> makes it less likely that the user of a pointer will see the error in
>>this function:
>
>> struct Foo
>> {
>> int i;
>> };
>
>> void f( Foo *fp )
>> {
>> // error here, because a pointer is not a reference
>> cout << fp.i << endl;
>> }
>
>> int main()
>> {
>> f(0);
>> return 0;
>> }
>
>I absolutely fail to understand!  Replace the 'fp.i' with 'fp->i' above
>and explain just exactly how this change has helps you notice or fix
>the bug!
>
>The "bug" is that the function f expects a non-null pointer, and
>it has been called with null.  The bug is therefore inside main() and
>no change in the implementation of f() is going to fix it.
>
>Bill Spitzak


 The bug is that the coder who was responsible for updating this
function when it was changed from a function taking a reference to a function
taking a pointer failed to understand the symantic differences between
pointers and references. Allowing the same notationf for both increases the
possibility of such confusion. Different isn't the same.
 -- Pete




Author: tob@world.std.com
Date: Tue, 13 Sep 1994 20:11:48 GMT
Raw View
pete@genghis.interbase.borland.com (Pete Becker) writes:
>         The bug is that the coder who was responsible for updating this
> function when it was changed from a function taking a reference to a function
> taking a pointer failed to understand the symantic differences between
> pointers and references. Allowing the same notationf for both increases the
> possibility of such confusion. Different isn't the same.

Allowing the same notation for both [member-access operations] has
nothing to do with the bug in question. You did not address his
objection. I don't think you even understood it.

You'll have to excuse my tone, but I'm getting a wee bit fed up at
reading positions that don't distinguish between 0) making a pointer and
reference use the same member access notation, and 1) making a pointer
and reference the same in every way. "Different isn't the same."

        Tom

--
finger me for how Tehomega is coming along (at tob@world.std.com)
Author of The Burning Tower (from TomBreton@delphi.com) (weekly in
rec.games.frp.archives)





Author: jaf3@ritz.cec.wustl.edu (John Andrew Fingerhut)
Date: 9 Sep 1994 07:43:31 -0500
Raw View
In article <JASON.94Sep5131615@deneb.cygnus.com>,
Jason Merrill <jason@cygnus.com> wrote:
>For those who support making -> pointer/struct-blind:  You can do this
>already in the existing language, by adding a single line to each class.
>
>struct A {
>  ...
>  A* operator-> () { return this; }
>  ...
>};
>
>Jason

Yes, but can you make operator . work on a pointer?  Don't take that as
an argument in favor of this thread's proposal.  I think that there are
more important issues to deal with than something as insignificant as
this.

Stephen Gevers
sg3235@shelob.sbc.com




Author: pete@genghis.interbase.borland.com (Pete Becker)
Date: Sat, 10 Sep 1994 17:05:52 GMT
Raw View
In article <34qq9p$493@search01.news.aol.com>,
Ares Robin <aresrobin@aol.com> wrote:
>In article <34pl9j$1do@ritz.cec.wustl.edu>, jaf3@ritz.cec.wustl.edu (John
>Andrew Fingerhut) writes:
>
>>Yes, but can you make operator . work on a pointer?
>
>Of course, the replacement of 'operator->' by 'operator.' has already
>happened -- almost.
>
>References to structures are -- actually (in all the compilers I've used)
>or effectively (because of the relationships set up between pointers and
>references in the language definition) -- pointer variables that are
>dereferenced by '.' instead of '->'.

 Don't confuse concepts with implementations. This is essentially the
same argument that says that it's OK to use goto's, because that's what the
compiler generates anyway. The issue is not what does the compiler do with
these things, but what are the legal operations on them and what impact do
they have on coding practices.

>
>The convenience of references argues against, I think, the rather dogmatic
>notion that we "need" to know whether we're dealing with a structure or a
>pointer to that structure. And the notion that 'operator.' applied to
>pointers won't "work".

 One critical distinction between pointers and references is that, used
properly, a reference always refers to a valid object. A pointer need not do
so. One consequence of this distinction is the common coding convention that
a pointer should be used as a function parameter when there may not be an
object, in which case a 0 should be passed. This means that the function must
check for a 0 argument. A reference is used when the parameter is required, in
which case the function need not check.
 Insisting on knowing what the legal operations on an object are is not
dogmatic. It's the only way to write code that has a chance of working
correctly through several maintenance cycles.
 -- Pete




Author: aresrobin@aol.com (Ares Robin)
Date: 9 Sep 1994 19:15:05 -0400
Raw View
In article <34pl9j$1do@ritz.cec.wustl.edu>, jaf3@ritz.cec.wustl.edu (John
Andrew Fingerhut) writes:

>Yes, but can you make operator . work on a pointer?

Of course, the replacement of 'operator->' by 'operator.' has already
happened -- almost.

References to structures are -- actually (in all the compilers I've used)
or effectively (because of the relationships set up between pointers and
references in the language definition) -- pointer variables that are
dereferenced by '.' instead of '->'.

The convenience of references argues against, I think, the rather dogmatic
notion that we "need" to know whether we're dealing with a structure or a
pointer to that structure. And the notion that 'operator.' applied to
pointers won't "work".

If, say,  there were a way of re-initializing reference variables, I for
one would happily eliminate pointers from my C++ vocabulary. Since that's
not going to happen, dumping '->' in favor of '.' for pointers seems like
the next best thing.

Regards,
Robin Henson
Ares Software Corp.




Author: tob@world.std.com (Tom O Breton)
Date: Sat, 3 Sep 1994 21:07:29 GMT
Raw View
wilkinso@gdls.com (Robert M. Wilkinson):
> You sound like an Ada programmer.  These things that you find frustrating
> are exactly why I consider Ada code difficult to read:  the reader cannot
> tell what the following does:
>
> X := Y;
>
> Does this call the function Y, or is Y a variable? This statement could
> very well be the bottleneck in your entire system, although you'd never
> suspect it from looking at it.

Guessing where the bottleneck is is not recommended anyways. Use a
profiler.

> With C++:
>
> x = y();
>
> you know a function is being called.

_syntactically_ you do, but precede it with:

static int
some_int;

inline
int
y( void ) { return some_int; }

and it's a variable, as far as run-time execution is concerned. Which is
not a problem in my eyes, but your reasoning suggests it should be.

> Same thing for array references.
> Ada does this:
>
> X := Y(Z);
>
> But what's this do?

Well, what's this do?

X = Y[ Z ];

In C++, it could calculate the square root of Z. "[...]" (in most
contexts) is really just a fancy function name.

Of course, you realized this yourself, but you completely de-emphasized
it:

> Of course, operator overloading destroys some of this, but at least
> different operations have a different syntax.

Of course, anyone with any style will use a _name_ that says what it
does. Which is what you're ignoring.


> Sure, the compiler can figure it out, but can the reader?

Why do you keep saying that? Why keep assuming that the reader has to
get into every detail of the function at every point in the function?
Isn't seeing that it is a pointer where it's declared enough? Why must
the reader be reminded of it with every member access? Why care? Lowers
the S/N ratio of the source, as far as I'm concerned.

That presumption is _really_ causing me to discount your argument.

> The -> notation
> tells you you're dealing with a pointer.  The . notation tells you you're
> dealing with a structure.  Why should a structure and a pointer be treated
> as equivalent, when clearly they are not?

I'm sorry, that's just dogmatic.

        Tom

--
finger me for how Tehomega is coming along (at tob@world.std.com)
Author of The Burning Tower (from TomBreton@delphi.com) (weekly in
rec.games.frp.archives)





Author: eyala@applicom.co.il (Eyal Allalouf)
Date: Sun, 4 Sep 1994 15:48:25 GMT
Raw View
I've been following this discussion for the last days.
It does concern some of the niceties (not necessities) I, personally,
would like to have in C++.
What I always thought was coherent, and might limit the use for overloading
of the "->" operator is the following.

  C++ has conversion operators. However they behave confusingly at times.
  Consider:
  class A {
    public:
   int   operator+ (int x) ...;
  };

  class B {
  ...
  };

  int  operator+ (const B&, int) ...;

  class A1 {
  public:
    operator A% () ...;
  };

  A1 x;
  X + 3; // Illegal in C++.


  class B1 {
  public:
    operator B% () ...;
  };

  B1 y;
  y + 3; // Legal.

The two examples seem at first look identical, and the reason for the
error is not apparent.

My suggestion is - if a class has a conversion operator than this class
can be used whenever the converted type can be used, INCLUDING accessing
methods and data of the converted type.
That is if class "A" has a conversion operator for "X*" than "A a; a->y"
is legal if X has a "y" data field.

Happy new year.

-----------------------------------------------------------------------------
    Eyal Alaluf                                eyala@applicom.co.il
    Mainsoft Israel Ltd.                       c/o Applicom Systems Ltd.
                                               16 Abba Hillel Silver St.
    Phone : 972 -(3) 575 5550 ext : 1278       Ramat-Gan, 52506
    Fax   : 972 -(3) 751 0906                  Israel
------------------------------------------------------------------------------




Author: aishdas@iia.org (Mitchel Berger)
Date: 4 Sep 1994 14:38:06 GMT
Raw View
wilkinso@gdls.com (Robert M. Wilkinson):
> You sound like an Ada programmer.  These things that you find frustrating
> are exactly why I consider Ada code difficult to read:  the reader cannot
> tell what the following does:
>
> X := Y;
>
> Does this call the function Y, or is Y a variable? This statement could
> very well be the bottleneck in your entire system, although you'd never
> suspect it from looking at it.

So, overloading and information hiding are Bad Things? :-)++




Author: jason@cygnus.com (Jason Merrill)
Date: Mon, 5 Sep 1994 20:16:15 GMT
Raw View
For those who support making -> pointer/struct-blind:  You can do this
already in the existing language, by adding a single line to each class.

struct A {
  ...
  A* operator-> () { return this; }
  ...
};

Jason




Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Wed, 7 Sep 1994 09:42:26 GMT
Raw View
In article <3471j5$n53@gdls.com> wilkinso@gdls.com (Robert M. Wilkinson) writes:
>
>Someone wrote:
>>>> I always find it somewhat frustrating that C++ (and C for that matter)
>>>> does not "understand" that a.b and a->b (to me) mean the same thing.
>>>>
>>>> [stuff deleted]
>>>>
>>>>incorporated in C++, only that I cannot see any reason for having two
>>>>different operators for invoking methods and accessing member
>>>>variables. By the same token, I just cannot stand having to add an
>>>>empty pait of parenthesis when calling a function with no arguments:
>>>>that's just in my way when I decide to change the implementation of
>>>>something between being a variable and being computed on the fly.
>>>>Again there's no reason why the compiler shouldn't figure out what to
>>>>do, and once again I don't think it should be in C++.
>
>You sound like an Ada programmer.  These things that you find frustrating
>are exactly why I consider Ada code difficult to read:  the reader cannot
>tell what the following does:
>
>X := Y;
>
>Does this call the function Y, or is Y a variable?  This statement could
>very well be the bottleneck in your entire system, although you'd never
>suspect it from looking at it...

Well, the original poster had a good point that in C++ (as in Ada) there
are already *many* language features whose sole purpose is to make C++
programs easier to write, even at the expense of making them vastly
harder to read.  So what's one more?

(The term `write only code' comes to mind.  If C++ was ever intended to
be a language in which large systems of code could be written maintainably,
it has failed to achieve that goal.)

P.S.  The most offensive example of a cutsey shorthand notation which is
available in C++ is the user-defined type conversion.  Using these makes
otherwise simple looking code absolutely indecypherable by mere mortals.

--

-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -




Author: olaf@cwi.nl (Olaf Weber)
Date: Wed, 31 Aug 1994 12:11:26 GMT
Raw View
In article <CvEDAB.2tr@undergrad.math.uwaterloo.ca>, r-ridge@calum.csclub.uwaterloo.ca (Ross Ridge) writes:

> John Max Skaller <maxtal@physics.su.OZ.AU> wrote:
>> Similarly, the correct interpretation of
>>
>> ptm . m
>>
>> is a pointer to member m. (Given ptm points to a member of
>> some class containing m).

> Huh?  Do you mean something like this:

>  struct foo { int m; int n; } x, *p = &x;
>  int *ptm = &p.n;
>  int *ptm_dot_m = ptm.m;
>  assert(ptm_dot_m == &p.m);

> or this:

>  struct foo { int m; int n; };
>  int foo::*ptm = &foo::n;
>  int foo::*ptm_dot_m = ptm.m;
>  assert(ptm_dot_m == &foo::m);

> I really don't buy either interpretation.

No, the implied meaning is something like this:

 struct foo { int m; int n; };
 struct bar { foo a; foo b; };

 foo bar::*ptm = &bar::a;
 int foo::*ptm_dot_m = ptm.m;
 assert(ptm_dot_m == &bar::a::m;

-- Olaf Weber




Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Thu, 1 Sep 1994 09:30:32 GMT
Raw View
In article <CvD6zA.8J0@world.std.com> tob@world.std.com writes:
>I have been reading over the "." == "->" suggestion. At first I had two
>doubts:
>
>Would the gain to the user be worth the compiler effort?
>
>        When I think about it, the change to the compiler is trivial...

It appears that I need to just keep saying this until it sinks in.

*EVERYTHING* is trivial as long as *you* are not the schmuck who has to
implement it, document it, test it, and maintain it.

--

-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -




Author: wilkinso@gdls.com (Robert M. Wilkinson)
Date: 2 Sep 1994 07:16:53 -0400
Raw View
Someone wrote:
>>> I always find it somewhat frustrating that C++ (and C for that matter)
>>> does not "understand" that a.b and a->b (to me) mean the same thing.
>>>
>>> [stuff deleted]
>>>
>>>incorporated in C++, only that I cannot see any reason for having two
>>>different operators for invoking methods and accessing member
>>>variables. By the same token, I just cannot stand having to add an
>>>empty pait of parenthesis when calling a function with no arguments:
>>>that's just in my way when I decide to change the implementation of
>>>something between being a variable and being computed on the fly.
>>>Again there's no reason why the compiler shouldn't figure out what to
>>>do, and once again I don't think it should be in C++.

You sound like an Ada programmer.  These things that you find frustrating
are exactly why I consider Ada code difficult to read:  the reader cannot
tell what the following does:

X := Y;

Does this call the function Y, or is Y a variable?  This statement could
very well be the bottleneck in your entire system, although you'd never
suspect it from looking at it.  With C++:

x = y();

you know a function is being called.  Same thing for array references.
Ada does this:

X := Y(Z);

But what's this do?  Does if reference array Y with a parameter returned
by function Z, does it reference array with variable Z, does it call function
Y with variable Z, or does it call function Y with the return value of
function Z?  You can't tell by looking at the statement;  you have to go
look up the types of everything.

In C++, the alternatives are:

x = y[z()];
x = y[z];
x = y(z);
x = y(z());

Looking at each statement the reader can easily see what they do
(semantically).  Of course, operator overloading destroys some of this,
but at least different operations have a different syntax.


>>> I always find it somewhat frustrating that C++ (and C for that matter)
>>> does not "understand" that a.b and a->b (to me) mean the same thing.
>>
>> They DON'T mean the same thing... but if you want to program
>> in a language which tries to pretend that they do, try Ada.
>
>They don't mean the same thing in the very same way that 2 + 2 and 2.0
>+ 2.0 don't mean the same thing. They both mean to use the member
>named `b' inside the object denoted by `a'. The fact that `a' is a
>user alterable pointer or a compiler+linker generated one is
>irrelevant to the semantic of the operation "use the `b' member inside
>`a'". It is true that C++ follows the C tradition on this, but there's
>no technical reason to this as I don't believe there's a single case
>in which the compiler cannot figure out what to do.

Sure, the compiler can figure it out, but can the reader?  The -> notation
tells you you're dealing with a pointer.  The . notation tells you you're
dealing with a structure.  Why should a structure and a pointer be treated
as equivalent, when clearly they are not?

This argument comes from many Ada programmers, who feel no need to
distinguish between records and pointers, but *do* feel the need
to distinguish between two integers declared in different places.
Go figure.

--

____________________________________________________________________________

Rob Wilkinson                                              wilkinso@gdls.com
____________________________________________________________________________





Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Sat, 3 Sep 1994 14:36:44 GMT
Raw View
wilkinso@gdls.com (Robert M. Wilkinson) writes:

>These things that you find frustrating
>are exactly why I consider Ada code difficult to read:  the reader cannot
>tell what the following does:
>
>X := Y;
>
>Does this call the function Y, or is Y a variable?  This statement could
>very well be the bottleneck in your entire system, although you'd never
>suspect it from looking at it.
...
>In C++ ... the reader can easily see what they do
>(semantically).

Your point about using different notation for different operations
to make the code easier to read is a valid point - although there
are arguments both for and against.  But your claim that in C++
the reader can easily see what is happening, and in particular
your implication that this is a lot easier in C++ than it is in Ada,
is IMHO utterly ridiculous.

>Of course, operator overloading destroys some of this,
>but at least different operations have a different syntax.

Operator overloading is only one part of it in C++.
Automatic invocation of constructors and destructors can
certainly make the behaviour non-obvious - especially when
you consider constructors and destructors for temporary
unnamed objects.  And don't forget about automatic implicit
invokation of user-defined conversions.  Then there's
template specializations, and for that matter virtual functions.
Oh, and of course don't forget macros.

This is not to say that these features are bad - just that they can
certainly make it more difficult to see exactly what is happening.
Often hiding the implementation details is exactly what you want!

--
Fergus Henderson - fjh@munta.cs.mu.oz.au




Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Mon, 29 Aug 1994 09:43:02 GMT
Raw View
In article <33b7ks$6fv@flclcnsa.clc.gmeds.com> bhenk02@cps.plnin.gmeds.com writes:
>I always find it somewhat frustrating that C++ (and C for that matter)
>does not "understand" that a.b and a->b (to me) mean the same thing.

They DON'T mean the same thing... but if you want to program in a language
which tries to pretend that they do, try Ada.

--

-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -




Author: mav@gaia.cc.gatech.edu (Maurizio Vitale)
Date: 29 Aug 1994 14:13:10 GMT
Raw View
>>>>> "Ronald" == Ronald F Guilmette <rfg@netcom.com> writes:

  Ronald> In article <33b7ks$6fv@flclcnsa.clc.gmeds.com> bhenk02@cps.plnin.gmeds.com writes:
  >> I always find it somewhat frustrating that C++ (and C for that matter)
  >> does not "understand" that a.b and a->b (to me) mean the same thing.

  Ronald> They DON'T mean the same thing... but if you want to program
  Ronald> in a language which tries to pretend that they do, try Ada.

They don't mean the same thing in the very same way that 2 + 2 and 2.0
+ 2.0 don't mean the same thing. They both mean to use the member
named `b' inside the object denoted by `a'. The fact that `a' is a
user alterable pointer or a compiler+linker generated one is
irrelevant to the semantic of the operation "use the `b' member inside
`a'". It is true that C++ follows the C tradition on this, but there's
no technical reason to this as I don't believe there's a single case
in which the compiler cannot figure out what to do.
--
    Maurizio Vitale
 _______________
|        _      |\   e-mail: mav@cc.gatech.edu     | How many times can
|  /|/| '_) | ) | |  voice:  (404) 881-6083 (home) | a man turn his head,
| | | |_(_|_|/  | |          (404) 853-9382 (work) | and pretend that he
|_______________| |                                | just doesn't see ?
 \_______________\|  fax:    (404) 853-9378        |  - Bob Dylan




Author: michaelc@lna.logica.com
Date: Mon, 29 Aug 1994 16:47:10 GMT
Raw View
>>>>> "mav" == Maurizio Vitale <mav@gaia.cc.gatech.edu> writes:

    mav> It is true that C++ follows the C tradition on this, but there's no
    mav> technical reason to this as I don't believe there's a single case in
    mav> which the compiler cannot figure out what to do.

The ANSI C people decided to let the compiler be smart enough to understand
that `pf()' is the same as `(*pf)()'.  Given that "prior art," letting the
compiler decide that `ps.m' is the same as `ps->m' seems natural.

Michael.




Author: pete@genghis.interbase.borland.com (Pete Becker)
Date: Mon, 29 Aug 1994 18:49:19 GMT
Raw View
In article <MCOOK.94Aug29124710@galaga.lna.logica.com>,
 <michaelc@lna.logica.com> wrote:
>
>The ANSI C people decided to let the compiler be smart enough to understand
>that `pf()' is the same as `(*pf)()'.  Given that "prior art," letting the
>compiler decide that `ps.m' is the same as `ps->m' seems natural.
>

 class Implementor
 {
 public:
  void f();
 };

 class User
 {
 public:
  void f();
  Implementor *operator->() const;
 };

 User u;
 u.f();

u.f() better not be the same as u->f().
 -- Pete




Author: mav@gaia.cc.gatech.edu (Maurizio Vitale)
Date: 29 Aug 1994 21:00:55 GMT
Raw View
>>>>> "Pete" == Pete Becker <pete@genghis.interbase.borland.com> writes:

  Pete> In article <MCOOK.94Aug29124710@galaga.lna.logica.com>,
  Pete>  <michaelc@lna.logica.com> wrote:
  >>
  >> The ANSI C people decided to let the compiler be smart enough to understand
  >> that `pf()' is the same as `(*pf)()'.  Given that "prior art," letting the
  >> compiler decide that `ps.m' is the same as `ps->m' seems natural.
  >>

  Pete>  class Implementor
  Pete>  {
  Pete>  public:
  Pete>   void f();
  Pete>  };

  Pete>  class User
  Pete>  {
  Pete>  public:
  Pete>   void f();
  Pete>   Implementor *operator->() const;
  Pete>  };

  Pete>  User u;
  Pete>  u.f();

  Pete> u.f() better not be the same as u->f().

Obviously if you code assuming operator. (I know there's no such
animal, but I stand there should be) to be different from operator->
then it is way better that the compiler do what you expect, but in a
world where . equal -> your code whould be ambiguous, just as today is
ambiguous to refer to f when f comes from two different derivation
path.
--
    Maurizio Vitale
 _______________
|        _      |\   e-mail: mav@cc.gatech.edu     | How many times can
|  /|/| '_) | ) | |  voice:  (404) 881-6083 (home) | a man turn his head,
| | | |_(_|_|/  | |          (404) 853-9382 (work) | and pretend that he
|_______________| |                                | just doesn't see ?
 \_______________\|  fax:    (404) 853-9378        |  - Bob Dylan




Author: rjl@f111.iassf.easams.com.au (Rohan LENARD)
Date: 30 Aug 1994 09:16:43 +1000
Raw View
In article <MAV.94Aug29101310@gaia.cc.gatech.edu>,
Maurizio Vitale <mav@cc.gatech.edu> wrote:
 >>>>>> "Ronald" == Ronald F Guilmette <rfg@netcom.com> writes:
 >
 >  Ronald> In article <33b7ks$6fv@flclcnsa.clc.gmeds.com> bhenk02@cps.plnin.gmeds.com writes:
 >  >> I always find it somewhat frustrating that C++ (and C for that matter)
 >  >> does not "understand" that a.b and a->b (to me) mean the same thing.
 >
 >  Ronald> They DON'T mean the same thing... but if you want to program
 >  Ronald> in a language which tries to pretend that they do, try Ada.
 >
 >They don't mean the same thing in the very same way that 2 + 2 and 2.0
 >+ 2.0 don't mean the same thing. They both mean to use the member
 >named `b' inside the object denoted by `a'. The fact that `a' is a
 >user alterable pointer or a compiler+linker generated one is
 >irrelevant to the semantic of the operation "use the `b' member inside
 >`a'". It is true that C++ follows the C tradition on this, but there's
 >no technical reason to this as I don't believe there's a single case
 >in which the compiler cannot figure out what to do.

This isn't really true either.

Because the meaning of operator-> can be re-defined by the user,
 a.b and a->b can do significantly different things, while by default
they both access member b of object a.

While it would be possible to allow a.b and a->b to act the same, you
would only be able to do it sometimes, and would get error messages other
times (ie. the ones which have user defined operator->).  This would be
significantly more confusing than the current situation.  It is also a
significant divergence from the C practice and would likely break code meant
to be compiled with either a C or C++ compiler.


Regards,
 Rohan
--
----------------------------------------------------------------------------
rjl@iassf.easams.com.au | All quotes can be attributed to my automated quote
Rohan Lenard            | writing tool.  Yours for just $19.95; and if you
+61-2-367-4555          | call now you'll get a free set of steak knives ...




Author: daniels@biles.com (Brad Daniels)
Date: Tue, 30 Aug 1994 14:37:37 GMT
Raw View
In article <CvB8A8.L5q@borland.com>,
Pete Becker <pete@genghis.interbase.borland.com> wrote:
>In article <MCOOK.94Aug29124710@galaga.lna.logica.com>,
> <michaelc@lna.logica.com> wrote:
>>
>>The ANSI C people decided to let the compiler be smart enough to understand
>>that `pf()' is the same as `(*pf)()'.  Given that "prior art," letting the
>>compiler decide that `ps.m' is the same as `ps->m' seems natural.
>>
>
> class Implementor
> {
> public:
>  void f();
> };
>
> class User
> {
> public:
>  void f();
>  Implementor *operator->() const;
> };
>
> User u;
> u.f();
>
>u.f() better not be the same as u->f().
> -- Pete

I've been reading the suggestions as saying that there should be a bult-in
"." operator on pointers which essentially makes "." equivalent to "->".
It doesn't sound like a terrible idea, but I'd probably never use it...

- Brad
------------------------------------------------------------------
+ Brad Daniels           | "For all men would be cowards         +
+ Biles and Associates   |  if they durst."                      +
+ My views, not B&A's    |      - John Wilmot, Earl of Rochester +
------------------------------------------------------------------




Author: pete@genghis.interbase.borland.com (Pete Becker)
Date: Tue, 30 Aug 1994 16:50:27 GMT
Raw View
In article <CvCrAq.uu@biles.com>, Brad Daniels <daniels@biles.com> wrote:
>
>I've been reading the suggestions as saying that there should be a bult-in
>"." operator on pointers which essentially makes "." equivalent to "->".
>It doesn't sound like a terrible idea, but I'd probably never use it...
>

 And while we're at it, let's make constructor invocation implicitly
do a new if we're dealing with a pointer, and make delete a no-op if we
invoke it on an object. That makes it much more likely that people who don't
know what they're doing will be able to write code that compiles.
 -- Pete





Author: spitzak@hollywood.cinenet.net (Bill Spitzak)
Date: 30 Aug 1994 10:15:47 -0700
Raw View
rjl@f111.iassf.easams.com.au (Rohan LENARD) writes:

>> re: compiler can always tell when a.b would mean a->b

>This isn't really true either.

>Because the meaning of operator-> can be re-defined by the user,
> a.b and a->b can do significantly different things, while by default
>they both access member b of object a.

Yes, they would then do different things.  It is already true that
you can make a+=b different than a=a+b by redefining operators,
and I don't hear anybody complaining that this means that += and +
should be forced to be different by default!

The definition could be:
 a.b means the 'b' field in a, if there is a 'b' field.
 otherwise a.b means to use (typeofa)::operator->.

>While it would be possible to allow a.b and a->b to act the same, you
>would only be able to do it sometimes, and would get error messages other
>times (ie. the ones which have user defined operator->).  This would be
>significantly more confusing than the current situation.

Somebody making a smart pointer class and putting fields in that pointer
that have the same names as ones in the pointed-to class is asking for
trouble already.

>  It is also a
>significant divergence from the C practice and would likely break code meant
>to be compiled with either a C or C++ compiler.

a->b would still work and would be used if you want code to be read by
both C and C++ compilers.

I personally feel the idea would be a big win, allowing easy changing
of an algorithim and encouraging pointers to objects instead of the
huge time-sink of passing by copy and making some code more compact
and easier to read.  I would also like to see '::' replaced by '.', by
restricting types and variables to the same name space.  So there.

Bill Spitzak




Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Tue, 30 Aug 1994 18:24:14 GMT
Raw View
In article <rfgCvAIzr.I36@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>In article <33b7ks$6fv@flclcnsa.clc.gmeds.com> bhenk02@cps.plnin.gmeds.com writes:
>>I always find it somewhat frustrating that C++ (and C for that matter)
>>does not "understand" that a.b and a->b (to me) mean the same thing.
>
>They DON'T mean the same thing... but if you want to program in a language
>which tries to pretend that they do, try Ada.

 IF a is a pointer to a class of which b is a member

 a . b == &( a->b )

is the CORRECT definition -- if it were to be supported at all.



--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Tue, 30 Aug 1994 18:30:27 GMT
Raw View
In article <MCOOK.94Aug29124710@galaga.lna.logica.com> michaelc@lna.logica.com writes:
>>>>>> "mav" == Maurizio Vitale <mav@gaia.cc.gatech.edu> writes:
>
>    mav> It is true that C++ follows the C tradition on this, but there's no
>    mav> technical reason to this as I don't believe there's a single case in
>    mav> which the compiler cannot figure out what to do.
>
>The ANSI C people decided to let the compiler be smart enough to understand
>that `pf()' is the same as `(*pf)()'.  Given that "prior art," letting the
>compiler decide that `ps.m' is the same as `ps->m' seems natural.

 Nope, its completely wrong. The only sensible meaning
of ps.m is &(ps->m); that is, its the ADDRESS of the m member
of the object to which ps points.

 Similarly, the correct interpretation of

 ptm . m

is a pointer to member m. (Given ptm points to a member of
some class containing m). In general, the LHS of the .
operator should preserve its "kind" as a reference (lvalue),
pointer, or pointer to member when "adding" the offset of
some member .. it just moves the address "inwards",
in the struct.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: robtcram@crl.com (Robert H. Cram)
Date: 30 Aug 1994 12:44:52 -0700
Raw View
Pete Becker (pete@genghis.interbase.borland.com) wrote:
: In article <CvCrAq.uu@biles.com>, Brad Daniels <daniels@biles.com> wrote:
: >
: >I've been reading the suggestions as saying that there should be a bult-in
: >"." operator on pointers which essentially makes "." equivalent to "->".
: >It doesn't sound like a terrible idea, but I'd probably never use it...
: >

:  And while we're at it, let's make constructor invocation implicitly
: do a new if we're dealing with a pointer, and make delete a no-op if we
: invoke it on an object. That makes it much more likely that people who don't
: know what they're doing will be able to write code that compiles.
:  -- Pete





Author: tob@world.std.com (Tom O Breton)
Date: Tue, 30 Aug 1994 20:16:21 GMT
Raw View
I have been reading over the "." == "->" suggestion. At first I had two
doubts:

Would the gain to the user be worth the compiler effort?

        When I think about it, the change to the compiler is trivial and
        slightly beneficial. Already when parsing dot-operator or "->",
        you gotta look at what comes before it and check whether it's a
        pointer or a struct. Check whether it's the right one, Abort +
        error message if it's the wrong one.

        So the compiler actually becomes simpler (Assuming it's
        underlying design is halfway decent): Drop the check and apply
        dereference or not according to the preceding type.

        Obviously the check for a user-defined operator-> on finding no
        matching name would be applied after all this.

Would it screw up user-defined operator->?

        Not in a way the language should defend against, IMO. _Yes_,
        it's now possible to write more ambiguous things. Dealing with
        name-clashes is already part of defined operator->. Being _able_
        to write bad code has never been a C++ reason for not allowing
        something.

Would it deprive users of important error-checking?

        I don't buy that. In my experience, there are practically no
        cases where misapplying "." for "->" happens because the
        variable was the wrong one; practically always it's because the
        other structure-access operator was intended.

        Therefore IMO there is no significant error-checking coming out
        of this anyways.


The benefit of not having to swap "." and "->" when changing types is a
real one, and something I for one face frequently enough.

Therefore I think the proposal is very good, and almost free.

        Tom


PS: Tongue-in-cheek comment: I'm sure making the compiler's work easier
will be derided as "too hard" by one or more people... }:^

--
finger me for how Tehomega is coming along (at tob@world.std.com)
Author of The Burning Tower (from TomBreton@delphi.com) (weekly in
rec.games.frp.archives)





Author: aresrobin@aol.com (Ares Robin)
Date: 30 Aug 1994 20:00:14 -0400
Raw View
In article <CvD22s.D7F@ucc.su.OZ.AU>, maxtal@physics.su.OZ.AU (John Max
Skaller) writes:

>The only sensible meaning
>of ps.m is &(ps->m); that is, its the ADDRESS of the m member
>of the object to which ps points.

It's patently not the only sensible meaning, since a perfectly sensible
meaning (i.e. the same as 'operator ->')  is the topic of this thread.

> In general, the LHS of the .
>operator should preserve its "kind" as a reference (lvalue),
>pointer, or pointer to member when "adding" the offset of
>some member .. it just moves the address "inwards",
>in the struct.

Where did this come from? Since the constructs you're talking about aren't
legal, there's no basis for saying that 'operator .' "should" behave a
certain way.

Regards,
Robin




Author: r-ridge@calum.csclub.uwaterloo.ca (Ross Ridge)
Date: Wed, 31 Aug 1994 11:30:11 GMT
Raw View
John Max Skaller <maxtal@physics.su.OZ.AU> wrote:
> Similarly, the correct interpretation of
>
> ptm . m
>
>is a pointer to member m. (Given ptm points to a member of
>some class containing m).

Huh?  Do you mean something like this:

 struct foo { int m; int n; } x, *p = &x;
 int *ptm = &p.n;
 int *ptm_dot_m = ptm.m;
 assert(ptm_dot_m == &p.m);

or this:

 struct foo { int m; int n; };
 int foo::*ptm = &foo::n;
 int foo::*ptm_dot_m = ptm.m;
 assert(ptm_dot_m == &foo::m);

I really don't buy either interpretation.

      Ross Ridge





Author: bhenk02@cps.plnin.gmeds.com (Brian Henk)
Date: 22 Aug 1994 22:08:28 GMT
Raw View
I always find it somewhat frustrating that C++ (and C for that matter)
does not "understand" that a.b and a->b (to me) mean the same thing.
This is especially the case when I change the type from ptr to 'Thing' to
automatic and back.

Thing *a;
a->b(); // is valid, a.b() is not

Thing a;
a.b(); // is valid, a->b() is not

Is there a way that I can say:

Thing a;

a@b(); // I don't care if a is a ptr or not !

Then when I change to 'Thing *a;' I need not change 'a@b();'
{without macros please}




Author: craffert@csfb1.fir.fbc.com (Colin Owen Rafferty)
Date: Wed, 24 Aug 1994 17:24:45 GMT
Raw View
bhenk02@cps.plnin.gmeds.com (Brian Henk) writes:

> I always find it somewhat frustrating that C++ (and C for that matter)
> does not "understand" that a.b and a->b (to me) mean the same thing.
> This is especially the case when I change the type from ptr to 'Thing' to
> automatic and back.

Well, they don't mean the same thing.  What if you have operator->
overloaded for class A?  Then changing variable `a' from a pointer to an
object could be a pretty drastic change in meaning.

> Thing *a;
> a-> b(); // is valid, a.b() is not

> Thing a;
> a.b(); // is valid, a->b() is not

> Is there a way that I can say:

> Thing a;

> a@b(); // I don't care if a is a ptr or not !

> Then when I change to 'Thing *a;' I need not change 'a@b();'
> {without macros please}

What you could do is overload operator-> for all classes that you want
to have this ability, and just use a->b(); in all cases..

class A {
   public:
      A* operator->() { return this; }
      ...
};
--
Colin Rafferty          Work: (212) 909 4529    Beeper: (800) 225 0256 x311944
CS First Boston         Home: (212) 663 3401            (917) 321 1733
Work: <craffert@csfb1.fir.fbc.com>        Home: <colin@rafferty.com>
--
The biggest problem with C++ is not that it's complex or C compatible.
It's that not enough people know enough about it to train others.
                                -John (Max) Skaller