June 11, 2002
"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[].


June 11, 2002
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[].
>
>


June 11, 2002
"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



June 11, 2002
"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



June 11, 2002
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))) ]


June 11, 2002
"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



June 11, 2002
"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.


June 11, 2002
For me it seems like the make or break.

C# has really surprisingly good performance so, whilst I think D will still win out there, the other "advantages" of C# (it being promulgated by M$, 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

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


June 11, 2002
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
>
>
>


June 11, 2002
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
>
>
>