HDTenEightyP/NetNews huggingface dataset:
From: jss@lucid.com (Jerry Schwarz)
Subject: Re: pointer comparisons
Reply-To: jss@lucid.com (Jerry Schwarz)
Organization: Lucid, Inc.
Date: Thu, 7 Jan 93 02:59:48 GMT

We seem to be arguing as much about the meaning of terms
and the model that should be used to define the semantics of C++
as we are about what the semantics are or should be.  I don't
think this is a fruitful discussion, so I'm going to take a different
tack and present my point of view solely in terms of code.

	struct X { int i ; } ;
	struct D : public X {
		X xInD ;
	} ;

	void set(X* p, int n) { p->i = n ; }

	void f() {
	    D d ;
	    X* p1 = &d;
	    X* p2 = &d.xInD ;
	    set(p1, 1) ;
	    set(p2, 2) ;
	    d.i ; // must be 1 
	    d.xInD.i ; // must be 2 
	    p1 == p2 ; // ????
        }


I'm not sure I can prove the two assertions (d.i is 1 and d.xInD.i is 2)
from the ARM.  I know I can't do it without using phrases (like
distinct object) that I'm trying to avoid in this post.  But I hope
there is no doubt about the assertions.

The rest of this posting is my opinion about how C++ ought to
be defined (by x3j16/wg21).

I believe that p1==p2 ought to be false (i.e. 0).  I'm not sure
I can prove it from the ARM, but I have what I consider good
justification. Namely, the only way that "set" can operate properly
with regard to d.i and d.xInX.i is for there to be some difference in
the values of its first argument on the two calls. Whatever this difference
is, it ought to be reflected in the result of ==.  If words to force
that result aren't already in the working paper, then I support
a change to the working paper.  Otherwise == on pointers becomes
almost useless and we would have to invent something else
(a library function perhaps) to do a complete comparison of 
pointer values.  

If there are any implementations out there that for which p1==p2
might be true in the above example, I'd be interested in hearing
about them. 

I'm not going to propose any exact wording here or address the question
of whether words already exist in the ARM because any attempt would
drop me into the terminological tar pit.  But I will say that I don't
think those words should make a distinction between X's that have or
don't have data members, or virtuals, or pure virtuals or anything
else.

  -- Jerry Schwarz
















Newsgroups: comp.std.c++
From: greg@qualcom.qualcomm.com (Greg Noel)
Subject: Use of nested functions (Was: Proposal for default scope)
Organization: Qualcomm, Inc., San Diego, CA
Date: Fri, 8 Jan 1993 19:29:06 GMT

Fergus James HENDERSON <fjh@munta.cs.mu.OZ.AU> writes:
>Many people seem to think that the purpose of nested functions is purely
>as encapsulation, a sort of code organization/modularization feature.
>... the real reason that they are useful is that ... their addresses can
>be passed to any function that just expects a function parameter.
>If a local function never has its address taken, then it does not use
>the full power of nested functions.

This is a valid point, but this is exactly the part that is expensive to
implement.  The ``Spirit of C'' is that expensive things are exposed to
the programmer; C++ inherits much of this spirit.

If you look at what a compiler must do to implement this, it has to create
a ``structure'' (the stack frame) that contains all the local variables,
the parameters, and so forth, and arrange for the nested function to be
able to find that structure with a sort of implicit ``this'' pointer.  In
a heavily optimizing compiler that keeps many values in registers, it can
be costly to have to re-sync memory every time a nested function _might_
be invoked.

On top of that, if you wish a function to retain its scope during a potentially
recursive invocation, it means that the implicit ``this'' pointer must be
kept as a part of the pointer, which would increase the size of _every_
pointer, whether the feature is used or not.  That was a real killer for
PL/I function pointers and very much against the C philosophy.

(BTW, I'd like to have nested functions, but I would not make pointers to
them be compatible with a ``normal'' function pointer.  Nested functions
are handy to improve the clarity of code, but I'd want the compiler to
have total knowledge over when they were invoked and allow it to optimize
them as it saw fit, so that it could inline them or use special lightweight
calling sequences if it wished.  If a pointer syntax is needed, I'd make
it similar to the C++ class pointer notation, using the function name as
the class---after all, that's really what's going on....)

But, as others have pointed out, it's possible for you, the programmer, to
do the expensive thing that the compiler would have to do, by putting the
variables you need in a structure and keeping a pointer to it where the
helper function can find it.  I won't claim that it's fun to do it this
way, but this is essentially what the compiler would have to generate, so
the overhead would be the same.
-- 
-- Greg Noel, Unix Guru         greg@qualcomm.com  or  greg@noel.cts.com
Newsgroups: comp.std.c++
From: fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON)
Subject: Re: pointer comparisons
Organization: Computer Science, University of Melbourne, Australia
Date: Fri, 8 Jan 1993 01:16:39 GMT

jss@lucid.com (Jerry Schwarz) writes:

>I'm not going to propose any exact wording here or address the question
>of whether words already exist in the ARM because any attempt would
>drop me into the terminological tar pit.  But I will say that I don't
>think those words should make a distinction between X's that have or
>don't have data members, or virtuals, or pure virtuals or anything
>else.

I would tend to agree. But I think that it might very well be appropriate
for the commentary to contain something like

	- Note that the above wording implies that if a class has any data
	  members, then ... (some guarantee about pointer comparisons).

In other words, requirements for data members (or such-like) could be implicit
rather than explicit in the ARM.

-- 
Fergus Henderson             fjh@munta.cs.mu.OZ.AU      
This .signature virus is a self-referential statement that is true - but 
you will only be able to consistently believe it if you copy it to your own
.signature file!
Newsgroups: comp.std.c++
From: mike@taumet.com (Mike Ball)
Subject: Re: Use of nested functions (Was: Proposal for default scope)
Organization: TauMetric Corporation
Date: Sun, 10 Jan 1993 19:29:02 GMT

greg@qualcom.qualcomm.com (Greg Noel) writes:

>If you look at what a compiler must do to implement this, it has to create
>a ``structure'' (the stack frame) that contains all the local variables,
>the parameters, and so forth, and arrange for the nested function to be
>able to find that structure with a sort of implicit ``this'' pointer.  In
>a heavily optimizing compiler that keeps many values in registers, it can
>be costly to have to re-sync memory every time a nested function _might_
>be invoked.

Since you always have the full text of the nested function available, and
you know exactly which variables it references, and you know exactly which
function calls might call it, this cost is borne only when it is actually
needed.

>On top of that, if you wish a function to retain its scope during a potentially
>recursive invocation, it means that the implicit ``this'' pointer must be
>kept as a part of the pointer, which would increase the size of _every_
>pointer, whether the feature is used or not.  That was a real killer for
>PL/I function pointers and very much against the C philosophy.

Only function pointers, of course.  For those who hate this cost, the
GCC approach of generating a helper function on the stack works well.  Then
you pay a slightly higher cost for the invocation, but only when it is
actually necessary.

>(BTW, I'd like to have nested functions, but I would not make pointers to
>them be compatible with a ``normal'' function pointer.  Nested functions
>are handy to improve the clarity of code, but I'd want the compiler to
>have total knowledge over when they were invoked and allow it to optimize
>them as it saw fit, so that it could inline them or use special lightweight
>calling sequences if it wished.

It's not a compiler problem.  The compiler has all of the knowledge
it needs.  It's pretty hard to inline a function through a pointer, though.

The arguments against nested functions are primarily based on compatibility
with C and on not making unnecessary changes to the language.  Implementation
costs in the generated code are quite small, and are paid only when needed.
Pointers to nested functions also add yet another area of undefined
behavour, just like pointers to local variables.

I find that my style of programming in C++ pretty much (but not entirely)
eliminates the desire for nested functions as lexical closures, so I won't
argue for them very strongly.
-- 
Michael S. Ball (mike@taumet.com)
TauMetric Corporation
Newsgroups: comp.std.c++
From: feathers@serss0 (Michael Feathers)
Subject: Overloading operator delete
Organization: Florida International University, Miami
Date: Wed, 6 Jan 1993 03:20:00 GMT


I discovered the hard way a while ago that the operator delete can not be
overloaded in C++.

I've read the annotation in the ARM and I can not say that I agree with
the reasoning.  One example given for overloading operator new involves using 
another arena for allocation.  But how will this memory be deallocated? 

Doesn't the possibility of using the global delete accidently make the 
absence of an overloadable delete at least as "hazardous" as allowing it?

I understand that there are many applications in which programmers may not
be concerned with reclaiming memory, but aren't there enough to justify being
able to use operator delete symmetrically with operator new without resorting
to the work around discussed in the ARM?

The work around that I've choosen involves using a set of malloc/free type
functions since I have no means of using an overloaded delete symmetrically 
with an overloaded new.

Michael Feathers   [feathers@fiu.edu]



 










Newsgroups: comp.std.c++
From: pkt@lpi.liant.com (Scott Turner)
Subject: Re: pointer comparisons
Organization: Liant Software Corporation
Date: Tue, 5 Jan 1993 20:32:37 GMT

In article <1993Jan05.003819.12515@microsoft.com>, jimad@microsoft.com (Jim Adcock) writes:
> In article <1992Dec31.170223.21637@lpi.liant.com> pkt@lpi.liant.com (Scott Turner) writes:
> |In article <1992Dec30.184614.5551@microsoft.com> (Jim Adcock) writes:
> |> Can you define your terms for us?
> |
> |> "distinct objects" means what?
> |It means the objects are not identical.  
> 
> Which only leaves the issue of object identity.

Which is where I wish to leave the issue, willing to trust for the present
that objects which I wish distinct will be distinct.  This trust rests on

      1. The status of distinct objects as objects.

      2. The guarantee of 1.3 that an object occupies at least 1 byte
         of storage.

      3. The implementation's duty to reserve storage for objects.

If anyone can think of an example in which I am likely to be diappointed
and end up surprised with indistinct objects, I'd be grateful to see it.  
(Implementations which don't do their duty aren't necessarily a surprise.)

> Lots of other things remain unclear.  If a definition or a new expressions
> reserves the storage needed by an object, when and when not can other
> objects use this storage? [this is a trick question ;-]

I was responding to clarify a possible feature of pointer comparison.
To clarify everything is beyond me.

> |	The constructs in a C++ program create, refer to, access, and
> |	manipulate objects in memory.  Each object (except bit-fields)
> |	occupies one or more contiguous bytes.
> 
> Can other objects occupy those bytes?

Yes.  An _other_ object is distinct, not identical to the object with which
it shares storage.  For example, given
	int x[9];
then the bytes occupied by the objects x and x[2] overlap.

> |	Does it govern base class subobjects?  As I understand it,
> |	base class subobjects are objects, and hence are covered.
> 
> As I understand it, base class subobjects are NOT objects, because [...]
> Further it would violate the overlapping objects rule.  

What rule?

> Also, it would imply that deriving some class from some base class can cause
> a change in behavior of an "object" of that base class, and such flies
> in the face of reason [IMHO].  

If some class declares a virtual function, it's asking to be changeable.
--
Prescott K. Turner, Jr.
Liant Software Corp. (developers of LPI languages)
959 Concord St., Framingham, MA 01701 USA    (508) 872-8700
UUCP: uunet!lpi!pkt                          Internet: pkt@lpi.liant.com


Newsgroups: comp.std.c++
From: steve@taumet.com (Steve Clamage)
Subject: Re: initialized 'global' (extern) char arrays
Organization: TauMetric Corporation
Date: Thu, 7 Jan 1993 17:44:01 GMT

jimlynch@netcom.com (Jim Lynch) writes:

>I am given to understand that the storage allocated by

>char *x = "abcde" ;

>is not writable. In terms of whatever standard exists, is it exactly the same as

>const char *x = "abcde" ;  // ?

It is not exactly the same.  Whether literal strings are writeable is
up to the implementation, not mandated by the Standard.  The sequence
	char *p = "abcde";
	*p = 'z';
is allowed to succeed or fail.  The compiler is not obligated to warn you
that you are writing to readonly storage if that is the case.  For one
thing, it can't always tell.  Consider
	void foo(char *q) { *q = 'z'; }
This function could be called from another translation unit.  It is
legal to pass such a function a pointer to a literal string, and the
function doesn't know what is being passed to it.  It could fail only
at run time, absent cross-module type checking.

The sequence
	const char *p = "abcde";
	*p = 'z';
must be diagnosed as an error.  Type "const char*" is not the same
type as "char *".

Three rules for happy living:
1. Don't assume you can write to literal strings.
2. Don't assign or pass a literal string to a char*.
3. Declare a parameter to be const char* if the string is only read.
(Hmmm.  Maybe this is too narrow a view of happy living...)
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com
Newsgroups: comp.std.c++
From: fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON)
Subject: Re: C++ already *has* nested functions SO WHAT'S THE BEEF?
Keywords: nested functions, dumb ideas
Organization: Computer Science, University of Melbourne, Australia
Date: Fri, 8 Jan 1993 00:39:33 GMT

harvey@opl.com (Harvey Reed) writes:

>If programmers want nested functions, it sounds a lot like delegation which
>C++ can handle quite well, as is. Just delegate to another object, or
>your self. This leaves matters fairly explicit.

Two points: firstly, I would not agree that C++ (without overloadable
operator dot) handles delegation well; secondly, delegation can be used
as a poor man's substitute for nested functions, but it does *not* have
the same power/expressiveness that nested functions do. The classic
sort of example where nested functions are useful is

	somefunc(lots of complex parameters) {
	    lots of complex local variables;

	    int compare(const void *ptr1, const void *ptr2) {
		const object *x = (object *)ptr1;
		const object *y = (object *)ptr2;
		// compare x and y using some complex ordering which is
		// dependant on the above parameters and local variables
	    }

	    ...
	    qsort(object_array, n, sizeof(object), compare);
	    ...
	}

Because the interface to qsort() is fixed, the alternative is to use a rather
ugly hack using global variables (well, ok, you can make them file-scope
static variables rather than real global variables). Here delegation doesn't
help.

-- 
Fergus Henderson             fjh@munta.cs.mu.OZ.AU      
This .signature virus is a self-referential statement that is true - but 
you will only be able to consistently believe it if you copy it to your own
.signature file!
Newsgroups: comp.std.c++
From: jimad@microsoft.com (Jim Adcock)
Subject: Re: Nested functions (was: Re: Zero-length structures and pointer comparisons)
Date: 06 Jan 93 19:32:56 GMT
Organization: Microsoft Corporation

In article <4048@hpwala.wal.hp.com> pabloh@hpwala.wal.hp.com (Pablo Halpern ) writes:
|Absolute orderings are a slightly different matter.  In the case of < and
|>, one might expect a significant performance improvement if the pointers
|are assumed to point into the same array, since the segment part can be
|ignored even for far pointers.  A ptrcmp() function might be worthwhile and
|should present no special implementation problems for segmented
|architectures.  However, systems (like the lisp machine) where pointers
|change behind the program's back DO present a problem since the
|bit-pattern-based ordering could change even if the equality/inequality
|property does not change.  This would argue against *requiring* a ptrcmp()
|function.

Except some OS's using segmented architectures implement movable segments, 
in which case the problem becomes the same as lisp machines --
"pointers change behind the programmers back"

My claim is that in either of these cases the pointers *aren't* changing --
they still point at the same objects.  What is changing is the underlying
implementation of the pointer, which is an implementation issue not
a language issue.  Casting pointers to and from int remains as always
implementation dependent.  The only issue in question is whether we
should introduce a new requirement on OS's that the OS must maintain
a total ordering on their objects.  Clearly IMHO this would represent
a stumbling block to many OS's, such a the lisp machines, movable segment
OS's and OO databases.  Making such a new requirement on C++ would make
C++ not reasonably portable to these systems.  The question then is
whether or not the standard C++ language should exist on such machines.
Newsgroups: comp.std.c++
From: jimlynch@netcom.com (Jim Lynch)
Subject: initialized 'global' (extern) char arrays
Organization: Netcom Online Communications Services (408-241-9760 login: guest)
Date: Thu, 7 Jan 1993 03:24:58 GMT

I am given to understand that the storage allocated by

char *x = "abcde" ;

is not writable. In terms of whatever standard exists, is it exactly the same as

const char *x = "abcde" ;  // ?

The reason I ask is that I used such a construct in gcc-2.3.2 (yes, I plan to
upgrade) as follows:

char *x = "some string" ;

main()
{
    something(x[0]) ;
}

where the prototype for something looks like

void something(char &z) ;

and modifies that which is referred to by z.

So when something() got around to modifying, the system dumped core, claiming
a segmentation fault. Shouldn't the compiler have warned me?

Also, some internal issues:

Assuming that x is a const char *, does the C compiler see the argument to
something() in main() as needing a type conversion from const char to plain
ol' char? If so, shouldn't the compiler warn about this (possibly probematic)
kind of conversion?

Someone told me that even though the ANSI standard says that x is unwritable,
the compiler won't implement this by making it a const. My feeling is that this
is a mistake: unwritable should imply const (although my assumption was the
other way around: unwritable is implemented through using const.)

-Jim

Newsgroups: comp.std.c++
From: feathers@serss0 (Michael Feathers)
Subject: Re: Overloading operator delete
Organization: Florida International University, Miami
Date: Wed, 6 Jan 1993 12:12:54 GMT

I am the author of this article.  I just realized that I did not explain 
thoroughly.  

In article <C0Ex9D.Ct7@fiu.edu> feathers@serss0 (Michael Feathers) writes:
>
>I discovered the hard way a while ago that the operator delete can not be
>overloaded in C++.

That is, overload operator delete with the placement syntax.  We can provide
extra versions of operator new with an arbitrary number of additional 
arguments, but there can be no additional arguments to delete other than 
those specified in the ARM.

I don't have the ARM at home with me right now, so I can not recite chapter
and verse.

>I've read the annotation in the ARM and I can not say that I agree with
>the reasoning.  One example given for overloading operator new involves using 
>another arena for allocation.  But how will this memory be deallocated? 
>
>Doesn't the possibility of using the global delete accidently make the 
>absence of an overloadable delete at least as "hazardous" as allowing it?
>
>I understand that there are many applications in which programmers may not
>be concerned with reclaiming memory, but aren't there enough to justify being
>able to use operator delete symmetrically with operator new without resorting
>to the work around discussed in the ARM?
>
>The work around that I've choosen involves using a set of malloc/free type
>functions since I have no means of using an overloaded delete symmetrically 
>with an overloaded new.
>
>Michael Feathers   [feathers@fiu.edu]
>
>

Michael Feathers [feathers@fiu.edu]


Newsgroups: comp.std.c++
From: pkt@lpi.liant.com (Scott Turner)
Subject: Re: pointer comparisons
Organization: Liant Software Corporation
Date: Mon, 11 Jan 1993 19:09:59 GMT

In article <1357@pivot-sts.sbi.com>, linke@sbi.sbi.com (User - Bill Linke) writes:
> In article <1993Jan7.145511.718@lpi.liant.com>, pkt@lpi.liant.com (Scott Turner) writes:
> > 
> > Identity of objects is more of the essence than storage, so it would be
> > problematic to define the former in terms of the latter.
> 
> Even this is not so clear, is it?  

It may be worth discussing.

> "Identity" means to me that we can
> distinguish between two instances of a class 

Yes.

> using only the attributes of the class itself
> (i.e. without using anything from derived classes which the class
> might happen to be a base class of). This in turn implies that somewhere
> within each instance is some storage which conceptually could hold some
> identifying value.  (Otherwise, there would be no way for two instances to
> have different attributes.)

How could this argument be meaningful?  If I have
       int x=2, y=2;
then in a typical implementation x and y are names of distinct objects,
each of which has storage.  We can conceive of an atypical implementation
which extra allows storage for identifying x and y with distinct keys.  But for
practical purposes all that's necessary is that x and y have different
addresses.  Whether or not the storage can conceptually hold an identifying
value doesn't matter.

If we have objects of a type which requires no state, e.g.
       struct {} a, b;
then in order for them to have distinct identities an implementation
might allocate addresses that don't point to valid memory.  Again, no
storage is required.


When I say that identity of objects is more of the essence than storage,
here's the kind of thing I have in mind:
       int x=2, y=2;
       y = 3;
       // Now the value of x is 2, not 3.  
Why?  Because the declaration defines 2 distinct objects named x and y. 

To explain it in terms of storage is more obscure.  One would
have to say that the storage reserved for the definition of x
is required not to overlap the storage reserved for the definition of y.  
And also mention that the state of the objects x and y resides in the 
storage reserved by their definitions.
--
Prescott K. Turner, Jr.
Liant Software Corp. (developers of LPI languages)
959 Concord St., Framingham, MA 01701 USA    (508) 872-8700
UUCP: uunet!lpi!pkt                          Internet: pkt@lpi.liant.com
Newsgroups: comp.std.c++
From: dwr@cci632.cci.com (Donald W. Rouse II)
Subject: Re: Compiler should generate virtual destructors
Organization: [Computer Consoles, Inc., Rochester, NY
Date: Wed, 6 Jan 1993 19:12:59 GMT

In article <lkc2k7INNajv@exodus.Eng.Sun.COM> db@argon.Eng.Sun.COM (David Brownell) writes:
>   (2a)	C++ compilers don't automagically generate ANYTHING for classes
>	any more:  constructors, destructors, assignment and address-of
>	operators, etc.  If such routines are used but not declared and
>	defined, that is an error.
>

The problem with this is that struct == class with all members public.
This would break much C code.
Better would be for the compiler not to generate default stuff
if _any_ constructor or destructor (or op=) is declared for a class;
elsewise, generate if nec.
Newsgroups: comp.std.c++