www.digitalmars.com         C & C++   DMDScript  

D - Question: Why Are All Class Objects on the Heap?

reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
I just wondered, Walter, if you would explain your reasoning why all
class objects are allocated on the heap?  Stack objects, not subject to
garbage collection and automatically cleaned up when the reference goes
out of scope, would give programmers some flexibility...and improve
program performance by reducing the number of objects that must be
considered by the garbage collector.

--
The Villagers are Online! villagersonline.com

.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]
May 29 2002
next sibling parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3CF4F102.D7F03F0C deming-os.org...

 I just wondered, Walter, if you would explain your reasoning why all
 class objects are allocated on the heap?  Stack objects, not subject to
 garbage collection and automatically cleaned up when the reference goes
 out of scope, would give programmers some flexibility...and improve
 program performance by reducing the number of objects that must be
 considered by the garbage collector.
It was done because objects on stack will have to be cleaned up properly in case of exceptions, thus complicating the rules of objects finalization (when the destructors get called, etc). Stack unwinding in C++ was quite a complex process, and I guess Walter doesn't want to see it in D. By the way, did you notice that many languages have also made the same decision? In Delphi, you can only declare objects on heap
May 29 2002
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Pavel Minayev wrote:

 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:3CF4F102.D7F03F0C deming-os.org...

 It was done because objects on stack will have to be cleaned up
 properly in case of exceptions, thus complicating the rules
 of objects finalization (when the destructors get called, etc).
 Stack unwinding in C++ was quite a complex process, and I guess
 Walter doesn't want to see it in D.
I read about that on the garbage collection page. But I thought that he was saying that since the garbage collector reduces the need for destructors, we get simpler unwinding. I guess I see how it makes the exception code simpler without stack objects, but the price of not having stack objects seems high. As I see it, declaring a stack objects means two things: * The compiler adds a "delete obj;" line in the "finally" block for that block of code. * The compiler doesn't add the object to the garbage collection table. Since the compiler already supports "finally" blocks, how much complexity does this really add?
 By the way, did you notice that many languages have also made the
 same decision? In Delphi, you can only declare objects on heap

I must admit that my knowledge of languages (other than C/C++/D) is limited. I found one and stuck with it. I've done a little Java (when college classes required it) and learned the basics of PERL for work...but I head back to C++ as soon as I get a chance. (And C++ will vanish as soon, in favor of D.) -- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
May 29 2002
parent reply "Sandor Hojtsy" <hojtsy index.hu> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3CF503BB.90F84DA1 deming-os.org...
 Pavel Minayev wrote:
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:3CF4F102.D7F03F0C deming-os.org...

 It was done because objects on stack will have to be cleaned up
 properly in case of exceptions, thus complicating the rules
 of objects finalization (when the destructors get called, etc).
 Stack unwinding in C++ was quite a complex process, and I guess
 Walter doesn't want to see it in D.
I read about that on the garbage collection page. But I thought that he
was
 saying that since the garbage collector reduces the need for destructors,
we
 get simpler unwinding.  I guess I see how it makes the exception code
simpler
 without stack objects, but the price of not having stack objects seems
high.
 As I see it, declaring a stack objects means two things:
     * The compiler adds a "delete obj;" line in the "finally" block for
that
 block of code.
     * The compiler doesn't add the object to the garbage collection table.

 Since the compiler already supports "finally" blocks, how much complexity
 does this really add?
Good point. Since D already have to do "finally-unwinding", I don't see much difference in destructing objects on the stack with stack unwinding. Is there a problem with pointers stored inside non-garbage collected objects pointing to garbage collected ones?
 By the way, did you notice that many languages have also made the
 same decision? In Delphi, you can only declare objects on heap

IMHO, in these languages this decision was made because the designers thought that this will help people to learn the language, and understand other developers code. They simply removed a feature, because it can be replaced by an other already implemented one (heap). I don't think they considered compiler complexity here. This was an important decision. They made great success in the domain of the beginners with it, and similar ones. But professionals don't like to see useful features disappear. Easy usage for the beginner is not the same as easy usage for the professional. The kind of thinking that resulted in removing stack objects among others, blocks all these languages way to become a truly general purpose language. Yours, Sandor
May 30 2002
parent reply "anderson" <anderson firestar.com.au> writes:
 Is there a problem with pointers stored
  inside non-garbage collected objects pointing to garbage collected ones?
Does D support automatic copy constuctors that traverse the object tree (ptrs and stuff)? Because if it does, I'd have-it-a-guess that copy and del would be quite simular operations (not in function but in general design). But correct me if I'm wrong.
May 30 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"anderson" <anderson firestar.com.au> wrote in message
news:ad5d48$1kdd$1 digitaldaemon.com...

 Does D support automatic copy constuctors that traverse the object tree
 (ptrs and stuff)?  Because if it does, I'd have-it-a-guess that copy and
del
 would be quite simular operations (not in function but in general design).
 But correct me if I'm wrong.
D doesn't have copy constructors at all because you never work with objects, but always with references. So "A = B" means "let A point to the same object as B". No copy occures.
May 30 2002
next sibling parent "OddesE" <OddesE_XYZ hotmail.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:ad5kl4$24tc$1 digitaldaemon.com...
 "anderson" <anderson firestar.com.au> wrote in message
 news:ad5d48$1kdd$1 digitaldaemon.com...

 Does D support automatic copy constuctors that traverse the object tree
 (ptrs and stuff)?  Because if it does, I'd have-it-a-guess that copy and
del
 would be quite simular operations (not in function but in general
design).
 But correct me if I'm wrong.
D doesn't have copy constructors at all because you never work with objects, but always with references. So "A = B" means "let A point to the same object as B". No copy occures.
But it should have an assignment operator! Yes, I keep trying... :) -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net _________________________________________________ Remove _XYZ from my address when replying by mail
May 30 2002
prev sibling parent reply "anderson" <anderson firestar.com.au> writes:
Oh, I really liked the copy constructor. I suppose I can create one manually
using a method called copy, but that's not standarised like the copy and
conversion constructors.

"Pavel Minayev" <evilone omen.ru> wrote in message
news:ad5kl4$24tc$1 digitaldaemon.com...
 "anderson" <anderson firestar.com.au> wrote in message
 news:ad5d48$1kdd$1 digitaldaemon.com...

 Does D support automatic copy constuctors that traverse the object tree
 (ptrs and stuff)?  Because if it does, I'd have-it-a-guess that copy and
del
 would be quite simular operations (not in function but in general
design).
 But correct me if I'm wrong.
D doesn't have copy constructors at all because you never work with objects, but always with references. So "A = B" means "let A point to the same object as B". No copy occures.
I used the copy constuctor for pointers in C++ like, class A = new class(B); And I do no that D defaults all objects to pointers.
May 31 2002
next sibling parent "Pavel Minayev" <evilone omen.ru> writes:
"anderson" <anderson firestar.com.au> wrote in message
news:ad7a38$1r7f$1 digitaldaemon.com...

 Oh, I really liked the copy constructor. I suppose I can create one
manually
 using a method called copy, but that's not standarised like the copy and
 conversion constructors.
I guess what Walter wants is to standartise this. I guess you'll have a method named dup(), which is supposed to copy an object. So it is standartized.
May 31 2002
prev sibling parent "Matthew Wilson" <dm synesis-group.com> writes:
Guys

Please berate be if I'm being dumb (it's a bit early here), but why is the
following not a reasonable solution to this whole issue:

All instances of one type of class (let's say as denoted by the "class"
keyword) are created on the heap. These types have a destructor.
All instances of another type of class (let's say as denoted by the "struct"
keyword) are created on the stack. These types also have a destructor.

The heap instances are manipulated through references.
The references are implemented as struct types (whose implementation is
hidden in the implementation). All reference arguments are call-by-value
(which is ok, since they are totally lightweight - usually having a
reference count integral, and the referent pointer), so taking copies
(whether as members, discrete variables or function arguments) manipulated
the reference count consistently.

When a reference goes out of scope its destructor (which is called
deterministically at the exit of its defining scope), causes the reference
count of its referent to be decremented.

When the class type class (sic.) has its reference count drop to zero, its
destructor is called, and then its memory is put into the garbage collector.
This way, we get deterministic destruction (yeeaaahhh!) whilst still having
a garbage collector for better memory performance.

The problems of unwinding of complex class types is simplified, since all
that has to be unwound is the references themselves, in releasing their
referent (though of course destruction of the referents would have to be
effected at that time if rc == 0).

I've implemented a junior version of this a few times previously, with great
success (in C++ of course).

The only issue I can think of (I'm sure you'll hit me with more) is how one
passes an instance of the struct type. Since they cannot be allocated
dynamically there is no possibility of a leak. Passing them to functions can
be done as const and non-const reference (the C++ meaning, rather than a
"reference" type") and they are returned by value (using shallow-copy in
abscence of explicit copy-ctor)

Give me your best criticism ...

Matthew

"anderson" <anderson firestar.com.au> wrote in message
news:ad7a38$1r7f$1 digitaldaemon.com...
 Oh, I really liked the copy constructor. I suppose I can create one
manually
 using a method called copy, but that's not standarised like the copy and
 conversion constructors.

 "Pavel Minayev" <evilone omen.ru> wrote in message
 news:ad5kl4$24tc$1 digitaldaemon.com...
 "anderson" <anderson firestar.com.au> wrote in message
 news:ad5d48$1kdd$1 digitaldaemon.com...

 Does D support automatic copy constuctors that traverse the object
tree
 (ptrs and stuff)?  Because if it does, I'd have-it-a-guess that copy
and
 del
 would be quite simular operations (not in function but in general
design).
 But correct me if I'm wrong.
D doesn't have copy constructors at all because you never work with objects, but always with references. So "A = B" means "let A point to the same object as B". No copy occures.
I used the copy constuctor for pointers in C++ like, class A = new class(B); And I do no that D defaults all objects to pointers.
Jun 12 2002
prev sibling next sibling parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
I've heard from everybody but Walter, it seems.  What is your reasoning,
Walter?

Russ Lewis wrote:

 I just wondered, Walter, if you would explain your reasoning why all
 class objects are allocated on the heap?  Stack objects, not subject to
 garbage collection and automatically cleaned up when the reference goes
 out of scope, would give programmers some flexibility...and improve
 program performance by reducing the number of objects that must be
 considered by the garbage collector.

 --
 The Villagers are Online! villagersonline.com

 .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
 .[ (a version.of(English).(precise.more)) is(possible) ]
 ?[ you want.to(help(develop(it))) ]
-- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
May 31 2002
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3CF4F102.D7F03F0C deming-os.org...
 I just wondered, Walter, if you would explain your reasoning why all
 class objects are allocated on the heap?  Stack objects, not subject to
 garbage collection and automatically cleaned up when the reference goes
 out of scope, would give programmers some flexibility...and improve
 program performance by reducing the number of objects that must be
 considered by the garbage collector.
There are stack based objects in D, they are structs. Structs are lightweight objects, with no virtual functions and no destructors. Reasons for not putting class objects on the stack: 1) no need for complicated and buggy rules about when objects get destructed. 2) no scoping rules for temporaries. 3) no need for copy constructors and assignment overloading - a large simplification. In C++, you cannot escape dealing with them. In D, no need to worry about them. 4) no worries/bugs about value vs reference semantics. 5) no need for a reference operator (the & in C++). 6) no need to worry about the difference between new and new[].
Jun 11 2002
next sibling parent reply "Matthew Wilson" <dmd synesis.com.au> writes:
Walter

Our exchange a few days ago seemed to have you moving towards deterministic
destructors. I was being titillated by the prospect of my class instances
cleaning up after themselves, for nought but a bit of pain on your part.

You now seem to be swaying back to the dark side. Is your swing irrevocable,
or might you still be amenable to some heartfelt petitioning?

Matthew

"Walter" <walter digitalmars.com> wrote in message
news:ae4dgl$1v5h$1 digitaldaemon.com...
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:3CF4F102.D7F03F0C deming-os.org...
 I just wondered, Walter, if you would explain your reasoning why all
 class objects are allocated on the heap?  Stack objects, not subject to
 garbage collection and automatically cleaned up when the reference goes
 out of scope, would give programmers some flexibility...and improve
 program performance by reducing the number of objects that must be
 considered by the garbage collector.
There are stack based objects in D, they are structs. Structs are lightweight objects, with no virtual functions and no destructors. Reasons for not putting class objects on the stack: 1) no need for complicated and buggy rules about when objects get destructed. 2) no scoping rules for temporaries. 3) no need for copy constructors and assignment overloading - a large simplification. In C++, you cannot escape dealing with them. In D, no need to worry about them. 4) no worries/bugs about value vs reference semantics. 5) no need for a reference operator (the & in C++). 6) no need to worry about the difference between new and new[].
Jun 11 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Matthew Wilson" <dmd synesis.com.au> wrote in message
news:ae4pib$2b0f$1 digitaldaemon.com...
 Walter

 Our exchange a few days ago seemed to have you moving towards
deterministic
 destructors. I was being titillated by the prospect of my class instances
 cleaning up after themselves, for nought but a bit of pain on your part.

 You now seem to be swaying back to the dark side. Is your swing
irrevocable,
 or might you still be amenable to some heartfelt petitioning?

 Matthew
The desire for deterministic destructors is greater than I'd anticipated.
Jun 11 2002
parent reply "Matthew Wilson" <dmd synesis.com.au> writes:
For me it seems like the make or break.



lot's of corporate buy-in) will not sufficiently distinguish D in the minds
of "managers". But were D to employ deterministic destructors, the push will
come from software engineers (=== people who use C++ ;), since the Java/.NET
Finalize model is almost universally unpopular with such

I know it's more effort for you, but think of the pay off!!

"Walter" <walter digitalmars.com> wrote in message
news:ae5kar$60s$1 digitaldaemon.com...
 "Matthew Wilson" <dmd synesis.com.au> wrote in message
 news:ae4pib$2b0f$1 digitaldaemon.com...
 Walter

 Our exchange a few days ago seemed to have you moving towards
deterministic
 destructors. I was being titillated by the prospect of my class
instances
 cleaning up after themselves, for nought but a bit of pain on your part.

 You now seem to be swaying back to the dark side. Is your swing
irrevocable,
 or might you still be amenable to some heartfelt petitioning?

 Matthew
The desire for deterministic destructors is greater than I'd anticipated.
Jun 11 2002
parent reply "Robert W. Cunningham" <rcunning acm.org> writes:
Matthew Wilson wrote:



 lot's of corporate buy-in) will not sufficiently distinguish D in the minds
 of "managers". But were D to employ deterministic destructors, the push will
 come from software engineers (=== people who use C++ ;), since the Java/.NET
 Finalize model is almost universally unpopular with such
the .NET runtime! Which in turn needs a bloated OS under it. Current rumor has it that there are problems getting .NET ported to Microsoft's "other" platform, MacOS X. Features being discussed for D make it a strong contender for the embedded market. Over 85% of all microprocessors sold go into the embedded market. You probably own over 30 microprocessors yourself, but only one of them is in your PC. The majority of software applications you interact with on a daily basis do not run on a PC. They run your microwave, refrigerator, phone, car, TV, remote control, VCR, radio, CD player. monitor, keyboard, mouse, ... There more code written for the PC than for embedded systems, but much of that code is never used, and never sees the light of day. It is not successful code. A much higher proportion of embedded code actually ships. There is more code running in embedded systems than in all the world's PCs combined. Put D where embedded programmers can use it, and it will be everywhere. At least .NET is abstracting the custom code from the bulk. An application is being written at work, the GUI for the embedded product I'm building, it is fits on a floppy (though I didn't put it on one, of course). MFC is dead. Microsoft killed it with .Net. Thank God I never learned MFC or the underlying Windows API. And VS.Net may even wind up killing the beast that is C++. (C++ never made much of a dent in the embedded world.) Remember, the QNX folks put an entire real-time PC Web server on a floppy, including the OS and networking stacks, with no need for 60 MB of support code and an OS that now consumes nearly a gigabyte of disk. These are the opposite extremes of the PC application world. I think we'll do even better with D: Bigger and better apps that go fast, are also fast to code and debug. This is what comes when the language is targeted to the happy middle between power, features and simplicity. In that part of the world where Windows is running on multi-gigahertz That leaves the rest of the world for D. Aim there. -BobC
Jun 11 2002
next sibling parent reply "Matthew Wilson" <dm synesis-group.com> writes:
Once again, I agree almost entirely. Where I differ is that I am a little
more circumspect wrt what may eventuate, since I believe we should not
underestimate the commercial might of M$ (clearly one is unable to
underestimate their technical might :).

My original point stands in concert with yours. We should aim to have D be
all that M$'s offspring are not: small, efficient, advanced but not bloated,
answering the needs of developers and compiler walters equally. That means
embedded, powerful syntax, proper dtors, and many of the other goodies that
have been mentioned lately

"Robert W. Cunningham" <rcunning acm.org> wrote in message
news:3D06C338.49A0D997 acm.org...
 Matthew Wilson wrote:


still

so
 lot's of corporate buy-in) will not sufficiently distinguish D in the
minds
 of "managers". But were D to employ deterministic destructors, the push
will
 come from software engineers (=== people who use C++ ;), since the
Java/.NET
 Finalize model is almost universally unpopular with such
of
 the .NET runtime!  Which in turn needs a bloated OS under it.

 Current rumor has it that there are problems getting .NET ported to
Microsoft's
 "other" platform, MacOS X.


Windows.
 Features being discussed for D make it a strong contender for the embedded
 market.  Over 85% of all microprocessors sold go into the embedded market.
You
 probably own over 30 microprocessors yourself, but only one of them is in
your
 PC.  The majority of software applications you interact with on a daily
basis
 do not run on a PC.  They run your microwave, refrigerator, phone, car,
TV,
 remote control, VCR, radio, CD player. monitor, keyboard, mouse, ...

 There more code written for the PC than for embedded systems, but much of
that
 code is never used, and never sees the light of day.  It is not successful
 code.  A much higher proportion of embedded code actually ships.  There is
more
 code running in embedded systems than in all the world's PCs combined.

 Put D where embedded programmers can use it, and it will be everywhere.

 At least .NET is abstracting the custom code from the bulk.  An
application is
 being written at work, the GUI for the embedded product I'm building, it
is

today
 fits on a floppy (though I didn't put it on one, of course).

 MFC is dead.  Microsoft killed it with .Net.  Thank God I never learned
MFC or
 the underlying Windows API.  And VS.Net may even wind up killing the beast
that
 is C++.  (C++ never made much of a dent in the embedded world.)

 Remember, the QNX folks put an entire real-time PC Web server on a floppy,
 including the OS and networking stacks, with no need for 60 MB of support
code
 and an OS that now consumes nearly a gigabyte of disk.

 These are the opposite extremes of the PC application world.

 I think we'll do even better with D:  Bigger and better apps that go fast,
are
 also fast to code and debug.  This is what comes when the language is
targeted
 to the happy middle between power, features and simplicity.



 In that part of the world where Windows is running on multi-gigahertz


 That leaves the rest of the world for D.

 Aim there.


 -BobC
Jun 11 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Matthew Wilson" <dm synesis-group.com> wrote in message
news:ae6hk3$13h0$1 digitaldaemon.com...
 answering the needs of developers and compiler walters equally.
As a "compiler walter", I agree <g>.
Jun 11 2002
parent reply "Sean L. Palmer" <seanpalmer earthlink.net> writes:
9 out of 10 compiler walters agree that D is spiffy.

Sean

"Walter" <walter digitalmars.com> wrote in message
news:ae6omh$1aen$1 digitaldaemon.com...
 "Matthew Wilson" <dm synesis-group.com> wrote in message
 news:ae6hk3$13h0$1 digitaldaemon.com...
 answering the needs of developers and compiler walters equally.
As a "compiler walter", I agree <g>.
Jun 11 2002
parent "Matthew Wilson" <dmd synesis.com.au> writes:
Have I coined a new term? :-)

"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message
news:ae6qql$1cil$1 digitaldaemon.com...
 9 out of 10 compiler walters agree that D is spiffy.

 Sean

 "Walter" <walter digitalmars.com> wrote in message
 news:ae6omh$1aen$1 digitaldaemon.com...
 "Matthew Wilson" <dm synesis-group.com> wrote in message
 news:ae6hk3$13h0$1 digitaldaemon.com...
 answering the needs of developers and compiler walters equally.
As a "compiler walter", I agree <g>.
Jun 12 2002
prev sibling parent "Matthew Wilson" <dm synesis-group.com> writes:
btw, Robert, this sounds like another opinion peice for "The D Journal"

"Robert W. Cunningham" <rcunning acm.org> wrote in message
news:3D06C338.49A0D997 acm.org...
 Matthew Wilson wrote:


still

so
 lot's of corporate buy-in) will not sufficiently distinguish D in the
minds
 of "managers". But were D to employ deterministic destructors, the push
will
 come from software engineers (=== people who use C++ ;), since the
Java/.NET
 Finalize model is almost universally unpopular with such
of
 the .NET runtime!  Which in turn needs a bloated OS under it.

 Current rumor has it that there are problems getting .NET ported to
Microsoft's
 "other" platform, MacOS X.


Windows.
 Features being discussed for D make it a strong contender for the embedded
 market.  Over 85% of all microprocessors sold go into the embedded market.
You
 probably own over 30 microprocessors yourself, but only one of them is in
your
 PC.  The majority of software applications you interact with on a daily
basis
 do not run on a PC.  They run your microwave, refrigerator, phone, car,
TV,
 remote control, VCR, radio, CD player. monitor, keyboard, mouse, ...

 There more code written for the PC than for embedded systems, but much of
that
 code is never used, and never sees the light of day.  It is not successful
 code.  A much higher proportion of embedded code actually ships.  There is
more
 code running in embedded systems than in all the world's PCs combined.

 Put D where embedded programmers can use it, and it will be everywhere.

 At least .NET is abstracting the custom code from the bulk.  An
application is
 being written at work, the GUI for the embedded product I'm building, it
is

today
 fits on a floppy (though I didn't put it on one, of course).

 MFC is dead.  Microsoft killed it with .Net.  Thank God I never learned
MFC or
 the underlying Windows API.  And VS.Net may even wind up killing the beast
that
 is C++.  (C++ never made much of a dent in the embedded world.)

 Remember, the QNX folks put an entire real-time PC Web server on a floppy,
 including the OS and networking stacks, with no need for 60 MB of support
code
 and an OS that now consumes nearly a gigabyte of disk.

 These are the opposite extremes of the PC application world.

 I think we'll do even better with D:  Bigger and better apps that go fast,
are
 also fast to code and debug.  This is what comes when the language is
targeted
 to the happy middle between power, features and simplicity.



 In that part of the world where Windows is running on multi-gigahertz


 That leaves the rest of the world for D.

 Aim there.


 -BobC
Jun 11 2002
prev sibling parent reply "Sandor Hojtsy" <hojtsy index.hu> writes:
"Walter" <walter digitalmars.com> wrote in message
news:ae4dgl$1v5h$1 digitaldaemon.com...
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:3CF4F102.D7F03F0C deming-os.org...
 I just wondered, Walter, if you would explain your reasoning why all
 class objects are allocated on the heap?  Stack objects, not subject to
 garbage collection and automatically cleaned up when the reference goes
 out of scope, would give programmers some flexibility...and improve
 program performance by reducing the number of objects that must be
 considered by the garbage collector.
There are stack based objects in D, they are structs. Structs are lightweight objects, with no virtual functions and no destructors. Reasons for not putting class objects on the stack: 1) no need for complicated and buggy rules about when objects get destructed. 2) no scoping rules for temporaries. 3) no need for copy constructors and assignment overloading - a large simplification. In C++, you cannot escape dealing with them. In D, no need to worry about them. 4) no worries/bugs about value vs reference semantics. 5) no need for a reference operator (the & in C++). 6) no need to worry about the difference between new and new[].
I think the main point here is not that any objects should be actually on the stack, but some of them should behave as-if. - some of them be constructed as-if - some of them be destructed as-if For example in the two syntax suggars I already proposed elsewhere ("owned" and "new"), int fn() { owned ResourceWrapper r1 = new ResourceWrapper("com1"); new Someting s; new owned ResourceWrapper r2("com2", s); whatever(r1); whatever(r2); } meaning: int fn() { ResourceWrapper r1 = new ResourceWrapper("com1"); try { Something s = new Something; ResourceWrapper r2 = new ResourceWrapper("com2", s); try { whatever(r1); whatever(r2); } finally delete r2; } finally delete r1; } And s, r1 and r2 are still references of course. I don't see any of the listed problems here. Sandor
Jun 11 2002
next sibling parent reply "Juan Carlos Arevalo Baeza" <jcab roningames.com> writes:
"Sandor Hojtsy" <hojtsy index.hu> wrote in message
news:ae53cg$2lg7$1 digitaldaemon.com...

 int fn()
 {
   owned ResourceWrapper r1 = new ResourceWrapper("com1");
   new Someting s;
   new owned ResourceWrapper r2("com2", s);
   whatever(r1);
   whatever(r2);
 }

 meaning:

 int fn()
 {
    ResourceWrapper r1 = new ResourceWrapper("com1");
    try {
      Something s = new Something;
      ResourceWrapper r2 = new ResourceWrapper("com2", s);
      try {
        whatever(r1);
        whatever(r2);
      } finally delete r2;
    } finally delete r1;
 }

 And s, r1 and r2 are still references of course. I don't see any of the
 listed problems here.
The problem is in the semantics and potential hidden bugs in the program. I'm not sure what D specifies will happen if you explicitly "delete" an object (you _could_ explicitly delete an object, couldn't you?) and then try to use it (for example, if "whatever()" leaves copies of the reference lying around). Still, I believe Walter's express desire is that such a dangerous "delete" shouldn't happen behind the programmer's back. Dangerous statements like that one are necessary to enhance the programmer's arsenal, but they are indeed problematic when they happen without the programmer's awareness of it. For example, the same argument applies (arguably) to overloaded operators, which have been discussed here before. There is a flaw in your approach, though. I think. I can't find proper documentation about the "finally" clause, but I believe it doesn't run if you just "return" from inside of the "try" block: int fn() { ResourceWrapper r1 = new ResourceWrapper("com1"); try { if (whatever(r1)) { return 0; } } finally delete r1; return 1; } The compiler would have to find all the different "return" statements and insert the appropriate "delete" statements in them. Same thing for "break" and "continue" statements, and at the end of the block where the resource was allocated. Still, I do think adding something like what you suggest to structs (not classes) would be beneficial to the language. At least, some mechanism for automated lifetime management of non-memory resources (synchronization objects, file/GUI handles, network connections, etc...). Salutaciones, JCAB
Jun 11 2002
next sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Juan Carlos Arevalo Baeza wrote:

    The problem is in the semantics and potential hidden bugs in the program.
 I'm not sure what D specifies will happen if you explicitly "delete" an
 object (you _could_ explicitly delete an object, couldn't you?) and then try
 to use it (for example, if "whatever()" leaves copies of the reference lying
 around). Still, I believe Walter's express desire is that such a dangerous
 "delete" shouldn't happen behind the programmer's back. Dangerous statements
 like that one are necessary to enhance the programmer's arsenal, but they
 are indeed problematic when they happen without the programmer's awareness
 of it.
Walter has said that you can use "delete" against something with references remaining...but it's undefined behavior. As I understand it, calling "delete" forces immediate cleanup of the object...including running its destructors. However, if that object has references to other objects, I do not think that the "delete" propogates to them...unless the destructor explicitly does so.
    There is a flaw in your approach, though. I think. I can't find proper
 documentation about the "finally" clause, but I believe it doesn't run if
 you just "return" from inside of the "try" block:

 int fn()
 {
    ResourceWrapper r1 = new ResourceWrapper("com1");
    try {
       if (whatever(r1)) {
          return 0;
       }
    } finally delete r1;

    return 1;
 }
I don't understand "finally" that way. I thought that "finally" statements run whenever you leave that block for any reason, including throwing an exception. I can't find good documentation to that effect, either, but that certainly seems to be the implication: go to the "statements" page and search for "finally".
    The compiler would have to find all the different "return" statements and
 insert the appropriate "delete" statements in them. Same thing for "break"
 and "continue" statements, and at the end of the block where the resource
 was allocated.
Right. After assigning the return value (if that applies), all exit points jump to a common exit routine. Not really all that odious...some asm code I've looked at did that anyway - there was only 1 return-from-function instruction, and a bunch of unconditional jumps to it from various points in the function.
 Still, I do think adding something like what you suggest to structs (not
 classes) would be beneficial to the language. At least, some mechanism for
 automated lifetime management of non-memory resources (synchronization
 objects, file/GUI handles, network connections, etc...).
-- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Jun 11 2002
next sibling parent "Juan Carlos Arevalo Baeza" <jcab roningames.com> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3D064768.A1C560DA deming-os.org...

 Walter has said that you can use "delete" against something with
references
 remaining...but it's undefined behavior.
That's what I thought. Then, he wants it to be explicitly requested by the programmer.
    There is a flaw in your approach, though. I think. I can't find
proper
 documentation about the "finally" clause, but I believe it doesn't run
if
 you just "return" from inside of the "try" block:
I don't understand "finally" that way. I thought that "finally"
statements run
 whenever you leave that block for any reason, including throwing an
exception.
 I can't find good documentation to that effect, either, but that certainly
seems
 to be the implication:  go to the "statements" page and search for
"finally". You're right. I checked only the "try-catch-finally" section, and saw no mention of what "finally" does there. Same thing in the "Handling errors" chapter. The documentation needs some fixing here. And it sounds to me that, if "finally" is only part of the exception handling mechanism, it shouldn't handle non-exception exits from the block. Maybe Walter would care to clarify about this or give the correct pointer. Anyway, it sounds like "finally" already does all the hard work, so implementing the resource management should be a breeze. Salutaciones, JCAB
Jun 11 2002
prev sibling parent reply "Sandor Hojtsy" <hojtsy index.hu> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3D064768.A1C560DA deming-os.org...
 Juan Carlos Arevalo Baeza wrote:

    The problem is in the semantics and potential hidden bugs in the
program.
 I'm not sure what D specifies will happen if you explicitly "delete" an
 object (you _could_ explicitly delete an object, couldn't you?) and then
try
 to use it (for example, if "whatever()" leaves copies of the reference
lying
 around). Still, I believe Walter's express desire is that such a
dangerous
 "delete" shouldn't happen behind the programmer's back. Dangerous
statements
 like that one are necessary to enhance the programmer's arsenal, but
they
 are indeed problematic when they happen without the programmer's
awareness
 of it.
Walter has said that you can use "delete" against something with
references
 remaining...but it's undefined behavior.  As I understand it, calling
"delete"
 forces immediate cleanup of the object...including running its
destructors. Please, please no Undefined Behaviour in language specs. If you delete an object all references to it should magically became null. Or invalid. Or get a GPF, or ... format the hard disk in a documented manner. Anything but the UB. Sandor
Jun 12 2002
next sibling parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Sandor Hojtsy" <hojtsy index.hu> wrote in message
news:ae7i8l$8cd$1 digitaldaemon.com...

 Please, please no Undefined Behaviour in language specs.
 If you delete an object all references to it should magically became null.
 Or invalid. Or get a GPF, or ... format the hard disk in a documented
 manner.
Now, how would it be implemented in a more or less effective way (other than holding a list of pointers for each object)?
Jun 12 2002
parent "Sandor Hojtsy" <hojtsy index.hu> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:ae8far$1bj9$1 digitaldaemon.com...
 "Sandor Hojtsy" <hojtsy index.hu> wrote in message
 news:ae7i8l$8cd$1 digitaldaemon.com...

 Please, please no Undefined Behaviour in language specs.
 If you delete an object all references to it should magically became
null.
 Or invalid. Or get a GPF, or ... format the hard disk in a documented
 manner.
Now, how would it be implemented in a more or less effective way (other than holding a list of pointers for each object)?
Well, you only use explicit delete in special cases. IMHO, it doesn't need to be fast. It could traverse the reference tree in much the same way as GC do, and check for references. Then it could find all other references, and do something EXPLICITELY SPECIFIED with them. At least in the debug build. Sandor
Jun 18 2002
prev sibling parent "Matthew Wilson" <dm synesis-group.com> writes:
Strongly AGREE! Please no undefined behaviour. That way leads to ...

"Sandor Hojtsy" <hojtsy index.hu> wrote in message
news:ae7i8l$8cd$1 digitaldaemon.com...
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:3D064768.A1C560DA deming-os.org...
 Juan Carlos Arevalo Baeza wrote:

    The problem is in the semantics and potential hidden bugs in the
program.
 I'm not sure what D specifies will happen if you explicitly "delete"
an
 object (you _could_ explicitly delete an object, couldn't you?) and
then
 try
 to use it (for example, if "whatever()" leaves copies of the reference
lying
 around). Still, I believe Walter's express desire is that such a
dangerous
 "delete" shouldn't happen behind the programmer's back. Dangerous
statements
 like that one are necessary to enhance the programmer's arsenal, but
they
 are indeed problematic when they happen without the programmer's
awareness
 of it.
Walter has said that you can use "delete" against something with
references
 remaining...but it's undefined behavior.  As I understand it, calling
"delete"
 forces immediate cleanup of the object...including running its
destructors. Please, please no Undefined Behaviour in language specs. If you delete an object all references to it should magically became null. Or invalid. Or get a GPF, or ... format the hard disk in a documented manner. Anything but the UB. Sandor
Jun 12 2002
prev sibling parent reply "Matthew Wilson" <dmd synesis.com.au> writes:
Why cannot we get rid of delete, in favour of assignment to the reference
causing the destructor to be fired at that point rather than at the exit of
the declaring scope, eg.

void fn()
{
    SomeObj    obj       =    new SomeObj();

}    // destructor called here

as opposed to

void fn()
{
    SomeObj    obj       =    new SomeObj();

    ...

    obj    = new SomeObj()    // destructor called here for first instance,
prior to construction of second

    ...

    obj = null;    // destructor called here for second instance

    ...

}



"Juan Carlos Arevalo Baeza" <jcab roningames.com> wrote in message
news:ae5fne$101$1 digitaldaemon.com...
 "Sandor Hojtsy" <hojtsy index.hu> wrote in message
 news:ae53cg$2lg7$1 digitaldaemon.com...

 int fn()
 {
   owned ResourceWrapper r1 = new ResourceWrapper("com1");
   new Someting s;
   new owned ResourceWrapper r2("com2", s);
   whatever(r1);
   whatever(r2);
 }

 meaning:

 int fn()
 {
    ResourceWrapper r1 = new ResourceWrapper("com1");
    try {
      Something s = new Something;
      ResourceWrapper r2 = new ResourceWrapper("com2", s);
      try {
        whatever(r1);
        whatever(r2);
      } finally delete r2;
    } finally delete r1;
 }

 And s, r1 and r2 are still references of course. I don't see any of the
 listed problems here.
The problem is in the semantics and potential hidden bugs in the
program.
 I'm not sure what D specifies will happen if you explicitly "delete" an
 object (you _could_ explicitly delete an object, couldn't you?) and then
try
 to use it (for example, if "whatever()" leaves copies of the reference
lying
 around). Still, I believe Walter's express desire is that such a dangerous
 "delete" shouldn't happen behind the programmer's back. Dangerous
statements
 like that one are necessary to enhance the programmer's arsenal, but they
 are indeed problematic when they happen without the programmer's awareness
 of it.

    For example, the same argument applies (arguably) to overloaded
 operators, which have been discussed here before.

    There is a flaw in your approach, though. I think. I can't find proper
 documentation about the "finally" clause, but I believe it doesn't run if
 you just "return" from inside of the "try" block:

 int fn()
 {
    ResourceWrapper r1 = new ResourceWrapper("com1");
    try {
       if (whatever(r1)) {
          return 0;
       }
    } finally delete r1;

    return 1;
 }

    The compiler would have to find all the different "return" statements
and
 insert the appropriate "delete" statements in them. Same thing for "break"
 and "continue" statements, and at the end of the block where the resource
 was allocated.

    Still, I do think adding something like what you suggest to structs
(not
 classes) would be beneficial to the language. At least, some mechanism for
 automated lifetime management of non-memory resources (synchronization
 objects, file/GUI handles, network connections, etc...).

 Salutaciones,
                          JCAB
Jun 11 2002
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Matthew Wilson wrote:

 Why cannot we get rid of delete, in favour of assignment to the reference
 causing the destructor to be fired at that point rather than at the exit of
 the declaring scope
In places where the compiler can determine at runtime that no external references exist, it could insert an automatic delete there. However, this has a few downsides: 1) If the reference is ever passed to another function, then the compiler has to track into that function to see if the reference is ever "saved off" anywhere. Can be done, but it gets complex, and may not catch all instances. 2) Different compilers may detect different conditions, meaning that in some compilers your object is cleaned up immediately, while others wait for the GC to find it. To fix that, you have to define a new standard for their seach algorithm... 3) As Walter noted on the D website, sometimes you don't want immediate destruction even if it's possible. Sometimes it makes more sense to just let the program run ahead and clean up the garbage later, when you hit an idle time or you actually run out of memory. Before then (in some cases) running the destructor just slows the program down. IMHO, if you want automatic destruction, you should do something to note that. Either have a keyword that tells the compiler to auto-destruct it, or use different declaration syntax for auto-destructed and garbage-collected objects. -- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Jun 11 2002
parent reply "Matthew Wilson" <dm synesis-group.com> writes:
A keyword is one solution, but can lead to error. The need for deterministic
destruction is a function of the type rather than its location (in the
majority of cases, anyway)

I think it would be better to have something denoting such in the class
definition. It could be some kind of attribute (stinks a bit) or it could be
the presence of a destructor. There may be some need for a late destruction,
in which case you could have a destructor (~MyClass()) and a finaliser
(Finalise()) but that sucks a bit as well. Perhaps you could have


class MyClass
{
    ...

    deterministic ~MyClass() // deterministic destruction
    {
    }

    ...
}

as opposed to either

class MyClass
{
    ...

    ~MyClass() // garbage-collect time finalisation
    {
    }

    ...
}

and

class MyClass
{
    ...

    // no dtor means nothing to be done at garbage collection

    ...
}

Does this sound ok?

"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3D0672F2.794C7225 deming-os.org...
 Matthew Wilson wrote:

 Why cannot we get rid of delete, in favour of assignment to the
reference
 causing the destructor to be fired at that point rather than at the exit
of
 the declaring scope
In places where the compiler can determine at runtime that no external references exist, it could insert an automatic delete there. However,
this has
 a few downsides:
     1) If the reference is ever passed to another function, then the
compiler
 has to track into that function to see if the reference is ever "saved
off"
 anywhere.  Can be done, but it gets complex, and may not catch all
instances.
     2) Different compilers may detect different conditions, meaning that
in some
 compilers your object is cleaned up immediately, while others wait for the
GC to
 find it.  To fix that, you have to define a new standard for their seach
 algorithm...
     3) As Walter noted on the D website, sometimes you don't want
immediate
 destruction even if it's possible.  Sometimes it makes more sense to just
let
 the program run ahead and clean up the garbage later, when you hit an idle
time
 or you actually run out of memory.  Before then (in some cases) running
the
 destructor just slows the program down.

 IMHO, if you want automatic destruction, you should do something to note
that.
 Either have a keyword that tells the compiler to auto-destruct it, or use
 different declaration syntax for auto-destructed and garbage-collected
objects.
 --
 The Villagers are Online! villagersonline.com

 .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
 .[ (a version.of(English).(precise.more)) is(possible) ]
 ?[ you want.to(help(develop(it))) ]
Jun 11 2002
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
I really like the idea of doing this at the class level rather than the usage
level!  However, there are some questions to address:
1) How to enforce that the user doesn't keep extra references to a deterministic
object type?  That is, if you pass a reference to a deterministic object to
another function, how do you enforce that it doesn't save the reference?  I'm
not really comfortable with "caveat emptor".  Somebody suggested that maybe you
shouldn't be able to pass these types of references to other functions...but
then how do you pass an open file handle to another function?
2) If you include a reference to this type of object in another class, does the
other class have to become deterministic, too, or not?

--
The Villagers are Online! villagersonline.com

.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]
Jun 12 2002
parent reply "Sean L. Palmer" <seanpalmer earthlink.net> writes:
Why not just be able to mark something as reference counted, then any
compiler created references will manipulate the reference count.

Built-in language-supported reference counting is something I could *really*
like.  Especially if we had to ask for it and by default got garbage
collection.

Sean

"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3D0759AF.7C8580F3 deming-os.org...
 I really like the idea of doing this at the class level rather than the
usage
 level!  However, there are some questions to address:
 1) How to enforce that the user doesn't keep extra references to a
deterministic
 object type?  That is, if you pass a reference to a deterministic object
to
 another function, how do you enforce that it doesn't save the reference?
I'm
 not really comfortable with "caveat emptor".  Somebody suggested that
maybe you
 shouldn't be able to pass these types of references to other
functions...but
 then how do you pass an open file handle to another function?
 2) If you include a reference to this type of object in another class,
does the
 other class have to become deterministic, too, or not?
Jun 12 2002
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Can you expand on what you mean by this?  Do you mean the reference counting as
a replacement to the garbage collector, or a supplement to it?  As a suplement,
it might be exactly what we need.

Russ

"Sean L. Palmer" wrote:

 Why not just be able to mark something as reference counted, then any
 compiler created references will manipulate the reference count.

 Built-in language-supported reference counting is something I could *really*
 like.  Especially if we had to ask for it and by default got garbage
 collection.

 Sean

 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:3D0759AF.7C8580F3 deming-os.org...
 I really like the idea of doing this at the class level rather than the
usage
 level!  However, there are some questions to address:
 1) How to enforce that the user doesn't keep extra references to a
deterministic
 object type?  That is, if you pass a reference to a deterministic object
to
 another function, how do you enforce that it doesn't save the reference?
I'm
 not really comfortable with "caveat emptor".  Somebody suggested that
maybe you
 shouldn't be able to pass these types of references to other
functions...but
 then how do you pass an open file handle to another function?
 2) If you include a reference to this type of object in another class,
does the
 other class have to become deterministic, too, or not?
-- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Jun 12 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3D078261.D25F03FA deming-os.org...

 Can you expand on what you mean by this?  Do you mean the reference
counting as
 a replacement to the garbage collector, or a supplement to it?  As a
suplement,
 it might be exactly what we need.
Indeed, it was meant to be a supplement. And I like the idea. Both GC and refcounting have their advantages and disadvantages, and having 'em both would be really great!
Jun 12 2002
parent reply "Sean L. Palmer" <seanpalmer earthlink.net> writes:
For those turned off by circular reference problems, I've been using
RefCounting almost exclusively for the past few years and I love it.  Sure I
wish it was builtin instead of a user defined class, but really it works
well in day-to-day work.  Cycles rarely happen to me and when it happens,
usually I can rearrange things a bit and remove the cycles.  For instance if
parent and child have ref pointers to each other, that's a cycle.  But I
just make the parent own a ref to the child and the child just have a raw
pointer to the parent (no ref) and presto no cycle.

The things I like about refcounts:

They're deterministic
They don't use voodoo magic

But really I'd probably be happy with GC so long as GC wasn't the *only* way
things got collected... I'd want the compiler to do data flow analysis and
explicitly clean up objects it can prove are no longer referenced when a
block exits.  Those kinds of objects can be allocated on the stack too to
avoid malloc overhead.  Everything else can get GC'd later or I can
explicitly call delete if I need it cleaned up right now.

Sean

"Pavel Minayev" <evilone omen.ru> wrote in message
news:ae8fd6$1blb$1 digitaldaemon.com...
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:3D078261.D25F03FA deming-os.org...

 Can you expand on what you mean by this?  Do you mean the reference
counting as
 a replacement to the garbage collector, or a supplement to it?  As a
suplement,
 it might be exactly what we need.
Indeed, it was meant to be a supplement. And I like the idea. Both GC and refcounting have their advantages and disadvantages, and having 'em both would be
really
 great!
Jun 13 2002
next sibling parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
"Sean L. Palmer" wrote:

 For those turned off by circular reference problems, I've been using
 RefCounting almost exclusively for the past few years and I love it.  Sure I
 wish it was builtin instead of a user defined class, but really it works
 well in day-to-day work.  Cycles rarely happen to me and when it happens,
 usually I can rearrange things a bit and remove the cycles.  For instance if
 parent and child have ref pointers to each other, that's a cycle.  But I
 just make the parent own a ref to the child and the child just have a raw
 pointer to the parent (no ref) and presto no cycle.
(Seriously,) I can't believe I didn't think of that before...don't refcount the last reference in the cycle...hence no cycle. Of course, it only lets you root the cycle in one place (otherwise you lose a few elements in the cycle), but still...a very elegant solution :) (cheering) I think that (optional) refcounts in D, IMHO, just moved from a good idea to a Good Idea. -- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Jun 13 2002
prev sibling next sibling parent reply "Matthew Wilson" <matthew thedjournal.com> writes:
Agreed. Also am a big and bug-free ref-counter.

I reckon the language, if references are built-in, can work out the circular
ref-stuff for us.

"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message
news:ae9l0o$2lur$1 digitaldaemon.com...
 For those turned off by circular reference problems, I've been using
 RefCounting almost exclusively for the past few years and I love it.  Sure
I
 wish it was builtin instead of a user defined class, but really it works
 well in day-to-day work.  Cycles rarely happen to me and when it happens,
 usually I can rearrange things a bit and remove the cycles.  For instance
if
 parent and child have ref pointers to each other, that's a cycle.  But I
 just make the parent own a ref to the child and the child just have a raw
 pointer to the parent (no ref) and presto no cycle.

 The things I like about refcounts:

 They're deterministic
 They don't use voodoo magic

 But really I'd probably be happy with GC so long as GC wasn't the *only*
way
 things got collected... I'd want the compiler to do data flow analysis and
 explicitly clean up objects it can prove are no longer referenced when a
 block exits.  Those kinds of objects can be allocated on the stack too to
 avoid malloc overhead.  Everything else can get GC'd later or I can
 explicitly call delete if I need it cleaned up right now.

 Sean

 "Pavel Minayev" <evilone omen.ru> wrote in message
 news:ae8fd6$1blb$1 digitaldaemon.com...
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:3D078261.D25F03FA deming-os.org...

 Can you expand on what you mean by this?  Do you mean the reference
counting as
 a replacement to the garbage collector, or a supplement to it?  As a
suplement,
 it might be exactly what we need.
Indeed, it was meant to be a supplement. And I like the idea. Both GC
and
 refcounting
 have their advantages and disadvantages, and having 'em both would be
really
 great!
Jun 13 2002
parent "Sean L. Palmer" <seanpalmer earthlink.net> writes:
Yes it probably could.  If they can build a garbage collector which is based
on reference counting they can do damn near anything.

Sean


"Matthew Wilson" <matthew thedjournal.com> wrote in message
news:aeb9nb$1cda$1 digitaldaemon.com...
 Agreed. Also am a big and bug-free ref-counter.

 I reckon the language, if references are built-in, can work out the
circular
 ref-stuff for us.
Jun 14 2002
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message
news:ae9l0o$2lur$1 digitaldaemon.com...
 I'd want the compiler to do data flow analysis and
 explicitly clean up objects it can prove are no longer referenced when a
 block exits.  Those kinds of objects can be allocated on the stack too to
 avoid malloc overhead.
This is actually quite a good idea. The trouble with it is it will depend on the quality of the data flow analysis, which is implementation dependent. For example, the normal thing to do with an object is call a method on it - the 'this' pointer may get copied and squirreled away somewhere by the method.
Jun 14 2002
parent "Juan Carlos Arevalo Baeza" <jcab roningames.com> writes:
"Walter" <walter digitalmars.com> wrote in message
news:aedvpb$120n$1 digitaldaemon.com...
 "Sean L. Palmer" <seanpalmer earthlink.net> wrote in message
 news:ae9l0o$2lur$1 digitaldaemon.com...
 I'd want the compiler to do data flow analysis
This is actually quite a good idea. The trouble with it is it will depend
on
 the quality of the data flow analysis, which is implementation dependent.
 For example, the normal thing to do with an object is call a method on
it -
 the 'this' pointer may get copied and squirreled away somewhere by the
 method.
The obvious solution might be adding semantic markers to the language, not unlike "const" and "volatile" in C++. For example, markers for pure functions (in the pure functional sense) and for unaliased parameters could help the compiler do the right thing better. Note that those markers would have to become part of the interface of the method. Like "const" and "volatile", and unlike function exception specifications in C++ or contracts in D. This would increase the burden on the programmer that uses them, and in the compiler, but it would increase the ability for the programmer to express known intent. Salutaciones, JCAB
Jun 17 2002
prev sibling parent "Matthew Wilson" <dmd synesis.com.au> writes:
Agreed.

I do not think it appropriate for us to require Walter's implementation to
be stack-based, just that we get deterministic destruction.

Could the references not be reference-counting stack instances who
handle/proxy the heap-based objects? I have implemented such systems in C++,
to great and efficient effect.

Maybe I'm being impossibly naive/optimistic ?

"Sandor Hojtsy" <hojtsy index.hu> wrote in message
news:ae53cg$2lg7$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:ae4dgl$1v5h$1 digitaldaemon.com...
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:3CF4F102.D7F03F0C deming-os.org...
 I just wondered, Walter, if you would explain your reasoning why all
 class objects are allocated on the heap?  Stack objects, not subject
to
 garbage collection and automatically cleaned up when the reference
goes
 out of scope, would give programmers some flexibility...and improve
 program performance by reducing the number of objects that must be
 considered by the garbage collector.
There are stack based objects in D, they are structs. Structs are lightweight objects, with no virtual functions and no destructors. Reasons for not putting class objects on the stack: 1) no need for complicated and buggy rules about when objects get destructed. 2) no scoping rules for temporaries. 3) no need for copy constructors and assignment overloading - a large simplification. In C++, you cannot escape dealing with them. In D, no
need
 to worry about them.
 4) no worries/bugs about value vs reference semantics.
 5) no need for a reference operator (the & in C++).
 6) no need to worry about the difference between new and new[].
I think the main point here is not that any objects should be actually on the stack, but some of them should behave as-if. - some of them be constructed as-if - some of them be destructed as-if For example in the two syntax suggars I already proposed elsewhere
("owned"
 and "new"),

 int fn()
 {
   owned ResourceWrapper r1 = new ResourceWrapper("com1");
   new Someting s;
   new owned ResourceWrapper r2("com2", s);
   whatever(r1);
   whatever(r2);
 }

 meaning:

 int fn()
 {
    ResourceWrapper r1 = new ResourceWrapper("com1");
    try {
      Something s = new Something;
      ResourceWrapper r2 = new ResourceWrapper("com2", s);
      try {
        whatever(r1);
        whatever(r2);
      } finally delete r2;
    } finally delete r1;
 }

 And s, r1 and r2 are still references of course. I don't see any of the
 listed problems here.

 Sandor
Jun 11 2002