D - RAII
- Walter (33/33) Aug 25 2002 Resource Aquisition Is Initialization (RAII)
- Pavel Minayev (7/16) Aug 25 2002
- Walter (5/8) Aug 25 2002 If no big problems with it show up.
- Russell Lewis (2/21) Aug 26 2002 I get nightmares of "riaa" objects...
- Patrick Down (6/16) Aug 25 2002 What happens if a is reassigned? Can A be reassigned?
- Walter (4/8) Aug 25 2002 In that case, the first a will get deleted by the gc when it gets around...
- Russell Lewis (3/17) Aug 26 2002 IMHO,If the reference is raii, the old object should get deleted
- Matthew Wilson (5/38) Aug 25 2002 Excellent!
- Sandor Hojtsy (13/46) Aug 26 2002 scope.
- Mac Reiter (83/99) Aug 26 2002 I don't know about the "suggesting a few months ago", since I am a very ...
- Walter (74/152) Aug 26 2002 I think it was suggested, though I can't recall who did. It might have b...
- Pavel Minayev (15/15) Aug 26 2002 On Mon=2C 26 Aug 2002 10=3A23=3A14 -0700 =22Walter=22 =3Cwalter=40digita...
- Walter (9/9) Aug 26 2002 Wouldn't it be better to make it clear upon each use that this is an
- Pavel Minayev (4/6) Aug 27 2002 Sometimes making it non-auto (simply by forgetting to put "auto" in
- Walter (6/12) Aug 27 2002 wrote:
- Russell Lewis (2/22) Aug 27 2002 How about being able to check "auto" in the invariant of the class?
- Walter (5/9) Aug 27 2002 (because
- Pavel Minayev (10/13) Aug 27 2002
- Mac Reiter (2/9) Aug 27 2002 Now that sounds like a plan. Explicitness is good.
- Mac Reiter (189/287) Aug 26 2002 To avoid constantly saying "scoped or reference counted", I'm just going...
- Russell Lewis (11/11) Aug 26 2002 Part of the problem (that I see) is that classes may need to be dof if
- Walter (132/290) Aug 26 2002 much
- Sean L. Palmer (40/101) Aug 27 2002 I don't know what you're talking about. A file reference in a non-dof c...
- Pavel Minayev (15/15) Aug 27 2002 On Mon=2C 26 Aug 2002 20=3A11=3A51 +0000 =28UTC=29 Mac Reiter =3CMac=5Fm...
- Sean L. Palmer (8/8) Aug 27 2002 Just poking my head into this thread to mention that if you think having
- Patrick Down (11/13) Aug 26 2002 I think this is a very pragmatic solution to a hard
- Russell Lewis (7/31) Aug 26 2002 I seem to remember that "auto" had some meaning back in the early C
- Pavel Minayev (25/25) Aug 26 2002 On Mon=2C 26 Aug 2002 11=3A39=3A00 -0700 Russell Lewis
- Walter (8/8) Aug 26 2002 Yeah, that might be a good approach.
- Walter (11/24) Aug 26 2002 Ok, ok!
- Patrick Down (4/9) Aug 26 2002 True. I was trying to sneek stack based storage in
- Russell Lewis (3/3) Aug 26 2002 You probably should be able to declare certain members of a class to be
- Walter (5/8) Aug 27 2002 destructor.
- Russ Lewis (8/16) Aug 28 2002 Details? I've learned to trust it when you say "too complex"...but I'm ...
- Walter (8/20) Aug 28 2002 be
Resource Aquisition Is Initialization (RAII) RAII is a programming paradigm where resources are automatically released when an object is no longer referenced. In C++, this is accomplished by putting the release code in a class destructor, and then the compiler will automatically insert the destructor call when the object goes out of scope. In D, automatic objects are structs, and structs do not have destructors. Classes have destructors (finalizers), but are only allocated on the gc heap, so the finalizer gets run at arbitrary and unpredictable times. D does support explicit finalization of objects: A a = new A(); ... delete a; but in the inevitable presence of exceptions, to make the code robust and reliable: try { A a = new A(); ... } finally { delete a; } While this does work, it can get tedious and unsightly when dealing with many such objects. The solution is to create a new storage class, raii: raii A a = new A(); All raii references will get a finally block created for them that calls delete on the reference. Of course, if the programmer stores a copy of a somewhere outside the scope, that reference will point to garbage once the scope is exited.
Aug 25 2002
On Sun, 25 Aug 2002 12:18:09 -0700 "Walter" <walter digitalmars.com> wrote:The solution is to create a new storage class, raii: raii A a = new A(); All raii references will get a finally block created for them that calls delete on the reference. Of course, if the programmer stores a copy of a somewhere outside the scope, that reference will point to garbage once the scope is exited.Is it going to be part of D? Just a suggestion... "raii" doesn't sound good =). I'd suggest using "auto" instead.
Aug 25 2002
"Pavel Minayev" <evilone omen.ru> wrote in message news:CFN374939933247569 news.digitalmars.com...Is it going to be part of D?If no big problems with it show up.Just a suggestion... "raii" doesn't sound good =). I'd suggest using"auto"instead.Yeah, auto is probably better.
Aug 25 2002
Pavel Minayev wrote:On Sun, 25 Aug 2002 12:18:09 -0700 "Walter" <walter digitalmars.com> wrote:I get nightmares of "riaa" objects...The solution is to create a new storage class, raii: raii A a = new A(); All raii references will get a finally block created for them that calls delete on the reference. Of course, if the programmer stores a copy of a somewhere outside the scope, that reference will point to garbage once the scope is exited.Is it going to be part of D? Just a suggestion... "raii" doesn't sound good =). I'd suggest using "auto" instead.
Aug 26 2002
"Walter" <walter digitalmars.com> wrote in news:akba6n$28tb$1 digitaldaemon.com:The solution is to create a new storage class, raii: raii A a = new A(); All raii references will get a finally block created for them that calls delete on the reference. Of course, if the programmer stores a copy of a somewhere outside the scope, that reference will point to garbage once the scope is exited.What happens if a is reassigned? Can A be reassigned? raii A a = new A(); a = new A(); I like "auto" better too.
Aug 25 2002
"Patrick Down" <pat codemoon.com> wrote in message news:Xns9275A0B6E350Cpatcodemooncom 63.105.9.61..."Walter" <walter digitalmars.com> wrote in What happens if a is reassigned? Can A be reassigned? raii A a = new A(); a = new A();In that case, the first a will get deleted by the gc when it gets around to it. Or you could explicitly do it via delete.
Aug 25 2002
Walter wrote:"Patrick Down" <pat codemoon.com> wrote in message news:Xns9275A0B6E350Cpatcodemooncom 63.105.9.61...IMHO,If the reference is raii, the old object should get deleted whenever you reassign the reference!"Walter" <walter digitalmars.com> wrote in What happens if a is reassigned? Can A be reassigned? raii A a = new A(); a = new A();In that case, the first a will get deleted by the gc when it gets around to it. Or you could explicitly do it via delete.
Aug 26 2002
Excellent! auto is a better keyword though "Walter" <walter digitalmars.com> wrote in message news:akba6n$28tb$1 digitaldaemon.com...Resource Aquisition Is Initialization (RAII) RAII is a programming paradigm where resources are automatically released when an object is no longer referenced. In C++, this is accomplished by putting the release code in a class destructor, and then the compiler will automatically insert the destructor call when the object goes out ofscope.In D, automatic objects are structs, and structs do not have destructors. Classes have destructors (finalizers), but are only allocated on the gc heap, so the finalizer gets run at arbitrary and unpredictable times. D does support explicit finalization of objects: A a = new A(); ... delete a; but in the inevitable presence of exceptions, to make the code robust and reliable: try { A a = new A(); ... } finally { delete a; } While this does work, it can get tedious and unsightly when dealing with many such objects. The solution is to create a new storage class, raii: raii A a = new A(); All raii references will get a finally block created for them that calls delete on the reference. Of course, if the programmer stores a copy of a somewhere outside the scope, that reference will point to garbage once the scope is exited.
Aug 25 2002
"Walter" <walter digitalmars.com> wrote in message news:akba6n$28tb$1 digitaldaemon.com...Resource Aquisition Is Initialization (RAII) RAII is a programming paradigm where resources are automatically released when an object is no longer referenced. In C++, this is accomplished by putting the release code in a class destructor, and then the compiler will automatically insert the destructor call when the object goes out ofscope.In D, automatic objects are structs, and structs do not have destructors. Classes have destructors (finalizers), but are only allocated on the gc heap, so the finalizer gets run at arbitrary and unpredictable times. D does support explicit finalization of objects: A a = new A(); ... delete a; but in the inevitable presence of exceptions, to make the code robust and reliable: try { A a = new A(); ... } finally { delete a; } While this does work, it can get tedious and unsightly when dealing with many such objects. The solution is to create a new storage class, raii: raii A a = new A(); All raii references will get a finally block created for them that calls delete on the reference. Of course, if the programmer stores a copy of a somewhere outside the scope, that reference will point to garbage once the scope is exited.Hey, isn't that exactly the same that we was suggesting a few months ago? I thought it was ignored. And the same problem arises: In practice, RAII is not the property of the instance, but of the class, isn't it? Then you need to specify this at the class declaration of "A", so it cannot be a storage class. Thoughts? Yours, Sandor
Aug 26 2002
In article <akd1sb$1ed6$1 digitaldaemon.com>, Sandor Hojtsy says..."Walter" <walter digitalmars.com> wrote in message news:akba6n$28tb$1 digitaldaemon.com...[clip]Resource Aquisition Is Initialization (RAII) RAII is a programming paradigm where resources are automatically released when an object is no longer referenced. In C++, this is accomplished byHey, isn't that exactly the same that we was suggesting a few months ago? I thought it was ignored. And the same problem arises: In practice, RAII is not the property of the instance, but of the class, isn't it? Then you need to specify this at the class declaration of "A", so it cannot be a storage class. Thoughts? Yours, SandorI don't know about the "suggesting a few months ago", since I am a very sporadic participant in this newsgroup (highly active for short periods, then nothing for quite awhile...). I do, however, agree that scoping is almost always going to be a property of the class, not the instances. Arguably, making it an instance is more flexible (if you have some reason to make a non-auto instance, you can), but you can now hose your program by forgetting to put the 'auto' in front of one of your instances. This could be fatal for something like a mutex -- if other threads got locked up before the GC ran, you could end up deadlocking the entire program over a mutex that should have been freed. Yes, it is a bug to forget the 'auto', but it would likewise be a bug to forget the 'try{}finally{}' that is being replaced by the auto. If it is doable, I would prefer that 'auto' be a class property ( auto class Lock{} ). If flexibility is a problem, and it becomes necessary for a particular instance of an 'auto class' to outlive its scope (unlikely, but it is possible), and if un-autoing the class is simply not an acceptable solution, perhaps a keyword like 'collected' or 'non_auto' could be added (it doesn't have to look nice -- it will be used VERY infrequently and should only be used by people who really know what they are doing) as a storage class so that it disabled 'auto'ness for a particular instance. Or, to flog a fatally wounded horse one last time, you could implement reference counting and get the RAII that you originally described : "RAII is a programming paradigm where resources are automatically released when an object is no longer referenced." C++'s method is a limited subset of what RAII really should be. If you can automatically implement the pseudo-finally to perform a delete for auto instances, you can automatically implement a pseudo-finally to decrement the reference count for a counted instance. The only reason for un-autoing an instance of an auto class (that I can think of) is to pass the instance on to someone else (it is occasionally necessary to transfer ownership of a synchronization lock). Reference counting handles this case without needing another keyword or any other special handling. The act of handing off the instance increases the refcount, keeping the instance alive. Reference counting also solves the: { auto A a = new A; // A1 a = new A; // A2 } where A2 gets deleted but A1 waits for the GC to get around to it (which is not RAII or deterministic). Refcounting would have to watch assignments, and modify the refcount for the old object as well as the new. But when it did that, it would notice that A1 was no longer used and could finalize it (I defer to the masses on whether it should be deleted or not, but it definitely should be finalized). As for whether the suggested 'counted' should be an instance or class property, I suspect the argument given above for class property still holds. Classes should be counted, not instances. Part of the reason for this is that a refcounted instance could be returned from a function and still be valid. If refcounting is an instance property, the external storage instance (the variable that stores the function return value) would also have to be refcounted to maintain the refcounting invariant. If the property belongs to the class, then all instances of the class are refcounted, and life is good. Also, by making it a class property, you can set a flag in the symbol table that says that this class: 1. is synchronized (refcounting must be thread safe) 2. contains a refcount field 3. has additional refcounting prolog or epilog in its assignment operator 4. <anything else that comes up as being necessary for refcounting> That way you don't have to track it on a per-instance basis, which should simplify processing. Because derived types can be assigned into base type references, it may be necessary to consider the interaction of inheritance and the 'counted' class specifier. Are all children of a counted class automatically counted? Can instances of counted classes be polymorphically assigned into non-counted base references? How about the other way around? It may also become necessary to make assignments across refcounting boundaries illegal, at least for current compilers, until the potential needs/problems are understood better. I realize that actually stopping *only* assignments across the refcounting border would require a runtime check. Perhaps a compile time restraint that simply says that counted classes are not allowed to participate in polymorphic assignments at all would be a better first solution... Yes, there are complications with 'counted' classes. But realistically, either compiler writers or programmers are going to experience similar complications with 'auto' classes (and worse problems with 'auto' instances). If the problems are roughly the same, I would vote for the more flexible and complete solution. Of course, I am somewhat biased on the issue... As a quick comment, if 'auto' is going to win out over 'counted', I would prefer 'scoped' over 'auto', because 'auto' means so many different things. 'scoped' (at least to me) is very explicit about exactly what behavior you are modifying. Of course, if you are worried about adding common keywords, 'scoped' is not currently a keyword in other languages, but I think 'auto' is already reserved in C/C++, which would make it a better choice from that standpoint. Mac
Aug 26 2002
"Mac Reiter" <Mac_member pathlink.com> wrote in message news:akdgqc$218p$1 digitaldaemon.com...In article <akd1sb$1ed6$1 digitaldaemon.com>, Sandor Hojtsy says...I think it was suggested, though I can't recall who did. It might have been Pavel.Hey, isn't that exactly the same that we was suggesting a few months ago? I thought it was ignored.cannotAnd the same problem arises: In practice, RAII is not the property of the instance, but of the class, isn't it? Then you need to specify this at the class declaration of "A", so itMaking it a property of the class, rather than the instance, leads to much implementation grief. For example, pulling on that thread a bit <g>, it seems to lead to needing to implement two versions of each class - one counted, one not.be a storage class. Thoughts?If it is doable, I would prefer that 'auto' be a class property ( autoclassLock{} ). If flexibility is a problem, and it becomes necessary for a particular instance of an 'auto class' to outlive its scope (unlikely, butit ispossible), and if un-autoing the class is simply not an acceptablesolution,perhaps a keyword like 'collected' or 'non_auto' could be added (itdoesn't haveto look nice -- it will be used VERY infrequently and should only be usedbypeople who really know what they are doing) as a storage class so that it disabled 'auto'ness for a particular instance.While in C++ it is common to have a destructor (to manage memory), in D having a resource that needs cleaning up should be the exception, not the rule.Or, to flog a fatally wounded horse one last time, you could implementreferencecounting and get the RAII that you originally described : "RAII is aprogrammingparadigm where resources are automatically released when an object is nolongerreferenced." C++'s method is a limited subset of what RAII really shouldbe.If you can automatically implement the pseudo-finally to perform a deleteforauto instances, you can automatically implement a pseudo-finally todecrementthe reference count for a counted instance. The only reason forun-autoing aninstance of an auto class (that I can think of) is to pass the instance ontosomeone else (it is occasionally necessary to transfer ownership of a synchronization lock). Reference counting handles this case withoutneedinganother keyword or any other special handling. The act of handing off the instance increases the refcount, keeping the instance alive.Reference counting involves far, far more than just a pseudo-finally.Reference counting also solves the: { auto A a = new A; // A1 a = new A; // A2 } where A2 gets deleted but A1 waits for the GC to get around to it (whichis notRAII or deterministic). Refcounting would have to watch assignments, andmodifythe refcount for the old object as well as the new. But when it did that,itwould notice that A1 was no longer used and could finalize it (I defer tothemasses on whether it should be deleted or not, but it definitely should be finalized).At least in D the resource would eventually get cleaned up on the GC pass, whereas in C++ it is a memory leak that will never get cleaned up.As for whether the suggested 'counted' should be an instance or classproperty,I suspect the argument given above for class property still holds.Classesshould be counted, not instances. Part of the reason for this is that a refcounted instance could be returned from a function and still be valid.Ifrefcounting is an instance property, the external storage instance (thevariablethat stores the function return value) would also have to be refcounted to maintain the refcounting invariant. If the property belongs to the class,thenall instances of the class are refcounted, and life is good. Also, bymaking ita class property, you can set a flag in the symbol table that says thatthisclass: 1. is synchronized (refcounting must be thread safe) 2. contains a refcount field 3. has additional refcounting prolog or epilog in its assignment operator 4. <anything else that comes up as being necessary for refcounting> That way you don't have to track it on a per-instance basis, which should simplify processing. Because derived types can be assigned into base type references, it may be necessary to consider the interaction of inheritance and the 'counted'classspecifier. Are all children of a counted class automatically counted?Caninstances of counted classes be polymorphically assigned into non-countedbasereferences? How about the other way around? It may also become necessarytomake assignments across refcounting boundaries illegal, at least forcurrentcompilers, until the potential needs/problems are understood better. Irealizethat actually stopping *only* assignments across the refcounting borderwouldrequire a runtime check. Perhaps a compile time restraint that simplysays thatcounted classes are not allowed to participate in polymorphic assignmentsat allwould be a better first solution...Suppose you have a printing function that takes an object of type Object. Object is not counted, so the counted class is cast to Object. To support this, it becomes necessary to 1) extend counting to every object 2) ignore the possibility of bugs from dangling references 3) disallow conversions to Object. 1) has too many penalties for D as whole 2) is a similar bug to handing off a reference to an 'auto' instance, but I think worse because it will happen more often 3) requires creation of two versions of most things in the library, one to handle counted and one for non-countedYes, there are complications with 'counted' classes. But realistically,eithercompiler writers or programmers are going to experience similarcomplicationswith 'auto' classes (and worse problems with 'auto' instances). If theproblemsare roughly the same, I would vote for the more flexible and completesolution.Of course, I am somewhat biased on the issue...No, I believe the 'auto' approach has an order of magnitude less implementation effort than ref counting. For example, it won't be necessary to handle arrays of counted objects, counted objects as members of structs, counted objects as members of non-counted objects, assignment overloading, etc.As a quick comment, if 'auto' is going to win out over 'counted', I wouldprefer'scoped' over 'auto', because 'auto' means so many different things.'scoped'(at least to me) is very explicit about exactly what behavior you aremodifying.Of course, if you are worried about adding common keywords, 'scoped' isnotcurrently a keyword in other languages, but I think 'auto' is alreadyreservedin C/C++, which would make it a better choice from that standpoint.auto does have the nice advantage that people recognize it as a keyword.
Aug 26 2002
On Mon=2C 26 Aug 2002 10=3A23=3A14 -0700 =22Walter=22 =3Cwalter=40digitalmars=2Ecom=3E wrote=3A =3E I think it was suggested=2C though I can't recall who did=2E It might have been =3E Pavel=2E I think it was me=2C but can't tell it for sure=2E Okay=2C so you can blame me=2E =3D=29 =3E Making it a property of the class=2C rather than the instance=2C leads to much =3E implementation grief=2E For example=2C pulling on that thread a bit =3Cg=3E=2C it =3E seems to lead to needing to implement two versions of each class - one =3E counted=2C one not=2E I wonder if you'd be able to emulate this proposed =22refcounted class=22 behaviour by applying attirubute to a typedef=3A =09class =5FFile { =2E=2E=2E } =09typedef auto =5FFile File=3B
Aug 26 2002
Wouldn't it be better to make it clear upon each use that this is an auto-destruct instance? "Pavel Minayev" <evilone omen.ru> wrote in message news:CFN374949748311227 news.digitalmars.com... I wonder if you'd be able to emulate this proposed "refcounted class" behaviour by applying attirubute to a typedef: class _File { ... } typedef auto _File File;
Aug 26 2002
On Mon, 26 Aug 2002 13:17:01 -0700 "Walter" <walter digitalmars.com> wrote:Wouldn't it be better to make it clear upon each use that this is an auto-destruct instance?Sometimes making it non-auto (simply by forgetting to put "auto" in declaration) is an _error_. For example, a Lock is supposed to be always auto.
Aug 27 2002
"Pavel Minayev" <evilone omen.ru> wrote in message news:CFN374955344668171 news.digitalmars.com...On Mon, 26 Aug 2002 13:17:01 -0700 "Walter" <walter digitalmars.com>wrote:I've been thinking about that. Some classes should never be 'auto' (because they might squirrel a reference to themselves away remotely), and some should always be 'auto'.Wouldn't it be better to make it clear upon each use that this is an auto-destruct instance?Sometimes making it non-auto (simply by forgetting to put "auto" in declaration) is an _error_. For example, a Lock is supposed to be always auto.
Aug 27 2002
Walter wrote:"Pavel Minayev" <evilone omen.ru> wrote in message news:CFN374955344668171 news.digitalmars.com...How about being able to check "auto" in the invariant of the class?On Mon, 26 Aug 2002 13:17:01 -0700 "Walter" <walter digitalmars.com>wrote:I've been thinking about that. Some classes should never be 'auto' (because they might squirrel a reference to themselves away remotely), and some should always be 'auto'.Wouldn't it be better to make it clear upon each use that this is an auto-destruct instance?Sometimes making it non-auto (simply by forgetting to put "auto" in declaration) is an _error_. For example, a Lock is supposed to be always auto.
Aug 27 2002
"Russell Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3D6BBF0D.3010000 deming-os.org...(becauseI've been thinking about that. Some classes should never be 'auto'Since such errors could be detected at compile time, I think it would be better to do it that way.they might squirrel a reference to themselves away remotely), and some should always be 'auto'.How about being able to check "auto" in the invariant of the class?
Aug 27 2002
On Tue, 27 Aug 2002 10:38:41 -0700 "Walter" <walter digitalmars.com> wrote:I've been thinking about that. Some classes should never be 'auto' (because they might squirrel a reference to themselves away remotely), and some should always be 'auto'.I think that the best approach would be to allow both auto classes and auto objects. Every instance of an auto class _must_ be declared as auto, otherwise it is an error. Non-auto classes can still have auto instances. Why require auto for classes if they are auto already? It'd make clear that class is actually auto.
Aug 27 2002
I think that the best approach would be to allow both auto classes and auto objects. Every instance of an auto class _must_ be declared as auto, otherwise it is an error. Non-auto classes can still have auto instances. Why require auto for classes if they are auto already? It'd make clear that class is actually auto.Now that sounds like a plan. Explicitness is good. Mac
Aug 27 2002
To avoid constantly saying "scoped or reference counted", I'm just going to say dof'ed (deterministic object finalized, or something like that...) I cannot offhand think of any classes that would need both a dof'ed and normal implementation. Most standard library classes certainly don't need dof behavior. Of the dof'able classes I can consider (Locks, Files, Ports), they should always be dof'ed. If I am finished with a Lock, it needs to be released now, or it may deadlock the program. If I am finished with a File or Port, it should be released now so that other applications can work with it. If someone really does need both versions of a class, it isn't all that difficult to do: class Foo{} dof class DofFoo : Foo{} (I am going to go slightly off my primary point here because I want to head off any comments about having to remember which version of the class to use...) This is no better or worse than the instance property approach for this case, but for the more common case of a dof'ed-only class, it saves the user having to remember the extra keyword each time they use the class. The number of polymorphic C++ designs that have blown up because a member functions somewhere in the class hierarchy left off the "virtual" keyword should be a clear enough example of why it would be preferable to make dof a class property rather than requiring a keyword at each instance. The quick point is that I personally cannot imagine a class that needs both dof'ed and normal implementations, but even if such a class arises it can be handled with inheritance with no more effort cost than the instance property form would force on all dof'ed instances.cannotAnd the same problem arises: In practice, RAII is not the property of the instance, but of the class, isn't it? Then you need to specify this at the class declaration of "A", so itMaking it a property of the class, rather than the instance, leads to much implementation grief. For example, pulling on that thread a bit <g>, it seems to lead to needing to implement two versions of each class - one counted, one not.be a storage class. Thoughts?I think this comment is suggesting that dof'ing is an exception, so it's OK to require a keyword at each instance. While a dof'ed instance may be an exception compared to the broader scope of programming (see below for my doubts), for classes that need dof the dof'ed instance is definitely the rule rather than the exception. Consider the all-too-common Lock. Lock would be dof'ed at least 99.9% of the time. Any non-dof usage of Lock would almost certainly be better handled by performing the lock/unlock function on the underlying Mutex/Semaphore/CriticalSection, rather than bundling it up in a useless Lock. Lock's very existence is to provide dof services. Lock doesn't even need to have any member functions -- its constructor locks the sync object, and its destructor/finalizer unlocks it. It has no other user interface. If such services can be disabled by forgetting to add a keyword, then they might as well not exist. When using classes that have dof behavior, dof is the rule, and non-dof is either non-existent or a rare exception. This suggests that dof classes should not require a keyword for the common dof'ed instances, and possibly have a keyword for the exceptional non-dof'ed instances. Slightly off topic, since I know that you recognize the importance of dof (otherwise you would not have offered up an implementation, right?). The statement that the use of dof is the exceptional case bothers me. I suspect D specifically because of the lack of dof? Once a programmer becomes familiar with RAII-style programming, relying on some form of dof, it can very quickly permeate designs. This is not simply syntactic sugar, but is a fundamental design practice that helps make the resulting implementation stabler, more correct, and more robust. A programmer that is used to RAII would never even consider attempting to make a multithreaded program without RAII. I realize that D's synchronized keyword and inherent multithreading simplify this process, but there are always other resources that are commonly used, and misused, that can benefit from dof/RAII behaviors.If it is doable, I would prefer that 'auto' be a class property ( autoclassLock{} ). If flexibility is a problem, and it becomes necessary for a particular instance of an 'auto class' to outlive its scope (unlikely, butit ispossible), and if un-autoing the class is simply not an acceptablesolution,perhaps a keyword like 'collected' or 'non_auto' could be added (itdoesn't haveto look nice -- it will be used VERY infrequently and should only be usedbypeople who really know what they are doing) as a storage class so that it disabled 'auto'ness for a particular instance.While in C++ it is common to have a destructor (to manage memory), in D having a resource that needs cleaning up should be the exception, not the rule.[clip]Or, to flog a fatally wounded horse one last time, you could implementreferencecounting and get the RAII that you originally described : "RAII is aprogrammingparadigm where resources are automatically released when an object is nolongerreferenced." C++'s method is a limited subset of what RAII really shouldbe.If you can automatically implement the pseudo-finally to perform a deleteforauto instances, you can automatically implement a pseudo-finally todecrementthe reference count for a counted instance. The only reason forReference counting involves far, far more than just a pseudo-finally.Granted. But in one of my previous refcounting posts it was mentioned that the primary difficulty was in maintaining the reference counting invariant in the presence of exceptions. Well, you have a mechanism for handling arbitrarily complicated stuff in the presence of exceptions, so it shouldn't be any harder to maintain the invariant with exceptions than it would have been without exceptions.It would eventually get cleaned up as long as some thread remained active to pump the GC. Back to Locks and threads: if I do not write a separate thread whose sole job is to run this code: while (!done) { gc.Collect(); } then it is possible to get in a state where all threads are locked on a Lock instance that has been lost. _If_ the GC could ever get cycles to run, it would notice this object and finalize it. But since all of the threads are locked on this object, the GC never gets a chance to run, so the object never gets finalized, and the application sits there forever. Unlikely, but the first rule in multithreaded programming is that (to plagiarize shamelessly from Terry Pratchett's Discworld books) "1 in a million chances happen 9 times out of 10". "Should" isn't "will", and unless it "will" be collected, it isn't safe.Reference counting also solves the: { auto A a = new A; // A1 a = new A; // A2 } where A2 gets deleted but A1 waits for the GC to get around to it (whichis notRAII or deterministic). Refcounting would have to watch assignments, andmodifythe refcount for the old object as well as the new. But when it did that,itwould notice that A1 was no longer used and could finalize it (I defer tothemasses on whether it should be deleted or not, but it definitely should be finalized).At least in D the resource would eventually get cleaned up on the GC pass, whereas in C++ it is a memory leak that will never get cleaned up.[clip]As for whether the suggested 'counted' should be an instance or classproperty,I suspect the argument given above for class property still holds.Classesshould be counted, not instances. Part of the reason for this is that a[clip]Because derived types can be assigned into base type references, it may be necessary to consider the interaction of inheritance and the 'counted'classspecifier. Are all children of a counted class automatically counted?This is why I suggested that 'counted' classes not be allowed to participate in polymorphic actions (conversion to Object, in your example). I certainly don't want everything in D to be refcounted. I have mentioned several times that refcounting adds a very noticeable performance penalty, and thus should be limited only to those things that need it. I also agree that "Ignoring the possibility of bugs" is never a wise choice of action. That is why I went for disabling type conversions for counted classes. I actually went further than your 3), because I suggested disabling _any_ conversion, up or down, to any level of the class hierarchy. The compiler simply disallows casting a counted class, implicitly or explicitly, to anything else. Maybe someday, when more experience is gained, some method of safely handling conversions may be found. But I don't think a moratorium on 'counted' conversions would cause any problems. Let me explain why: (I will continue to use thread synchronization primitives and the Lock class, because it is my primary experience with the RAII idiom that does not work just as well with GC) Say you have some system that needs to be able to manage a collection of Locks, some of which will lock Mutexes, others lock Semaphores, etc. You might think that you need polymorphism here so that you can treat all the different types of Locks as the same type. But that is a flawed design. There is only _one_ Lock type. What is changing is not the type of lock, but the type of object being locked. Lock has a private data member, and that member will be a polymorphic base class pointer/reference to the base class of all of the synchronization objects: class SyncObject{} class Mutex : SyncObject{} class Semaphore : SyncObject{} counted class Lock { SyncObject* lockableObject; } Lock[] MyLocks; bool HandleLock(Lock TheLock); Note that Lock does not derive from anything, and nothing derives from Lock, and yet you can still maintain a collection of Locks that are each internally polymorphizing SyncObjects. You don't need any implicit or explicit conversions, so the 'counted' on Lock doesn't cause any problems. I already talked about the "requires creation of two versions of most things in the library, one to handle counted and one for non-counted" issue above, and why I don't think it is an issue.require a runtime check. Perhaps a compile time restraint that simplysays thatcounted classes are not allowed to participate in polymorphic assignmentsat allwould be a better first solution...Suppose you have a printing function that takes an object of type Object. Object is not counted, so the counted class is cast to Object. To support this, it becomes necessary to 1) extend counting to every object 2) ignore the possibility of bugs from dangling references 3) disallow conversions to Object. 1) has too many penalties for D as whole 2) is a similar bug to handing off a reference to an 'auto' instance, but I think worse because it will happen more often 3) requires creation of two versions of most things in the library, one to handle counted and one for non-counted1. arrays of counted objects Pragmatically, this means that the array is counted. The slightly tricky bit is that the array doesn't have a refcount of its own. Its refcount is the largest refcount of any of its elements. For pathological cases, this could be expensive to check, but you do get to stop as soon as you hit any non-zero refcount, so it's only a problem for large arrays of counted objects, where all but the last object have already been "freed". Because of that, I would recommend that when you construct the pseudo-finally, you decrement refcounts for the array elements starting at the back, so that each check will see the positive refcount in the first array element. Then when you finish by decrementing the refcount of the first element, the array refcount check will make one big sweep through and free up the memory. (Or, if you write the count checking loop as a back-to-front loop, then do the decrements from front-to-back.) Of course, static analysis could be used in more advanced implementations to notice when the refcount would never exceed 1 and just finalize the whole array, bypassing the whole refcounting proceedings, at scope exit. But it doesn't have to be that fancy to begin with. I also don't see really big arrays of counted objects, but just 'coz I don't see it doesn't mean somebody won't try to do it... 2. counted objects as members of structs I assume this is referring to the lack of destructors for structs, which would mean that there was nowhere to perform the refcount decrement. My simple answer for this is the same as it would be for (keep reading): 3. counted objects as members of non-counted objects Similar to the "Lock isn't polymorphic, it just contains a polymorphic member" example above, I suspect that it is a bad design to have a counted object as a member of a non-counted object, whether it is a struct or a normal class. I think that the composite class should also be counted. But I also believe that you shouldn't walk around with pointers to members of objects, so maybe I'm a little too strict. My simple answer is to disallow it. Compiler error. It would have to wait until the symbol table is available during actual compilation to detect, given the "property of a class" nature of the counted keyword. Since nobody but the compiler particularly needs to know about the counted/non-counted nature of classes, I don't think that's a problem. 4. assignment overloading I think that this is addressed by the "disallow conversions" and "store a flag in the symbol table to know that you need additional prolog/epilog code for assignment" topics. It would not surprise me, however, to discover that I am simply overlooking something. Reference counting _will_ eventually be implemented. It's been done several times in C++, and C++ already had dof. No matter how hard it is to do in the compiler, it is even harder to do correctly from source-code-land. Sometimes it is even impossible to do correctly from out here, due to optimizations that can be performed by the compiler, which can result is out-of-order operation that makes the classes think that the last reference was removed before another reference was created. If I had to pick someone I trust to implement difficult things correctly, I would rather trust you (Walter) than someone who decides to provide an add-on library that "does reference counting, mostly, as long as you don't ever do <list of not entirely uncommon things>". Yes, it does add to the complexity of the compiler. But I suspect that once you did it you would find some simplifications and tricks that made it considerably easier. Having rambled on for so long, I will close with this. I would _really_ prefer the dof mechanism to be reference counting, but if scoping is all anyone else needs, then that is still almost infinitely better than no dof at all. Most dof usage will be fine with scoping. The problem of "losing" instances when their controlling reference switches to a new instance (A1 and A2 example) is a little disturbing, but probably not common in practice. C++ avoids it by removing the reference indirection -- RAII in C++ only applies to local objects, not to local pointers/references to heap objects. I suppose you could try to do something similar in D, but only for dof'ed instances. This doesn't mean it has to come from the stack -- SmallEiffel knows the difference between objects and references to objects, but all of them come from the heap. It's just that objects can't ever be attached to anything except the particular instance that was created for them at scope entry. Or you could do what was suggested in one of the earlier posts, and when an assignment happens to a dof'ed variable, you finalize the previous occupant (after making sure that they haven't done something foolish like "a = a;"). Hoping that I'm not being too annoying, MacYes, there are complications with 'counted' classes. But realistically,eithercompiler writers or programmers are going to experience similarcomplicationswith 'auto' classes (and worse problems with 'auto' instances). If theproblemsare roughly the same, I would vote for the more flexible and completesolution.Of course, I am somewhat biased on the issue...No, I believe the 'auto' approach has an order of magnitude less implementation effort than ref counting. For example, it won't be necessary to handle arrays of counted objects, counted objects as members of structs, counted objects as members of non-counted objects, assignment overloading, etc.
Aug 26 2002
Part of the problem (that I see) is that classes may need to be dof if one of their members is. If your class holds a reference to a File class (that is dof), then really your class that holds the reference should be dof as well. That's not too hard, I suppose. But what if you are using templates? instance Container(File) fileContainer; Now, the container needs to be dof as well...but that probably isn't already declared in the container class's implementation. I'm not saying that these things aren't solvable...but they need to be considered. Russ
Aug 26 2002
"Mac Reiter" <Mac_member pathlink.com> wrote in message news:ake227$2go$1 digitaldaemon.com...muchMaking it a property of the class, rather than the instance, leads tonormalimplementation grief. For example, pulling on that thread a bit <g>, it seems to lead to needing to implement two versions of each class - one counted, one not.I cannot offhand think of any classes that would need both a dof'ed andimplementation. Most standard library classes certainly don't need dof behavior. Of the dof'able classes I can consider (Locks, Files, Ports),theyshould always be dof'ed. If I am finished with a Lock, it needs to bereleasednow, or it may deadlock the program. If I am finished with a File orPort, itshould be released now so that other applications can work with it.You would need two versions of, say a File class, if you'd like to store File references inside some other class.If someone really does need both versions of a class, it isn't all that difficult to do: class Foo{} dof class DofFoo : Foo{} (I am going to go slightly off my primary point here because I want tohead offany comments about having to remember which version of the class touse...)This is no better or worse than the instance property approach for thiscase,but for the more common case of a dof'ed-only class, it saves the userhaving toremember the extra keyword each time they use the class. The number of polymorphic C++ designs that have blown up because a member functionssomewherein the class hierarchy left off the "virtual" keyword should be a clearenoughexample of why it would be preferable to make dof a class property ratherthanrequiring a keyword at each instance.Yes, a good point.The quick point is that I personally cannot imagine a class that needsbothdof'ed and normal implementations, but even if such a class arises it canbehandled with inheritance with no more effort cost than the instancepropertyform would force on all dof'ed instances.I can see it happening also with handles to windows resources. Sometimes you deal with it completely in function scope, other times you attach it as a member to some other gc'd class.I think this comment is suggesting that dof'ing is an exception, so it'sOK torequire a keyword at each instance.Yes.While a dof'ed instance may be an exception compared to the broader scope of programming (see below for my doubts),forclasses that need dof the dof'ed instance is definitely the rule ratherthan theexception. Consider the all-too-common Lock. Lock would be dof'ed atleast99.9% of the time. Any non-dof usage of Lock would almost certainly bebetterhandled by performing the lock/unlock function on the underlying Mutex/Semaphore/CriticalSection, rather than bundling it up in a uselessLock.Lock's very existence is to provide dof services. Lock doesn't even needtohave any member functions -- its constructor locks the sync object, anditsdestructor/finalizer unlocks it. It has no other user interface. If such services can be disabled by forgetting to add a keyword, then they mightas wellnot exist.99% of the classes I use do not hold resources other than memory. These do not need to be dof'd in a gc environment - but in C++ they all would need carefully crafted destructors.Slightly off topic, since I know that you recognize the importance of dof (otherwise you would not have offered up an implementation, right?).Yes.The statement that the use of dof is the exceptional case bothers me. Isuspectthat that is not the case. How many people have stayed away from Java,D specifically because of the lack of dof?I have no idea. I have it heard as a common complaint.Once a programmer becomes familiar with RAII-style programming, relying on some form of dof, it can veryquicklypermeate designs. This is not simply syntactic sugar, but is afundamentaldesign practice that helps make the resulting implementation stabler, more correct, and more robust. A programmer that is used to RAII would neverevenconsider attempting to make a multithreaded program without RAII. Irealizethat D's synchronized keyword and inherent multithreading simplify thisprocess,but there are always other resources that are commonly used, and misused,thatcan benefit from dof/RAII behaviors.Yes, but D already handles memory and synchronization, leaving the resource issue for a relatively small percentage of classes.pass,At least in D the resource would eventually get cleaned up on the GCtowhereas in C++ it is a memory leak that will never get cleaned up.It would eventually get cleaned up as long as some thread remained activepump the GC.The GC is also called on program exit specifically to run all remaining finalizers.Back to Locks and threads: if I do not write a separate thread whose sole job is to run this code: while (!done) { gc.Collect(); } then it is possible to get in a state where all threads are locked on aLockinstance that has been lost.Yes, but that would happen only if you "leaked" reference to the Lock outside of the auto instance.This is why I suggested that 'counted' classes not be allowed toparticipate inpolymorphic actions (conversion to Object, in your example).But then you cannot take advantage of things like Object.print.I certainly don't want everything in D to be refcounted. I have mentioned several timesthatrefcounting adds a very noticeable performance penalty, and thus should be limited only to those things that need it.Ok.I also agree that "Ignoring the possibility of bugs" is never a wise choice of action. That is why I wentfordisabling type conversions for counted classes. I actually went furtherthanyour 3), because I suggested disabling _any_ conversion, up or down, toanylevel of the class hierarchy. The compiler simply disallows casting acountedclass, implicitly or explicitly, to anything else. Maybe someday, whenmoreexperience is gained, some method of safely handling conversions may befound.But I don't think a moratorium on 'counted' conversions would cause any problems. Let me explain why: (I will continue to use thread synchronization primitives and the Lockclass,because it is my primary experience with the RAII idiom that does not workjustas well with GC) Say you have some system that needs to be able to manage a collection ofLocks,some of which will lock Mutexes, others lock Semaphores, etc. You mightthinkthat you need polymorphism here so that you can treat all the differenttypes ofLocks as the same type. But that is a flawed design. There is only _one_Locktype. What is changing is not the type of lock, but the type of objectbeinglocked. Lock has a private data member, and that member will be apolymorphicbase class pointer/reference to the base class of all of thesynchronizationobjects: class SyncObject{} class Mutex : SyncObject{} class Semaphore : SyncObject{} counted class Lock { SyncObject* lockableObject; } Lock[] MyLocks; bool HandleLock(Lock TheLock); Note that Lock does not derive from anything, and nothing derives fromLock, andyet you can still maintain a collection of Locks that are each internally polymorphizing SyncObjects. You don't need any implicit or explicit conversions, so the 'counted' on Lock doesn't cause any problems. I already talked about the "requires creation of two versions of mostthings inthe library, one to handle counted and one for non-counted" issue above,and whyI don't think it is an issue.I see your point, but the D design relies on the existence of Object's member functions. If the object cannot be cast to Object, then those are inaccessible.1. arrays of counted objects Pragmatically, this means that the array is counted.Yes - making for bugs in the implementation and hidden complexity. I speak from experience in trying to get arrays of destructed objects in C++ working right. There are all kinds of issues, such as having an exception thrown halfway through destructing the array, etc.2. counted objects as members of structs I assume this is referring to the lack of destructors for structs, whichwouldmean that there was nowhere to perform the refcount decrement.Yes. It means auto-generating constructors, destructors, and assignment ops for them. I was trying to avoid this C++ messiness in D.3. counted objects as members of non-counted objects Similar to the "Lock isn't polymorphic, it just contains a polymorphicmember"example above, I suspect that it is a bad design to have a counted objectas amember of a non-counted object, whether it is a struct or a normal class.Ithink that the composite class should also be counted. But I also believethatyou shouldn't walk around with pointers to members of objects, so maybeI'm alittle too strict. My simple answer is to disallow it. Compiler error.With that, you wind up with two parallel implementations of classes.4. assignment overloading I think that this is addressed by the "disallow conversions" and "store aflagin the symbol table to know that you need additional prolog/epilog codeforassignment" topics. It would not surprise me, however, to discover that Iamsimply overlooking something.It took years for the people designing C++ and the people implementing it to discover all the cases that got overlooked in making this work right. I am reluctant to start off down that path.Reference counting _will_ eventually be implemented. It's been doneseveraltimes in C++, and C++ already had dof. No matter how hard it is to do inthecompiler, it is even harder to do correctly from source-code-land.Sometimes itis even impossible to do correctly from out here, due to optimizationsthat canbe performed by the compiler, which can result is out-of-order operationthatmakes the classes think that the last reference was removed before another reference was created.I agree it's hard to get right.If I had to pick someone I trust to implement difficult things correctly,Iwould rather trust you (Walter) than someone who decides to provide anadd-onlibrary that "does reference counting, mostly, as long as you don't everdo<list of not entirely uncommon things>". Yes, it does add to thecomplexity ofthe compiler. But I suspect that once you did it you would find some simplifications and tricks that made it considerably easier.The nice thing about the auto method is it is easy to explain, so the problems with misuse are more obvious. I never liked the hidden magic going on in C++ to try and make these things work right, I find code much easier to understand if the machinations are more out in the open. I understand that many programmers find the opposite more appealing <g>.Having rambled on for so long, I will close with this. I would _really_preferthe dof mechanism to be reference counting, but if scoping is all anyoneelseneeds, then that is still almost infinitely better than no dof at all.Most dofusage will be fine with scoping.I suspected that was true. If by using a much simpler mechanism most all cases can be covered, and there are workarounds for the remainder, I think that is eminently pragmatic.The problem of "losing" instances when their controlling reference switches to a new instance (A1 and A2 example) is alittledisturbing, but probably not common in practice. C++ avoids it byremoving thereference indirection -- RAII in C++ only applies to local objects, not tolocalpointers/references to heap objects. I suppose you could try to dosomethingsimilar in D, but only for dof'ed instances. This doesn't mean it has tocomefrom the stack -- SmallEiffel knows the difference between objects and references to objects, but all of them come from the heap. It's just that objects can't ever be attached to anything except the particular instancethatwas created for them at scope entry. Or you could do what was suggestedin oneof the earlier posts, and when an assignment happens to a dof'ed variable,youfinalize the previous occupant (after making sure that they haven't done something foolish like "a = a;").I am trying to avoid complicated rules - thinking it is better to have a simple rule with a few caveats than a complex rule that few will really understand.Hoping that I'm not being too annoying,Not at all. I value your thoughts on this.
Aug 26 2002
"Walter" <walter digitalmars.com> wrote in message news:akecsk$e6a$1 digitaldaemon.com..."Mac Reiter" <Mac_member pathlink.com> wrote in message news:ake227$2go$1 digitaldaemon.com...I don't know what you're talking about. A file reference in a non-dof class would just get its refcount decremented when the containing class *is* finalized. Before then, it's not "done" with the file.muchMaking it a property of the class, rather than the instance, leads tonormalimplementation grief. For example, pulling on that thread a bit <g>, it seems to lead to needing to implement two versions of each class - one counted, one not.I cannot offhand think of any classes that would need both a dof'ed andimplementation. Most standard library classes certainly don't need dof behavior. Of the dof'able classes I can consider (Locks, Files, Ports),theyshould always be dof'ed. If I am finished with a Lock, it needs to bereleasednow, or it may deadlock the program. If I am finished with a File orPort, itshould be released now so that other applications can work with it.You would need two versions of, say a File class, if you'd like to store File references inside some other class.canThe quick point is that I personally cannot imagine a class that needsbothdof'ed and normal implementations, but even if such a class arises itbeyouhandled with inheritance with no more effort cost than the instancepropertyform would force on all dof'ed instances.I can see it happening also with handles to windows resources. Sometimesdeal with it completely in function scope, other times you attach it as a member to some other gc'd class.If it's dealt with entirely in function scope, the compiler can potentially figure out that it can optimize the ref counting completely away. This would be a Very Good Thing. If stored in a member, I still don't see the big problem. I would not have a class inherit refcounting semantics just because a member has them. The refcounting semantics are only for references anyway. You wouldn't want to embed the actual class as a member because then the containing object would always have an implicit ref on it and it could never be freed until the containing class is freed, at which point the memory it lives in is freed and it can't exist anymore so all remaining references are invalid. So embedding an actual refcounted object in a class would be a no-no. Embedding a ref to one would be what you'd want to do.99% of the classes I use do not hold resources other than memory. These do not need to be dof'd in a gc environment - but in C++ they all would need carefully crafted destructors.You write compilers, not servers, not games, not web browsers, not military software.Yes, but D already handles memory and synchronization, leaving theresourceissue for a relatively small percentage of classes.Resources are a very important fundamental concept. Just because you have 2 common instances handled doesn't mean you have the entire spectrum handled. You speak as though resources such as threads, files, window handles, etc are all trivial. Resource leaks are very real problems.ops2. counted objects as members of structs I assume this is referring to the lack of destructors for structs, whichwouldmean that there was nowhere to perform the refcount decrement.Yes. It means auto-generating constructors, destructors, and assignmentfor them. I was trying to avoid this C++ messiness in D.I don't see it as messiness, I see it as having the compiler do useful work for me automatically. That's a Good Thing.object3. counted objects as members of non-counted objects Similar to the "Lock isn't polymorphic, it just contains a polymorphicmember"example above, I suspect that it is a bad design to have a countedas aclass.member of a non-counted object, whether it is a struct or a normalIbelievethink that the composite class should also be counted. But I alsothatJust disallow addresses of members in general. You can always pass the address of a temporary and use assignment. Wouldn't it simplify the GC as well?you shouldn't walk around with pointers to members of objects, so maybeI'm alittle too strict. My simple answer is to disallow it. Compiler error.With that, you wind up with two parallel implementations of classes.The nice thing about the auto method is it is easy to explain, so the problems with misuse are more obvious. I never liked the hidden magicgoingon in C++ to try and make these things work right, I find code much easier to understand if the machinations are more out in the open. I understand that many programmers find the opposite more appealing <g>.My ears are burning. :)I am trying to avoid complicated rules - thinking it is better to have a simple rule with a few caveats than a complex rule that few will really understand.That sounds like a rule that should trump most other rules. Simpler is almost universally better. Sean
Aug 27 2002
On Mon=2C 26 Aug 2002 20=3A11=3A51 +0000 =28UTC=29 Mac Reiter =3CMac=5Fmember=40pathlink=2Ecom=3E wrote=3A =3E your 3=29=2C because I suggested disabling =5Fany=5F conversion=2C up or down=2C to any =3E level of the class hierarchy=2E The compiler simply disallows casting a counted =3E class=2C implicitly or explicitly=2C to anything else=2E Maybe someday=2C when more =3E experience is gained=2C some method of safely handling conversions may be found=2E I have to disagree here=2E Clearly=2C File should be a counted class=2E On the other hand=2C it derives from Stream =28which is not counted=29=2E Currently=2C you can write code like this=3A =09uint crc32=28Stream s=29 { =2E=2E=2E } =09File f =3D new File=28=22foo=2Ebar=22=29=3B =09crc =3D crc32=28f=29=3B If casting is forbidden=2C you couldn't treat File as if it was Stream - which is the main feature of the current streams implementation=2E
Aug 27 2002
Just poking my head into this thread to mention that if you think having people maintain pointers to internal class data is a problem for reference counting, simply disallow taking the address of data members of reference counted classes or at very least prevent storing them anywhere but a local variable inside a member function of the class. I'd just completely disallow it, myself. There are workarounds to avoid the need for taking addresses. Sean
Aug 27 2002
"Walter" <walter digitalmars.com> wrote in news:akba6n$28tb$1 digitaldaemon.com:Resource Aquisition Is Initialization (RAII)I think this is a very pragmatic solution to a hard problem. I only have two suggestions. 1. Call it auto. 2. I think auto Foo a = new Foo(); is how this will be used 99% of the time. Why not get rid of the explict initialization and not allow reassignment. So: auto Foo a; // same as a = new Foo(); a = new Foo(); // error
Aug 26 2002
Patrick Down wrote:"Walter" <walter digitalmars.com> wrote in news:akba6n$28tb$1 digitaldaemon.com:I seem to remember that "auto" had some meaning back in the early C days. I wonder if it isn't a bad choice. Maybe, going off of Patrick's point 2 here, we could use the keyword "stack": stack Foo a; Which might make it clear that it is a stack variable, not an ordinary reference. I like Patrick's idea that you wouldn't need to "new" a copy.Resource Aquisition Is Initialization (RAII)I think this is a very pragmatic solution to a hard problem. I only have two suggestions. 1. Call it auto. 2. I think auto Foo a = new Foo(); is how this will be used 99% of the time. Why not get rid of the explict initialization and not allow reassignment. So: auto Foo a; // same as a = new Foo(); a = new Foo(); // error
Aug 26 2002
On Mon=2C 26 Aug 2002 11=3A39=3A00 -0700 Russell Lewis =3Cspamhole-2001-07-16=40deming-os=2Eorg=3E wrote=3A =3E I seem to remember that =22auto=22 had some meaning back in the early C It is in ANSI C=2FC++ standard and means local non-static variable=2E Since variables are non-static by default=2C it's never used=2C but still it is there =28and for that reason I proposed it=29=2E =3E days=2E I wonder if it isn't a bad choice=2E Maybe=2C going off of Patrick's =3E point 2 here=2C we could use the keyword =22stack=22=3A =3E =3E stack Foo a=3B I also like =22counted=22=2C since the object is not actually on stack - it can outlive the function in which it was created if you pass it outside =28due to refcounting=29=2E Maybe =22counted=22 is a better idea then=3F Still I like =22auto=22=2E=2E=2E =3D=29 =3E Which might make it clear that it is a stack variable=2C not an ordinary =3E reference=2E I like Patrick's idea that you wouldn't need to =22new=22 a copy=2E Alternatively=2C it could new it by defaullt=2C and where you don't want it=2C you can initialize it to null=3A =09auto File a=3B=09=09=2F=2F default =3D new File=28=29=3B =09auto File b =3D null=3B=09=2F=2F no object created=2E
Aug 26 2002
Yeah, that might be a good approach. "Pavel Minayev" <evilone omen.ru> wrote in message news:CFN374949701187963 news.digitalmars.com... Alternatively, it could new it by defaullt, and where you don't want it, you can initialize it to null: auto File a; // default = new File(); auto File b = null; // no object created.
Aug 26 2002
"Patrick Down" <pat codemoon.com> wrote in message news:Xns927689D889E24patcodemooncom 63.105.9.61..."Walter" <walter digitalmars.com> wrote in news:akba6n$28tb$1 digitaldaemon.com:Ok, ok!Resource Aquisition Is Initialization (RAII)I think this is a very pragmatic solution to a hard problem. I only have two suggestions. 1. Call it auto.2. I think auto Foo a = new Foo(); is how this will be used 99% of the time. Why not get rid of the explict initialization and not allow reassignment. So: auto Foo a; // same as a = new Foo();That would preclude initialization via out parameter: void func(out A a); void test() { auto A a; foo(a); }a = new Foo(); // errorThis may be a very good idea, but I don't want to close the door on reassigning it just yet.
Aug 26 2002
"Walter" <walter digitalmars.com> wrote in news:ake6ln$79r$2 digitaldaemon.com:True. I was trying to sneek stack based storage in somehow.auto Foo a; // same as a = new Foo();That would preclude initialization via out parameter:
Aug 26 2002
You probably should be able to declare certain members of a class to be "auto" as well, so that they are dof'ed whenever the class goes away. Otherwise, the programmer has to code an explicit 'delete' in a destructor.
Aug 26 2002
"Russell Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3D6A8F2A.40902 deming-os.org...You probably should be able to declare certain members of a class to be "auto" as well, so that they are dof'ed whenever the class goes away. Otherwise, the programmer has to code an explicit 'delete' in adestructor. That adds some significant complexity to the compiler (I know, I did it for C++!), so I'd like to defer that for some future variant of the language.
Aug 27 2002
Walter wrote:"Russell Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3D6A8F2A.40902 deming-os.org...Details? I've learned to trust it when you say "too complex"...but I'm curious what happens... -- 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))) ]You probably should be able to declare certain members of a class to be "auto" as well, so that they are dof'ed whenever the class goes away. Otherwise, the programmer has to code an explicit 'delete' in adestructor. That adds some significant complexity to the compiler (I know, I did it for C++!), so I'd like to defer that for some future variant of the language.
Aug 28 2002
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3D6D1A90.910A1A30 deming-os.org...Walter wrote:be"Russell Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3D6A8F2A.40902 deming-os.org...You probably should be able to declare certain members of a class tofor"auto" as well, so that they are dof'ed whenever the class goes away. Otherwise, the programmer has to code an explicit 'delete' in adestructor. That adds some significant complexity to the compiler (I know, I did itlanguage.C++!), so I'd like to defer that for some future variant of theDetails? I've learned to trust it when you say "too complex"...but I'mcuriouswhat happens...You have to add the member destructor code into existing destructors, and create destructors where there aren't any.
Aug 28 2002