D - RAII take 2
- Walter (23/23) Aug 27 2002 The 'auto' idea was looking more and more like a way to simply put class
- Patrick Down (11/12) Aug 27 2002 struct Foo
- Walter (3/15) Aug 27 2002 No. I should add that copy-initializers are not allowed, either.
- Patrick Down (26/45) Aug 27 2002 With the previous method I could.
- Walter (2/2) Aug 28 2002 You're right. I know supporting struct constructors is an attractive not...
- Sandor Hojtsy (6/30) Aug 28 2002 Every problem can be solved by adding a level of indirection.
- Sean L. Palmer (9/32) Aug 27 2002 That sounds like a fine plan.
- Walter (10/10) Aug 28 2002 Making them work is a substantial increase in the complexity of the
- Patrick Down (9/24) Aug 28 2002 I think I still like the auto idea better.
- Russ Lewis (7/7) Aug 28 2002 Yes, my gut feeling is that the struct solution causes more problems tha...
- Mac Reiter (77/77) Aug 28 2002 Let me start by saying that the struct solution would work for me. I ca...
- Walter (32/98) Aug 28 2002 types
- Russ Lewis (12/22) Aug 28 2002 I think that that is an argument FOR the other style. As I see it, ther...
- Walter (9/15) Aug 28 2002 are
- Russ Lewis (23/29) Aug 29 2002 I hear you, but (from my perspective), the key difference between a stru...
- Walter (14/39) Aug 29 2002 and
- Sean L. Palmer (24/54) Aug 30 2002 If I had a choice, I'd *much* rather have operator overloading for struc...
- Russ Lewis (11/23) Sep 04 2002 Amen.
- Sandor Hojtsy (69/85) Sep 02 2002 there
- Pavel Minayev (4/16) Sep 02 2002 I wholeheartedly agree. Using structs for raii is not very practical,
- Martin M. Pedersen (25/28) Aug 28 2002 Hi,
- Martin M. Pedersen (8/9) Aug 28 2002 Hi,
- Walter (10/16) Aug 28 2002 this()
- Walter (8/33) Aug 28 2002 I agree. Also, constructors for stack objects have wretched parsing
- Matthew Wilson (67/90) Sep 02 2002 Guys
- Pavel Minayev (16/38) Sep 02 2002 I think the latter is much better... just to remind my example with
- Sandor Hojtsy (33/86) Sep 04 2002 and
- Mac Reiter (31/49) Sep 04 2002 There is a risk if the non-raii reference will be holding on past the fu...
- Pavel Minayev (2/9) Sep 04 2002 Yes, exactly. I think it would be the best approach.
- Sandor Hojtsy (61/98) Sep 05 2002 counted, so
- Mac Reiter (80/90) Sep 05 2002 OK, there are two things that I need to point out that will help tremend...
- Russ Lewis (45/64) Sep 05 2002 Interesting idea. But maybe you could build it into the compile: There ...
- Walter (7/12) Sep 05 2002 could be
- Russell Lewis (6/31) Sep 05 2002 (Shudder) Well, I suppose any error is better than none. It's a good
- Sandor Hojtsy (9/21) Sep 09 2002 Good. In that case, releasing raii objects should call finalyze, and not
- Walter (9/13) Sep 05 2002 realized
- Juarez Rudsatz (5/7) Sep 05 2002 A example of code being converted for user RAII:
The 'auto' idea was looking more and more like a way to simply put class objects on the stack. Ok, so I smack my forehead, and think why not allow destructors for structs? This would provide the automatic destruction of structs when they go out of scope. Some other properties talked about with auto are implicit with structs: 1) they cannot be derived from or inherited 2) the 'auto' is implicit 3) can't implicitly convert to Object Furthermore, to make things easier, the following can be disallowed: 1) arrays of structs with destructors 2) structs with destructors as class or struct fields 3) assignment of structs with destructors A class can be 'auto-ized' by wrapping it in a struct: struct AutoA { A a; ~this() { delete a; } } and can even be templatized: template AutoClass(T) { T t; ~this() { delete t; } }
Aug 27 2002
"Walter" <walter digitalmars.com> wrote in news:akgsaf$aog$1 digitaldaemon.com:3) assignment of structs with destructorsstruct Foo { ~this() { } } void Bar(Foo a) { } Foo a; Bar(a); // Is this allowed?
Aug 27 2002
"Patrick Down" <pat codemoon.com> wrote in message news:Xns9277B119511Bpatcodemooncom 63.105.9.61..."Walter" <walter digitalmars.com> wrote in news:akgsaf$aog$1 digitaldaemon.com:No. I should add that copy-initializers are not allowed, either.3) assignment of structs with destructorsstruct Foo { ~this() { } } void Bar(Foo a) { } Foo a; Bar(a); // Is this allowed?
Aug 27 2002
"Walter" <walter digitalmars.com> wrote in news:akh8id$p90$1 digitaldaemon.com:"Patrick Down" <pat codemoon.com> wrote in message news:Xns9277B119511Bpatcodemooncom 63.105.9.61...With the previous method I could. auto fload = new File(name); LoadObjects(fload); Now it looks like I need to do this... instance AutoClass(File) AutoFile; AutoFile fload; fload.t = new File(name); LoadObjects(fload.t); If you put constructors on structs too then it could work like this. struct AutoFile { File f; this(char[] name) { f = new File(name); } ~this() { if(f) f.close(); } } Autofile fload(name); LoadObjects(fload.f);"Walter" <walter digitalmars.com> wrote in news:akgsaf$aog$1 digitaldaemon.com:No. I should add that copy-initializers are not allowed, either.3) assignment of structs with destructorsstruct Foo { ~this() { } } void Bar(Foo a) { } Foo a; Bar(a); // Is this allowed?
Aug 27 2002
You're right. I know supporting struct constructors is an attractive notion, but I'd like to try avoiding them for the moment.
Aug 28 2002
"Patrick Down" <pat codemoon.com> wrote in message news:Xns927810D18195Dpatcodemooncom 63.105.9.61..."Walter" <walter digitalmars.com> wrote in news:akh8id$p90$1 digitaldaemon.com:Every problem can be solved by adding a level of indirection. auto fload = new File(name); LoadObjects(&fload); If File is a struct you should not pass it by value, but by address."Patrick Down" <pat codemoon.com> wrote in message news:Xns9277B119511Bpatcodemooncom 63.105.9.61...With the previous method I could. auto fload = new File(name); LoadObjects(fload);"Walter" <walter digitalmars.com> wrote in news:akgsaf$aog$1 digitaldaemon.com:No. I should add that copy-initializers are not allowed, either.3) assignment of structs with destructorsstruct Foo { ~this() { } } void Bar(Foo a) { } Foo a; Bar(a); // Is this allowed?
Aug 28 2002
That sounds like a fine plan. I don't see how any of your second 3 points (to make things easier) would seem daunting to someone like you who has implemented a C++ compiler or three. ;) They seem like simple enough concepts. What do you find so difficult about it? Seems templates and exceptions are far more of a challenge. Sean "Walter" <walter digitalmars.com> wrote in message news:akgsaf$aog$1 digitaldaemon.com...The 'auto' idea was looking more and more like a way to simply put class objects on the stack. Ok, so I smack my forehead, and think why not allow destructors for structs? This would provide the automatic destruction of structs when they go out of scope. Some other properties talked about with auto are implicit with structs: 1) they cannot be derived from or inherited 2) the 'auto' is implicit 3) can't implicitly convert to Object Furthermore, to make things easier, the following can be disallowed: 1) arrays of structs with destructors 2) structs with destructors as class or struct fields 3) assignment of structs with destructors A class can be 'auto-ized' by wrapping it in a struct: struct AutoA { A a; ~this() { delete a; } } and can even be templatized: template AutoClass(T) { T t; ~this() { delete t; } }
Aug 27 2002
Making them work is a substantial increase in the complexity of the compiler, bugs in the compiler (!), attempting to explain to programmers all the noise going on behind the scenes for something simple-appearing like passing a struct value to a function, etc. It brings to the fore confusing notions like the difference between assignment and initialization, overloading assignment operators and copy constructors start becoming necessary, etc. In short, many things I was trying to leave behind <g>. If the territory can be covered without needing that stuff, I sure want to give it a try.
Aug 28 2002
"Walter" <walter digitalmars.com> wrote in news:akgsaf$aog$1 digitaldaemon.com:The 'auto' idea was looking more and more like a way to simply put class objects on the stack. Ok, so I smack my forehead, and think why not allow destructors for structs? This would provide the automatic destruction of structs when they go out of scope. Some other properties talked about with auto are implicit with structs: 1) they cannot be derived from or inherited 2) the 'auto' is implicit 3) can't implicitly convert to Object Furthermore, to make things easier, the following can be disallowed: 1) arrays of structs with destructors 2) structs with destructors as class or struct fields 3) assignment of structs with destructorsI think I still like the auto idea better. With the struct solution it seems like you would end back at the old problem of having duplicate class and struct variants of the same objects. As you suggest we can wrap a class reference in a struct. However this just seems like a more complicated version of the auto keyword.
Aug 28 2002
Yes, my gut feeling is that the struct solution causes more problems than it solves. -- 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))) ]
Aug 28 2002
Let me start by saying that the struct solution would work for me. I can't resist the urge to ramble on, however. Just for comment: 1. Since structs don't participate in inheritance, D already has variable types that cannot participate in Stream solutions or solutions that leverage the Object interface. Which suggests that arguments against non-convertible auto/scoped/counted classes can also be made against the structs that have been there since day one... 2. Presence of a destructor will tend to make people wonder why there isn't a constructor. I know that the answer has to do with reducing complexity, but the question will continue to come up. 3. This kinda pushes an implementation detail up into user cognitive space. Prior to this suggestion, the major benefits of structs were alignment control and lightweight allocation (stack). Now the second benefit (stack) turns into two benefits - lightweight allocation and scoping/d.o.f. This feels slightly wrong, somehow. 4. I know that the impetus for using struct this way would be to minimize the marginal added complexity of d.o.f. behavior. However, looking at the end result, I kinda feel the same way I do when I look at the 'static' keyword in C++ and have to stop and wonder if it is referring to a static thing or to a file-scope-restricted thing. Or when I look at the 'const' keyword and have to stop and figure out if it is referring to the thing being constant, or claiming that it is legal for the thing to be called on a constant instance (For C++ programmers that may not have seen the usage I am talking about: 'const' after a member function declaration means that it is legal for a user to call that member function if they have a constant instance of that class. Functions without this decoration cannot be called on a constant instance because the function might change the state of the class, which would violate the const-ness of the instance. Of course, const functions can also change the state of the instance, but they're not *supposed* to...) (Sorry for the tangential rambling) Having said all of that, I have been thinking about how to use RAII.v2. Since all classes derive (directly or indirectly) from Object, you could make: struct Scoped { Object obj; ~this() {delete obj;} } and put that somewhere in Phobos. Then, to scope something, I can just: void MyFunc() { Scoped s; s.obj = new MyClass; // proceed willy-nilly } // s.obj gets deleted here. Since the scoping struct doesn't need any interface of the scoped object other than Object, this polymorphism works, and can be done once and for all inside the standard library. I would like some form of initializer. It would be great if we could use the "static initializer" syntax from struct.html for non-static structs: void MyFunc() { Scoped s = {obj:new MyClass}; // proceed willy-nilly } // s.obj gets deleted here. Actually, there are nicer (or at least easier to type/read) syntaxes for this, but this would be consistent with existing language. How bad would it be to allow initializer-only constructors for structs? In C++, a constructor can use an initializer list to store incoming parameters in data members during creation. Since that would be the only use for a struct constructor anyway, initializer-only constructors should be sufficient for anything anyone needs in a struct (more complicated stuff gets done in a class, like it should). This would make the syntax something more like: struct Scoped { Object obj; this(Object o) : obj(o); // or pick a better syntax, this is "like" C++ ~this() {delete obj;} } void MyFunc() { Scoped s(new MyClass); // proceed willy-nilly } // s.obj gets deleted here. I don't know if limiting the nature of the constructor helps any or not. An initializer-based constructor may cause just as many problems as a full-fledged constructor. Mac
Aug 28 2002
"Mac Reiter" <Mac_member pathlink.com> wrote in message news:akj7dl$nc$1 digitaldaemon.com...1. Since structs don't participate in inheritance, D already has variabletypesthat cannot participate in Stream solutions or solutions that leverage the Object interface. Which suggests that arguments against non-convertible auto/scoped/counted classes can also be made against the structs that havebeenthere since day one...Yes, but with this scheme there are only 2 kinds of objects instead of 3.2. Presence of a destructor will tend to make people wonder why thereisn't aconstructor. I know that the answer has to do with reducing complexity,but thequestion will continue to come up.You're right. We'll have to see how this goes.3. This kinda pushes an implementation detail up into user cognitivespace.Prior to this suggestion, the major benefits of structs were alignmentcontroland lightweight allocation (stack). Now the second benefit (stack) turnsintotwo benefits - lightweight allocation and scoping/d.o.f. This feelsslightlywrong, somehow.It seems natural to me <g>.4. I know that the impetus for using struct this way would be to minimizethemarginal added complexity of d.o.f. behavior. However, looking at the end result, I kinda feel the same way I do when I look at the 'static' keywordinC++ and have to stop and wonder if it is referring to a static thing or toafile-scope-restricted thing. Or when I look at the 'const' keyword andhave tostop and figure out if it is referring to the thing being constant, orclaimingthat it is legal for the thing to be called on a constant instanceStructs were already scoped, they just didn't have destructors.Having said all of that, I have been thinking about how to use RAII.v2.Sinceall classes derive (directly or indirectly) from Object, you could make: struct Scoped { Object obj; ~this() {delete obj;} } and put that somewhere in Phobos. Then, to scope something, I can just: void MyFunc() { Scoped s; s.obj = new MyClass; // proceed willy-nilly } // s.obj gets deleted here. Since the scoping struct doesn't need any interface of the scoped objectotherthan Object, this polymorphism works, and can be done once and for allinsidethe standard library.Yes, although Scoped can be made a template.I would like some form of initializer. It would be great if we could usethe"static initializer" syntax from struct.html for non-static structs: void MyFunc() { Scoped s = {obj:new MyClass}; // proceed willy-nilly } // s.obj gets deleted here. Actually, there are nicer (or at least easier to type/read) syntaxes forthis,but this would be consistent with existing language.Yes.How bad would it be to allow initializer-only constructors for structs?In C++,a constructor can use an initializer list to store incoming parameters indatamembers during creation. Since that would be the only use for a struct constructor anyway, initializer-only constructors should be sufficient for anything anyone needs in a struct (more complicated stuff gets done in aclass,like it should). This would make the syntax something more like: struct Scoped { Object obj; this(Object o) : obj(o); // or pick a better syntax, this is "like" C++ ~this() {delete obj;} } void MyFunc() { Scoped s(new MyClass); // proceed willy-nilly } // s.obj gets deleted here. I don't know if limiting the nature of the constructor helps any or not.Aninitializer-based constructor may cause just as many problems as afull-fledgedconstructor.Initializer lists are a bug in C++ <g>.
Aug 28 2002
Walter wrote:"Mac Reiter" <Mac_member pathlink.com> wrote in message news:akj7dl$nc$1 digitaldaemon.com...I think that that is an argument FOR the other style. As I see it, there are (at least) three types of usage: * struct (pure data map) * garbage collected class (arbitrary lifespan) * raii class (d.o.f.) Those 3 should be well distinguished. -- 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))) ]1. Since structs don't participate in inheritance, D already has variabletypesthat cannot participate in Stream solutions or solutions that leverage the Object interface. Which suggests that arguments against non-convertible auto/scoped/counted classes can also be made against the structs that havebeenthere since day one...Yes, but with this scheme there are only 2 kinds of objects instead of 3.
Aug 28 2002
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3D6D4905.4BAF1C5C deming-os.org...I think that that is an argument FOR the other style. As I see it, thereare(at least) three types of usage: * struct (pure data map) * garbage collected class (arbitrary lifespan) * raii class (d.o.f.) Those 3 should be well distinguished.They are: 1) struct 2) class 3) struct with destructor The distinction between 1 and 3 should be comfortable for anyone used to destructors in C++.
Aug 28 2002
Walter wrote:They are: 1) struct 2) class 3) struct with destructor The distinction between 1 and 3 should be comfortable for anyone used to destructors in C++.I hear you, but (from my perspective), the key difference between a struct and a class is not the stack/heap question, but the active/inactive and binary layout issues. As I think of them, a struct is a primarily a binary layout mechanism - its purpose is to give a portable, definable, C-interoperable design for the data. That it can be laid out on the stack is very much secondary in that view. Since it is primarily a binary layout mechanism, it is an "inactive" mechanism - it doesn't contain any virtualization or implicit code (constructors and destructors are implicit code, since they run without us explicitly calling them). Member functions of structs, IMHO, are just (good) syntax sugar - they simply serve to encapsulate common operations on the structure. A class, on the other hand, is fundamentally an active mechanism. It has implicit code (constructors, destructors, operator overloading, etc.) and does a lot of virtualization. It explicitly does NOT allow you to define binary layout. In this view, an active property of the object (raii) fits far better with a class than a struct. -- 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))) ]
Aug 29 2002
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3D6E5614.E9ACCEE9 deming-os.org...Walter wrote:andThey are: 1) struct 2) class 3) struct with destructor The distinction between 1 and 3 should be comfortable for anyone used to destructors in C++.I hear you, but (from my perspective), the key difference between a structa class is not the stack/heap question, but the active/inactive and binary layout issues. As I think of them, a struct is a primarily a binary layout mechanism -itspurpose is to give a portable, definable, C-interoperable design for thedata.That it can be laid out on the stack is very much secondary in that view. Since it is primarily a binary layout mechanism, it is an "inactive"mechanism- it doesn't contain any virtualization or implicit code (constructors and destructors are implicit code, since they run without us explicitlycallingthem). Member functions of structs, IMHO, are just (good) syntax sugar -theysimply serve to encapsulate common operations on the structure. A class, on the other hand, is fundamentally an active mechanism. It has implicit code (constructors, destructors, operator overloading, etc.) anddoesa lot of virtualization. It explicitly does NOT allow you to definebinarylayout. In this view, an active property of the object (raii) fits far better withaclass than a struct.A struct also provides a mechanism for lightweight objects intended to be on the stack. (The absense of these is a large burden in Java.) Providing a destructor for raii is a natural extension of that.
Aug 29 2002
If I had a choice, I'd *much* rather have operator overloading for structs than for classes. I guess for both wouldn't hurt. And I'd prefer if the stack allocation policy be explicit in the spec. Although I suppose arrays of structs and very large structs can come from the heap if necessary. I don't know what everybody's problem with implicit code is. Every function ever compiled comes with hidden entry and exit code. A lot of stuff goes on behind the scenes that most people never know about, even in C. The chance to contribute to that general madness can make alot of programming tasks a lot easier. If I can't get the compiler to write my program for me, at least I should be able to get it to do a good portion of the redundant grunt work. ;) Sean "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3D6E5614.E9ACCEE9 deming-os.org...Walter wrote:andThey are: 1) struct 2) class 3) struct with destructor The distinction between 1 and 3 should be comfortable for anyone used to destructors in C++.I hear you, but (from my perspective), the key difference between a structa class is not the stack/heap question, but the active/inactive and binary layout issues. As I think of them, a struct is a primarily a binary layout mechanism -itspurpose is to give a portable, definable, C-interoperable design for thedata.That it can be laid out on the stack is very much secondary in that view. Since it is primarily a binary layout mechanism, it is an "inactive"mechanism- it doesn't contain any virtualization or implicit code (constructors and destructors are implicit code, since they run without us explicitlycallingthem). Member functions of structs, IMHO, are just (good) syntax sugar -theysimply serve to encapsulate common operations on the structure. A class, on the other hand, is fundamentally an active mechanism. It has implicit code (constructors, destructors, operator overloading, etc.) anddoesa lot of virtualization. It explicitly does NOT allow you to definebinarylayout. In this view, an active property of the object (raii) fits far better withaclass than a struct. -- 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))) ]
Aug 30 2002
"Sean L. Palmer" wrote:If I had a choice, I'd *much* rather have operator overloading for structs than for classes. I guess for both wouldn't hurt. And I'd prefer if the stack allocation policy be explicit in the spec. Although I suppose arrays of structs and very large structs can come from the heap if necessary. I don't know what everybody's problem with implicit code is. Every function ever compiled comes with hidden entry and exit code. A lot of stuff goes on behind the scenes that most people never know about, even in C. The chance to contribute to that general madness can make alot of programming tasks a lot easier. If I can't get the compiler to write my program for me, at least I should be able to get it to do a good portion of the redundant grunt work. ;)Amen. I'm not against having the compiler insert implicit code - in fact, I'm generally very much in favor of it. But if we make structs too much like classes, then why do we have two types at all? Either unify them in one program element, or give them noticable (useful) differences. -- 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))) ]
Sep 04 2002
"Walter" <walter digitalmars.com> wrote in message news:akjm07$urk$1 digitaldaemon.com..."Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3D6D4905.4BAF1C5C deming-os.org...thereI think that that is an argument FOR the other style. As I see it,areI have used C++ destructors for a few years now. I usually think of (1) as a struct with an empty destructor. So the list becomes: 1) struct with empty destructor 2) class 3) struct with non-empty destructor Now that distinction between raii and non-raii is not clear enough for me. The problem is that you want to pass raii objects into other functions before releasing them. With structs that is quite uncomfortable. I think we should pick the example of a File, find a solution, and that solution will be OK for every other raii object. Struct destructors, (and constructors) are usefull on their own right, and they should be implemented, but using them for raii, means or requires workarounds. Please do not force workarounds in or with the language. As I have already written raii is the property of the class not of the instance. BUT: It doesn't mean I want every reference to a raii object to release the instance! Only the OWNER reference: void foo() { owner File f = new File(); f.doSomething(); bar(f); } void bar(File f2) { ... } So the when the "f" reference is "lost", the instance is deleted. But not with the "f2" reference. Yes I realize that this is exactly the same that was suggested by Walter the first time, but with another keyword (raii). I also would like to point out that this is almost the same as constructing a wrapper struct with a destructor at "f", and passing the wrapped reference to "bar". See the same with desturcted struct : void foo { instance RaiiWrapper(File).RaiiWrapper fw; fw.f = new File(); fw.f.doSomething(); bar(fw.f); } Which one do you like better? What you see is unneccessary indirection in the source code and the binary too. Not talking about the wrapper contruct which is hard to read out. So please return to the original idea. Use a keyword to signal that a certain reference is owner of the instance. If operator overloading would be <Sigh> nice enough (dot operator, cast overloading, struct constructors), you could make a transparent wrapper struct here. That way source code complexity would match the first example. But binary code will be still a bit slower. Please don't say: that way referenced instances can be deleted. Yes, but with structs there are the same problem if you store the address of a struct. Or the wrapped reference. Either way this has to be left to the programmers good will. Future plans: 1) References stored inside class members can be owners too. This should mean, that after the finalyzer of a class runs, owned instances should be deleted. Seems easy to me. 2) Ownership can be made transferable. (implementation problems) 3) Asignment to an owner reference should delete the old instance. (implementation problems) For the 3) problem I propose a solution. If owner references are a separate "type" from normal references, the compiler could generate special code when assigment to an owner reference happens. For 2) you need a special field in each reference, and complex code for each assignment to any reference. I don't see an elegant solution for this. Yours, Sandor(at least) three types of usage: * struct (pure data map) * garbage collected class (arbitrary lifespan) * raii class (d.o.f.) Those 3 should be well distinguished.They are: 1) struct 2) class 3) struct with destructor The distinction between 1 and 3 should be comfortable for anyone used to destructors in C++.
Sep 02 2002
"Sandor Hojtsy" <hojtsy index.hu> wrote in news:akva29$2uju$1 digitaldaemon.com:Now that distinction between raii and non-raii is not clear enough for me. The problem is that you want to pass raii objects into other functions before releasing them. With structs that is quite uncomfortable. I think we should pick the example of a File, find a solution, and that solution will be OK for every other raii object. Struct destructors, (and constructors) are usefull on their own right, and they should be implemented, but using them for raii, means or requires workarounds. Please do not force workarounds in or with the language. As I have already written raii is the property of the classI wholeheartedly agree. Using structs for raii is not very practical, since we actually want _classes_ to be such.
Sep 02 2002
Hi, "Walter" <walter digitalmars.com> wrote in message news:akjh94$k4g$1 digitaldaemon.com...Constructors are nice, but not really that important. They do not offer functionality, that could not be realized using regular methods. Destructors, on the other hand, are a gift to man-kind. Deterministic destructors makes them even more so. Concentrating on destructors first seems very right to me. I have a thought about constructors, though: A new object is often created like this: SomeClass a = new SomeClass(args); You wrote yourself sometime ago, that it was clumsy. I agree. How about: SomeClass a(args); meaning that if an argument list was present, it was to be instantiated, and the constructor called. The argument list could be omitted like today like this: SomeClass a; // initialized to null The destinction between null initialization and initialization using a constructor without arguments would be: SomeClass a; // null SomeClass a(); // allocates new object and initializes it using this() The existing syntax would still have to be supported in cases like this: SomeClass a = new DerivedClass(args); Regards, Martin M. Pedersen2. Presence of a destructor will tend to make people wonder why there isn't a constructor.You're right. We'll have to see how this goes.
Aug 28 2002
Hi, "Martin M. Pedersen" <mmp www.moeller-pedersen.dk> wrote in message news:akjir7$ns6$1 digitaldaemon.com...SomeClass a(); // allocates new object and initializes it using this()I might add, that this might conflict with prototypes as we know them from C. However, prototypes belongs at global scope, object instantiation do not. So, there does not need to be a conflict. Regards, Martin M. Pedersen
Aug 28 2002
"Martin M. Pedersen" <mmp www.moeller-pedersen.dk> wrote in message news:akjj57$odk$1 digitaldaemon.com..."Martin M. Pedersen" <mmp www.moeller-pedersen.dk> wrote in message news:akjir7$ns6$1 digitaldaemon.com...this()SomeClass a(); // allocates new object and initializes it usingI might add, that this might conflict with prototypes as we know them from C. However, prototypes belongs at global scope, object instantiation donot.So, there does not need to be a conflict.You're right, but it would be better if the syntax for constructors was unique without relying on scope context. In C++, as things got added to the language, fairly simple ambiguity problems just got worse and worse. It's so bad now that even if the compiler parses it correctly, it is unable to generate a reasonable error message for any goofs. Syntactical redundancy is the key to being able to generate good error diagnostics.
Aug 28 2002
"Martin M. Pedersen" <mmp www.moeller-pedersen.dk> wrote in message news:akjir7$ns6$1 digitaldaemon.com..."Walter" <walter digitalmars.com> wrote in message news:akjh94$k4g$1 digitaldaemon.com...I agree. Also, constructors for stack objects have wretched parsing ambiguity problems. (Is it a declaration? Is it a function call? Is it a bird? Is it a plane? <g>)Constructors are nice, but not really that important. They do not offer functionality, that could not be realized using regular methods.2. Presence of a destructor will tend to make people wonder why there isn't a constructor.You're right. We'll have to see how this goes.Destructors, on the other hand, are a gift to man-kind. Deterministic destructors makes them even more so. Concentrating on destructors first seems very right to me.Yes.I have a thought about constructors, though: A new object is often created like this: SomeClass a = new SomeClass(args); You wrote yourself sometime ago, that it was clumsy. I agree. How about: SomeClass a(args); meaning that if an argument list was present, it was to be instantiated,andthe constructor called. The argument list could be omitted like today like this: SomeClass a; // initialized to null The destinction between null initialization and initialization using a constructor without arguments would be: SomeClass a; // null SomeClass a(); // allocates new object and initializes it using this() The existing syntax would still have to be supported in cases like this: SomeClass a = new DerivedClass(args);That's the "is it a function declaration or a declaration with constructor".
Aug 28 2002
Guys It seems to be the case that this debate is trying to reconcile keeping the simpler semantics and implementation of Java, whilst bringing back the essential constructs of C++ which (IMO) make it a more powerful, robust and object-oriented (supporting) language than its weakened offspring. I have a couple of thoughts: 1. struct The struct keyword remains what most people assume it to imply, an "inactive" type definition that doesn't contain constructor/destructor. The programmer can specify the layout of the structure. Arrays of structs are valid. Structs can be on the heap or on the frame (see below). Structs can have static methods. If it is feasible (from a compiler Walter's perspective), they may contain instance methods. Structs can have contain other structs (as members), but cannot contain references to classes (since they don't have destructors). 2. class The class keyword remains what most people assume it to imply, an "active" type definition, that contains constructors and destructors (although they can be omitted, in which case the compiler can provide them, or simply omit them, as it chooses). The default nature of a class is that of the current D class, ie. it is on the heap, and is garbage collected. class Normal { }; Normal n = new Normal(... some params ...); The raii (or auto) keyword can be applied to a class instance declaration, in which case the instance is placed on the frame, and is doffed when it goes out of scope. The syntax for such declarations do not use the new keyword, further disambiguating the syntax. class ToDofOrNotToDof { }; auto ToDofOrNotToDof dof(... args ...); // Dof'ed at the end of this scope. ToDofOrNotToDof nodof = new ToDofOrNotToDof(... args ...); // Destructor called when garbage collected. The raii (or auto) keyword can also be applied to a class definition, in which case all instances of the class _must_ be placed on the frame, and are doffed when they go out of scope. All instances use the raii declaration syntax. auto class AlwaysDof { }; AlwaysDof adof1(... args ...); // Dof'ed at the end of this scope auto AlwaysDof adof2(... args ...); // Identical to previous line - auto is redundant on an auto class AlwaysDof adof3 = new AlwaysDof(... args ...); // ERROR! The question of whether a doffing instance can be passed to a function taking a non-doffing instance can be resolved by either (i) disallowing it for any doffed instance, or (ii) allowing this at the programmer's own risk. I prefer the latter, but can live with the former quite happily. 3. Function declarations are at global scope, whereas object default-construction is not. Nevetheless, if Walter wants to distinguish between the two, the former could bear the "function" keyword, or the latter can be required to omit (as in C++) the empty braces: AlwaysDof adof(); // invalid AlwaysDOf adof; // valid I'm not sure this isn't only a summary of all the points made on this topic, but thought I'd mention it. One important implication for all this, that I don't know if anyone's yet addressed, is the impact of generics/templates. Perhaps this needs to be discussed before a final DOF decision is made. Matthew "Walter" <walter digitalmars.com> wrote in message news:akgsaf$aog$1 digitaldaemon.com...The 'auto' idea was looking more and more like a way to simply put class objects on the stack. Ok, so I smack my forehead, and think why not allow destructors for structs? This would provide the automatic destruction of structs when they go out of scope. Some other properties talked about with auto are implicit with structs: 1) they cannot be derived from or inherited 2) the 'auto' is implicit 3) can't implicitly convert to Object Furthermore, to make things easier, the following can be disallowed: 1) arrays of structs with destructors 2) structs with destructors as class or struct fields 3) assignment of structs with destructors A class can be 'auto-ized' by wrapping it in a struct: struct AutoA { A a; ~this() { delete a; } } and can even be templatized: template AutoClass(T) { T t; ~this() { delete t; } }
Sep 02 2002
Matthew Wilson wrote:The raii (or auto) keyword can also be applied to a class definition, in which case all instances of the class _must_ be placed on the frame, and are doffed when they go out of scope. All instances use the raii declaration syntax. auto class AlwaysDof { }; AlwaysDof adof1(... args ...); // Dof'ed at the end of this scope auto AlwaysDof adof2(... args ...); // Identical to previous line - autoI think that "auto" should also be _required_.The question of whether a doffing instance can be passed to a function taking a non-doffing instance can be resolved by either (i) disallowing it for any doffed instance, or (ii) allowing this at the programmer's own risk. I prefer the latter, but can live with the former quite happily.I think the latter is much better... just to remind my example with Stream/File: class Stream; // not all Streams are auto, auto class File; // but File definitely is uint crc32(Stream str); // Stream is not auto! auto File f("foo.bar"); crc32(f); Now if you forbid passing auto objects to functions expecting non-auto reference, the last line is invalid. But I don't see any reasons why it shouldn't be allowed...3. Function declarations are at global scope, whereas object default-construction is not. Nevetheless, if Walter wants to distinguish between the two, the former could bear the "function" keyword, or the latter can be required to omit (as in C++) the empty braces: AlwaysDof adof(); // invalid AlwaysDOf adof; // validAs long as you require to use "auto", there is no ambiguity. Overall, I must say that I really like this proposal, and would vote for it should the voting take place. It seems like the best approach to me, enabling power of C++ while preserving D's simplicity
Sep 02 2002
"Matthew Wilson" <matthew thedjournal.com> wrote in messageGuys It seems to be the case that this debate is trying to reconcile keepingthesimpler semantics and implementation of Java, whilst bringing back the essential constructs of C++ which (IMO) make it a more powerful, robustandobject-oriented (supporting) language than its weakened offspring. I haveacouple of thoughts: 1. struct The struct keyword remains what most people assume it to imply, an "inactive" type definition that doesn't contain constructor/destructor. The programmer can specify the layout of the structure. Arrays of structs are valid. Structs can be on the heap or on the frame (see below). Structs can have static methods. If it is feasible (from a compilerWalter'sperspective), they may contain instance methods. Structs can have contain other structs (as members), but cannot contain references to classes (since they don't have destructors).I don't think destructors and contained references are connected.2. class The class keyword remains what most people assume it to imply, an "active" type definition, that contains constructors and destructors (although they can be omitted, in which case the compiler can provide them, or simplyomitthem, as it chooses). The default nature of a class is that of the current D class, ie. it is on the heap, and is garbage collected. class Normal { }; Normal n = new Normal(... some params ...); The raii (or auto) keyword can be applied to a class instance declaration, in which case the instance is placed on the frame, and is doffed when it goes out of scope. The syntax for such declarations do not use the new keyword, further disambiguating the syntax. class ToDofOrNotToDof { }; auto ToDofOrNotToDof dof(... args ...); // Dof'ed at the end of this scope. ToDofOrNotToDof nodof = new ToDofOrNotToDof(... args ...); // Destructor called when garbage collected.I like this syntax. Could you please remind me, what this DOF word stands for?The raii (or auto) keyword can also be applied to a class definition, in which case all instances of the class _must_ be placed on the frame, andaredoffed when they go out of scope. All instances use the raii declaration syntax.I don't think the language specification should say whether raii is on the stack, or the heap. The only important point is that it's lifetime is the scope.auto class AlwaysDof { }; AlwaysDof adof1(... args ...); // Dof'ed at the end of thisscopeauto AlwaysDof adof2(... args ...); // Identical to previous line -autois redundant on an auto class AlwaysDof adof3 = new AlwaysDof(... args ...); // ERROR! The question of whether a doffing instance can be passed to a function taking a non-doffing instance can be resolved by either (i) disallowing it for any doffed instance, or (ii) allowing this at the programmer's ownrisk.I prefer the latter, but can live with the former quite happily.Incorrect. The raii is not the property of the object instance! It is the property of the reference instance. This is very important. You cannot ever pass a class instance. Only copy the reference. Now, would you like the copied reference to destroy your original object before the caller function ends? In 99 cases out of 100, no. So the real problem is copying an raii reference to an other raii reference. There is simply no risk with copying a raii reference into a non-raii reference. Why would someone disallow it? Because I want functions which take a reference to a File object, and don't close the File, you cannot have File as a raii class. Only specific references to File-s can be raii. Can you please provide a class which requires all references to it, to be raii? Because that is what you are suggesting. So I agree with you in most points, but think there is no need for this "auto class", but only for the individual "auto"s. Yours, Sandor
Sep 04 2002
In article <al4j79$2s6p$1 digitaldaemon.com>, Sandor Hojtsy says..."Matthew Wilson" <matthew thedjournal.com> wrote in message Incorrect. The raii is not the property of the object instance! It is the property of the reference instance. This is very important. You cannot ever pass a class instance. Only copy the reference. Now, would you like the copied reference to destroy your original object before the caller function ends? In 99 cases out of 100, no. So the real problem is copying an raii reference to an other raii reference. There is simply no risk with copying a raii reference into a non-raii reference. Why would someone disallow it?There is a risk if the non-raii reference will be holding on past the function invocation lifetime -- if it is storing it away in a cache or something. Of course, such a situation will blow up anything that isn't reference counted, so we'll ignore that case for the time being...Because I want functions which take a reference to a File object, and don't close the File, you cannot have File as a raii class. Only specific references to File-s can be raii. Can you please provide a class which requires all references to it, to be raii? Because that is what you are suggesting. So I agree with you in most points, but think there is no need for this "auto class", but only for the individual "auto"s. Yours, SandorMy personal preference is not to require the per-instance keyword, because it is easy to forget it and then lose all of the benefits of raii. If I make a Lock class, I know that in 99.99% of the cases I want it to be raii. Why require someone to type an extra keyword for all of those cases? Why add the debugging risk of forgetting to type it to the most common case? C++ requires you to flag each and every member function as virtual if you want polymorphism to work. How many class hierarchies are subtly broken because somebody forgot to add that word? 'virtual' is the most common case, so it should be what you get if you don't go out of your way to specify otherwise. Because C++ broke that rule, lots of C++ code is broken as well. I would prefer to avoid a similar mistake in D (which does do 'virtual' by default, by the way, because Walter realized this problem). Because there will always be the odd case of needing a non-raii instance of a class that is "almost always" raii, I recommend having a keyword that *stops* raii behavior for a particular instance. That way, the keyword is only used to flag the special cases, not the common cases. With this, you signal your class that all of its instances are raii unless otherwise noted, and then let people switch individual special cases back to normal GC'ed instances. Another argument for having the raii per-instance keyword is that it signifies at the local code that this instance is used differently. I'm not a big believer in this, but I see the validity of the issue. If that is a desirable property, then I would keep the raii for classes, and then whenever you make an instance of that class, you are then required to explicitly state whether you want raii or gc behavior. More typing than I prefer, but it is explicit about these classes and their use. Mac
Sep 04 2002
Mac Reiter wrote:Another argument for having the raii per-instance keyword is that it signifies at the local code that this instance is used differently. I'm not a big believer in this, but I see the validity of the issue. If that is a desirable property, then I would keep the raii for classes, and then whenever you make an instance of that class, you are then required to explicitly state whether you want raii or gc behavior. More typing than I prefer, but it is explicit about these classes and their use.Yes, exactly. I think it would be the best approach.
Sep 04 2002
There is a risk if the non-raii reference will be holding on past thefunctioninvocation lifetime -- if it is storing it away in a cache or something.Ofcourse, such a situation will blow up anything that isn't referencecounted, sowe'll ignore that case for the time being...Yes that kind of trickery can also ruin the "struct destructors" concept. And of course you will need non-raii references to Lock and File objects, to enable function calls (including member functions of Lock and File). Would you disable member function calls of Lock and File? The secret parameter, the reference to itself will be non-raii, and can be stored anywhere you like. But let me start a new line of discussion here. You don't really need to *delete* the instance. Memory is not important. You only need to release other resources. Finalyzing or "disposing" would do. Then the old references may remain valid. Like references to an existing but closed File object. All i/o operations would produce exceptions. I think it is more elegant than possibly having "dangling references".don'tBecause I want functions which take a reference to a File object, andit isclose the File, you cannot have File as a raii class. Only specific references to File-s can be raii. Can you please provide a class which requires all references to it, to be raii? Because that is what you are suggesting.My personal preference is not to require the per-instance keyword, becauseeasy to forget it and then lose all of the benefits of raii. If I make aLockclass, I know that in 99.99% of the cases I want it to be raii. Whyrequiresomeone to type an extra keyword for all of those cases? Why add thedebuggingrisk of forgetting to type it to the most common case? C++ requires youto flageach and every member function as virtual if you want polymorphism towork. Howmany class hierarchies are subtly broken because somebody forgot to addthatword? 'virtual' is the most common case, so it should be what you get ifyoudon't go out of your way to specify otherwise. Because C++ broke thatrule,lots of C++ code is broken as well. I would prefer to avoid a similarmistakein D (which does do 'virtual' by default, by the way, because Walterrealizedthis problem). Because there will always be the odd case of needing a non-raii instanceof aclass that is "almost always" raii, I recommend having a keyword that*stops*raii behavior for a particular instance. That way, the keyword is onlyused toflag the special cases, not the common cases. With this, you signal yourclassthat all of its instances are raii unless otherwise noted, and then letpeopleswitch individual special cases back to normal GC'ed instances.The *instances* of Lock and File can (<sigh> almost) always be raii. But you are associating the raii property with the *references* to Lock and File. In this discussion there was no mentioning of keywords to require or stop raii "for a particular instance". How would you accomplish that?"you signal your class that all of its instances are raii unless otherwisenoted" Put it this way: "you signal your class that all *references* to its instances are raii unless otherwise noted" And signaling that doesn't make sense.Another argument for having the raii per-instance keyword is that itsignifiesat the local code that this instance is used differently.The reference is used differently. Actually it is the *owner* reference of the instance, as compared to other references to the same instance. The owner reference deletes the instance, when itself is "scoped out". Other references to the same instance don't do it. Raii is the property of the class. Ownership is the property of the reference. Nothing special is property of the instance. Raii classes differ from non-raii classes that: - an instance of a raii class has exaclty one owner reference pointing to it, - an instance of a non-raii class has exaclty zero owner reference pointing to it. This can be easily achieved if - owner references can be assigned to non-owners without limitation, and - owner references can be overwritten by both kinds of reference, automagically deleting the old owned instance (if there is any).I'm not a big believer in this, but I see the validity of the issue. If that is adesirableproperty, then I would keep the raii for classes, and then whenever youmake aninstance of that class,You mean inside the "new" operator?you are then required to explicitly state whether you want raii or gc behavior. More typing than I prefer, but it is explicitaboutthese classes and their use.
Sep 05 2002
OK, there are two things that I need to point out that will help tremendously: 1. I apologize, I was sloppy with my terminology. When reading my earlier posts, please replace "instance" with "reference". At no point was I actually intentionally referring to the instance (chunk of memory, allocated with new, to which there may be multiple references). I was always referring to the reference variable. Please take my posts, put 'em in an editor, and do a global search and replace, then see if they make any more sense. This was an incredibly bad mistake on my part, because without precision in our words, we can't communicate effectively. 2. I am strongly in favor of reference counting instead of simple scoping. I think that the only reliable and safe deterministic finalization technique is reference counting (assuming the presence of a GC that can come through and gather up the cycles that refcounting leaves behind). Scoping falls out as the simplest case of reference counting. However, I have beaten that horse until it is not only dead, but has now been chopped up, processed, cured, canned, fed to dogs around the country, and gone to its final (though ignoble and somewhat disgusting) resting place(s). It isn't going to happen, at least not in the foreseeable future. So, I have turned my attentions to trying to make the raii system as safe as I can envision it. The safest form that I can imagine, because it requires the least continuous attention and effort from the programmer, is one where classes are flagged so that any references to their instances are raii by default. Then two exceptions are made: 1. References that are function arguments are not raii -- the function isn't creating the instance (I meant it that time :-), so the argument reference is not the owning reference, so it must not exhibit raii destruction behavior. 2. A keyword is introduced to allow a particular owner reference (the one that was used in the statement "MyRef = new MyRaiiClass") to not exhibit raii behaviors. Thus, if a function is going to create an instance (meant that one, too) and attach a reference to it, but it also expects to hand that instance to somewhere else and then exit (which would finalize the instance, normally), it can declare its reference to be a nonraii reference. The following is contrived, but I'm trying to keep it short... raii class Lock{/*...*/} void func1() { Lock lockFromElsewhere; // reference is raii, because no keyword lockFromElsewhere = func2(); } // lockFromElsewhere reference will finalize instance that is returned // from func2 at this point Lock func2() { nonraii Lock notMine = new Lock; // notMine is a nonraii reference return notMine; } // Since notMine is nonraii, nothing magical happens here. Looking at that code, I'm not sure if a third exception needs to be made for function return types or not. I certainly don't want to have to type: nonraii Lock func2() {/*...*/} although that might not be a bad thing... It would signify that the Lock that is being returned does not have the normal raii semantics and will need to be handled some other way. Of course, any return value will "not have the normal raii semantics", so the nonraii keyword there should not technically be necessary. Functions like those above are not common, but it is possible that a subfunction could start doing some work for which it needed to acquire a resource, and then reached a point where it needed to let the caller finish the work, but it doesn't want to release the resource because that would open a window of opportunity for other threads/processes/tasks/whatever to affect the resource. Of the few cases where this comes up, most can probably be handled by redesigning the two functions in question. But there are still some cases that simply need that design. Just to forestall any comments, I wish to point out that Lock can usually be fixed through other means. If a function has to return a locked resource, the programmer must take the responsibility for tracking who owns the lock and who should finally unlock it. Most Lock classes do not actually contain the locking mechanism -- they usually just contain a reference to a Mutex or Semaphore. The purpose of the Lock class is to remove responsibility from the programmer for remembering to unlock the Mutex/Semaphore. If the programmer has taken that responsibility back upon him/herself, then there is no need to use the Lock, and the Mutex/Semaphore (which are non-raii classes anyway) can be directly managed. I mention this to show that I understand that Lock is probably a poor choice for demonstrating some of the more contorted cases that occasionally arise. A better example would probably be File or Printer or Port, where the raii'd class also actually "is" the resource, from a programming standpoint, rather than a simple convenience wrapper around another class. In article <al7dih$2oaq$1 digitaldaemon.com>, Sandor Hojtsy says...The *instances* of Lock and File can (<sigh> almost) always be raii. But you are associating the raii property with the *references* to Lock and File. In this discussion there was no mentioning of keywords to require or stop raii "for a particular instance". How would you accomplish that?OK, given the exceptions mentioned above (function parameter references and keyword marked references), does it now make sense to signal that all non-exceptional references to the raii class are raii references? Mac"you signal your class that all of its instances are raii unless otherwisenoted" Put it this way: "you signal your class that all *references* to its instances are raii unless otherwise noted" And signaling that doesn't make sense.
Sep 05 2002
Sandor Hojtsy wrote:Interesting idea. But maybe you could build it into the compile: There could be a "valid" bool variable (allocated along with the object?) that marked whether or not the object had been finalized. Each call on a member function would include an implicit "in" contract that "valid==true". So use after the object had been "finalized" would result in a contract failure exception. Of course, you could also code this individually into each class that needs it. Perhaps a special template for raii classes: template Raii(X : Object) { class Raii_Wrapper : X { X ref; bool raii_valid = true; void finalize() { ref.finalize(); raii_valid = false; }; invariant() { assert raii_valid; } } } Now, each time that somebody declares an raii object: void func() { auto MyClass raii_ref; // blah } the compiler turns it into an instance of the template, with the implicit finally clause: void func() { instance Raii(MyClass) raii_ref; try { // blah } finally { raii_ref.finalize(); } } Thoughts? -- 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))) ]There is a risk if the non-raii reference will be holding on past thefunctioninvocation lifetime -- if it is storing it away in a cache or something.Ofcourse, such a situation will blow up anything that isn't referencecounted, sowe'll ignore that case for the time being...Yes that kind of trickery can also ruin the "struct destructors" concept. And of course you will need non-raii references to Lock and File objects, to enable function calls (including member functions of Lock and File). Would you disable member function calls of Lock and File? The secret parameter, the reference to itself will be non-raii, and can be stored anywhere you like. But let me start a new line of discussion here. You don't really need to *delete* the instance. Memory is not important. You only need to release other resources. Finalyzing or "disposing" would do. Then the old references may remain valid. Like references to an existing but closed File object. All i/o operations would produce exceptions. I think it is more elegant than possibly having "dangling references".
Sep 05 2002
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3D77A06B.ACD19741 deming-os.org...Interesting idea. But maybe you could build it into the compile: Therecould bea "valid" bool variable (allocated along with the object?) that markedwhetheror not the object had been finalized. Each call on a member functionwouldinclude an implicit "in" contract that "valid==true". So use after theobjecthad been "finalized" would result in a contract failure exception.That is handilly handled (!) by zeroing the vptr after finalization.
Sep 05 2002
Walter wrote:"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3D77A06B.ACD19741 deming-os.org...(Shudder) Well, I suppose any error is better than none. It's a good point, though, that raii finalization should NOT drop the object out of the garbage collection map. Finalize it, but don't mark it as garbage until you're sure there are no dangling references. It will make for easier-to-debug programs.Interesting idea. But maybe you could build it into the compile: Therecould bea "valid" bool variable (allocated along with the object?) that markedwhetheror not the object had been finalized. Each call on a member functionwouldinclude an implicit "in" contract that "valid==true". So use after theobjecthad been "finalized" would result in a contract failure exception.That is handilly handled (!) by zeroing the vptr after finalization.
Sep 05 2002
"Walter" <walter digitalmars.com> wrote in message news:al8nql$2ejr$1 digitaldaemon.com..."Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3D77A06B.ACD19741 deming-os.org...Good. In that case, releasing raii objects should call finalyze, and not delete. Theoretically a wrapper object of a released resource may still have usable member functions, such as statistical data of usage, or filename an such. Calling these functions are still disabled, but at least dangling references are better handled. SandorInteresting idea. But maybe you could build it into the compile: Therecould bea "valid" bool variable (allocated along with the object?) that markedwhetheror not the object had been finalized. Each call on a member functionwouldinclude an implicit "in" contract that "valid==true". So use after theobjecthad been "finalized" would result in a contract failure exception.That is handilly handled (!) by zeroing the vptr after finalization.
Sep 09 2002
"Mac Reiter" <Mac_member pathlink.com> wrote in message news:al5kgm$1ud8$1 digitaldaemon.com...In article <al4j79$2s6p$1 digitaldaemon.com>, Sandor Hojtsy says... I would prefer to avoid a similar mistake in D (which does do 'virtual' by default, by the way, because Walterrealizedthis problem).LOL. I suffered from subtle bugs caused by that exact issue over and over. When you have a large app, the tedium of trying to verify the correctness of the virtual use is boggling. There was just no way to prove your program was free of such. It's a maddening timewaster. The correct way is to have virtual by default, and allow no overrides of final functions.
Sep 05 2002
"Walter" <walter digitalmars.com> wrote in news:akgsaf$aog$1 digitaldaemon.com:The 'auto' idea was looking more and more like a way to simply put class objects on the stack.A example of code being converted for user RAII: http://sourceforge.net/docman/display_doc.php?docid=8673&group_id=9028 This is the Firebird SQL DB Server converted from C to C++
Sep 05 2002