tag:blogger.com,1999:blog-2428374771421713311.post401782883677096143..comments2024-03-10T12:04:17.661-07:00Comments on The Oracle at Delphi: Stupid Enumerator Tricks - And now for something completely differentAnonymoushttp://www.blogger.com/profile/10119008505905401707noreply@blogger.comBlogger16125tag:blogger.com,1999:blog-2428374771421713311.post-83625683805211786282007-11-12T16:26:12.000-08:002007-11-12T16:26:12.000-08:00Look at my experimental auto object implementation...Look at my experimental auto object implementation....<br>http://cc.codegear.com/item/25108Vivek Nnoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-51424824095045344962007-11-27T01:04:30.000-08:002007-11-27T01:04:30.000-08:00Robert, That wasn't the point of this post. ...Robert,<br><br> That wasn't the point of this post. It was about using the existing facilities that are already present in the language. Besides, who's to say that what you suggest is "right" or "wrong." It is merely different.<br><br>Allen.Allen Bauerhttp://blogs.codegear.com/abauer/noreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-64054247974578306572007-11-12T09:15:18.000-08:002007-11-12T09:15:18.000-08:00The source code is not properly formatted thus it&...The source code is not properly formatted thus it's really hard to understand your examples.Erick Sassehttp://www.ericksasse.com.brnoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-67472012864300295192007-11-12T10:52:49.000-08:002007-11-12T10:52:49.000-08:00Um, can't you do exactly the same thing by cre...Um, can't you do exactly the same thing by creating a reference counted wrapper for your little piece of code?<br><br>The lifetime issue is then taken care of by the compiler generating the code to _Release the interface of the container object, which may also involve a compiler generated try..finally, certainly it seems to be guaranteed behaviour even in the presence of exceptions.<br><br>Certainly I've used reference counted lifetime management to achieve what you seem to be describing for "throw away" utility classes. That is, classes whose instances are routinely called into existence, used and then discarded in the life of a single procedure.<br><br>e.g. a string formatter that accepts params that it then uses to format a list of strings either added individually or from a TStrings, and yields the contents as a single, formatted string (for when "CommaText" just isn't good enough - LOL):<br><br> var<br> f: IStringListFormatter;<br> begin<br> f := StringListFormatter( ... );<br> f.Add( aStringList );<br> Form.Caption := f.Result;<br> end;<br><br>Internally this code instantiates a TStringListFormatter which isautomatically disposed of once 'f' falls out of scope.<br><br>Combining this behaviour with a singleton also yielded a very useful little hourglass cursor manager:<br><br> begin<br> HourglassOn;<br> :<br> // lengthy operation that may even call procedures that<br> // in turn call HourGlassOn... that's OK, reference counting<br> // takes care of everything<br> end;<br><br><br>HourglassOn calls a function which instantiates a singleton object (if it does not already exist) and returns a reference to it. When that reference falls out of scope, it is _Release()ed. When ALL references have been _Release()ed, the singleton gets destroyed, so that the next call to HourglassOn() will create a new one.<br><br>The singleton sets Screen.Cursor = crHourglass when created and to crDefault when destroyed (I know, it could be cleverer than that but it suited my needs).<br><br>GUI methods that wish to turn on the hourglass simply call "HourGlassOn". It will get turned off again when that method returns, whether normally or by raising (or not handling) an exception.Jolyon Smithhttp://www.deltics.co.nznoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-83950781987530090322007-11-12T13:08:04.000-08:002007-11-12T13:08:04.000-08:00Kinda cute idea, but the code is lying. You're...Kinda cute idea, but the code is lying. You're not enumerating. Big-time code smell.<br><br>Why not just add something like C#'s "using" block, so you're not lying at all? Just make it so that for..in *isn't* the only construct where the compiler will memory-manage a class.<br><br>using RTask := TReplicableTask.Create(@ExecuteEvent)do<br> RTask.Wait;<br><br>Actually, better yet in this case would be to add a static method, and hide the try..finally inside it:<br><br>TReplicableTask.Execute(@ExecuteEvent);Joe Whitehttp://www.excastle.com/blog/noreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-76780836431288444562007-11-12T13:48:23.000-08:002007-11-12T13:48:23.000-08:00Just give us garbage collection in win32. Problem...Just give us garbage collection in win32. Problem solved.<br><br>SeanSean Crosshttp://www.sourceitsoftware.comnoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-209393539730330432007-11-12T18:04:35.000-08:002007-11-12T18:04:35.000-08:00Apart from the obvious ommisions/errors in the dec...Apart from the obvious ommisions/errors in the declarations of TTaskDestructor and TObjectDestructor, wouldn't class helpers fit perfectly into this solution?!?<br>You could make a helper that adds GetEnumerator/GetCurrent/MoveNext to TReplicableTask, so no extra instance is needed.<br>Or are class-helpers incompatible with the for-in construct?Patrick van Logchemhttp://www.every-angle.comnoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-4145765012078476822007-11-12T21:23:17.000-08:002007-11-12T21:23:17.000-08:00Nice trick but the code reads really funny.I'm...Nice trick but the code reads really funny.<br><br>I'm usually abusing Delphi's ability to auto-destroy interfaces to automatically destroy objects. In your case, it could be something like this:<br><br>with AutoDestroy(TReplicableTask.Create(@ExecuteEvent)).Task do<br> Wait;<br><br>or <br><br>AutoDetroy(TReplicableTask.Create(@ExecuteEvent)).Task.Wait;<br><br>Where AutoDestroy is defined along those lines (untested):<br><br>type<br> IAutoDestroyWrapper = interface<br> function GetTask: TReplicableTask;<br> property Task: TReplicableTask read GetTask;<br> end;<br><br> TAutoDestroyWrapper = class(TInterfacedObject, IAutoDestroyWrapper)<br> FOwnedTask: TReplicableTask;<br> constructor Create(task: TReplicableTask);<br> destructor Destroy; <br> function GetTask: TReplicableTask;<br> end;<br><br>function AutoDestroy(task: TReplicableTask): IAutoDestroyWrapper;<br>begin<br> Result := TAutoDestroyWrapper.Create(task);<br>end;<br><br>constructor TAutoDestroyWrapper.Create(task: TReplicableTask);<br>begin<br> inherited Create;<br> FOwnedTask := task;<br>end;<br><br>destructor TAutoDestroyWrapper.Destroy;<br>begin<br> FOwnedTask.Free;<br> inherited;<br>end;<br><br>function TAutoDestroyWrapper.GetTask: TReplicableTask;<br>begin<br> Result := FOwnedTask;<br>end;<br><br>--<br>Primozgabrhttp://17slon.com/blogs/gabr/blogger.htmlnoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-34076827761877488332007-11-12T22:37:09.000-08:002007-11-12T22:37:09.000-08:00I agree with Joe White. Nice trick, but I would pr...I agree with Joe White. Nice trick, but I would prefer something that is explicit instead of making the code lie.Fabriciohttp://nonenoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-10965906519369962492007-11-13T00:28:21.000-08:002007-11-13T00:28:21.000-08:00Jolyon, I've used that trick several times in...Jolyon,<br><br> I've used that trick several times in the past as well. The difference here is that the enumerator is freed immediately upon exit from the "for" loop rather than upon exit of the whole procedure. Sometimes you need the instance to be freed immediately.<br><br>Allen.Allen Bauerhttp://blogs.codegear.com/abauer/noreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-51497288351359883582007-11-13T00:39:06.000-08:002007-11-13T00:39:06.000-08:00Joe, I never said it was something I'd actual...Joe,<br><br> I never said it was something I'd actually recommend doing.. it was just some kooky idea I thought up. I was really looking for an excuse to show the last experimental implementation :-)<br><br>Allen.Allen Bauerhttp://blogs.codegear.com/abauer/noreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-56150303107240766682007-11-13T00:54:03.000-08:002007-11-13T00:54:03.000-08:00Sean, You're jumping ahead. Need to stay wit...Sean,<br><br> You're jumping ahead. Need to stay with the class... ;-)...<br><br>Allen.Allen Bauerhttp://blogs.codegear.com/abauer/noreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-64241810738398744842007-11-13T00:55:54.000-08:002007-11-13T00:55:54.000-08:00Erick, Take another look. I think I fixed all of...Erick,<br><br> Take another look. I think I fixed all of the formatting errors. Even Windows Live Writer has issues with properly formatting code.<br><br>Allen.Allen Bauerhttp://blogs.codegear.com/abauer/noreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-83089395500470797972007-11-13T07:50:40.000-08:002007-11-13T07:50:40.000-08:00Allen: "Sometimes you need the instance to b...Allen:<br><br> "Sometimes you need the instance to be freed immediately"<br><br>Then use an explicit try..finally (or a hypothetical "using..") construct. Since the lifetime management is compiler defined, it is also subject to compiler changes.<br><br>The same applies of course to ref counted interfaces, but I thought the point of your example was that ensuring that the instance will _certainly_ be cleaned up (and making it less cumbersome to do so) is more important than knowing strictly _when_ it will get cleaned up.<br><br>If you "need" to know exactly when an instance will be/has been freed, free it yourself at the appropriate time.<br><br>Anything else is a convenient side effect that might just turn bite you in the future.Jolyon Smithhttp://www.deltics.co.nznoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-75576644620632245042007-11-14T18:20:03.000-08:002007-11-14T18:20:03.000-08:00Hi Allen,Second post, not quite related to lambdas...Hi Allen,<br><br>Second post, not quite related to lambdas but more related to "auto destroying" things.<br>We have some problems with the WITH construction: when we have an anonymous (!) object created there then, if the programmer doesn't pay attention, then that object is leaked, when, in fact it's obvious that its scope is only in the 'with' block. Think which can be clearly detected by the compiler (or it should). So, imho, it's much safer to inject an "auto-destroy" code if we have an anonymous object creation, something like:<br><br>User input:<br><br><br>With TStringList.Create do<br>Begin<br>//bunch of useful code<br>End;<br><br><br>Compiled code:<br><br><br>With TStringList.Create do<br>Begin<br>//the same bunch of useful code<br>.Free; //in a 'try' block perhaps?<br>End;<br><br><br>…this will apply also when we'll have (in Tiburon, of course :-) ) inline variables, ie. something like 'with tmp:=TStringList.Create do' (QC #679 - #9 Voted in QC!) and 'for i: integer=1 to 10 do' (QC #49588)<br><br>Just my 2cm. Th.noreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-28281134840988855342007-11-26T07:23:55.000-08:002007-11-26T07:23:55.000-08:00Why not do it like in .Net?And when adding a new f...Why not do it like in .Net?<br>And when adding a new feature, do it right, enforce an alias!<br><br>using sl := TStringList.Create() do<br>begin<br> sl.Add('abc');<br> sl....<br>end;<br><br>This gives reduced scope and autom. destruction. :-)Robertnoreply@blogger.com