<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-724433477148659254</id><updated>2011-07-07T18:07:18.324-07:00</updated><title type='text'>Delphi Thoughts</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://xdenser.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/724433477148659254/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://xdenser.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>xdenser</name><uri>http://www.blogger.com/profile/17488675591312565990</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>2</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-724433477148659254.post-8732909425863623645</id><published>2010-01-06T09:52:00.000-08:00</published><updated>2010-01-06T10:05:53.522-08:00</updated><title type='text'>Asynchronous  operations using Deferred object</title><content type='html'>In this post I want to describe an idea of using Deferred object in asynchronous programming. The idea is not new. It is used widely in AJAX frameworks. The advantage of using such technique is clear and compact code. The technique would be impossible without anonymous functions in Delphi 2009/2010.&lt;br /&gt;So let's start with code example of using deferred object.&lt;br /&gt;&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: delphi"&gt;&lt;![CDATA[function QueuedAsyncDownload(url:string; deffered:IDeferred = nil):IDeferred;procedure TForm1.Button1Click(Sender: TObject);var Im:TJPEGImage; def:IDeferred;begin def:=QueuedAsyncDownload(Url.Text).  Add(function(Res:TObject):TObject  begin   if(Res is TStream) then    begin      Im:=TJPEGImage.Create;      TStream(Res).Position:=0;      Im.LoadFromStream(TStream(Res));      Image1.Picture.Assign(Im);      Im.Free;      Res.Free;    end;   result := nil;   def:=nil  end).  Err(function (E:Exception):TObject  begin     ShowMessage('Exception '+E.Message);     E.Free;     Result:=nil;     def:=nil;  end);end;]]&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;The code asynchronously downloads image from the Web and places it in TImage control.&lt;br /&gt;In case of exception error handling function called in context of main application thread - from that context asynchronous download operation were initiated.&lt;br /&gt;&lt;br /&gt;The Deferred object is a helper to handle asynchronous operations in common manner.&lt;br /&gt;The object maintains a queue of anonymous functions of 2 kinds. Functions of first kind are called as a result of successful asynchronous operation, second kind are error handlers. &lt;br /&gt;&lt;br /&gt;I think it will be handy to expose Deferred as interface with following declaration.&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: delphi"&gt;&lt;![CDATA[ TDeferredSuccessFunc = reference to function(ARes:TObject):TObject; TDeferredExceptionFunc = reference to function(ERes:Exception):TObject; IDeferred = interface  procedure SetResult(const Value: TObject);  function GetResult:TObject;  function Add(AFunc:TDeferredSuccessFunc):IDeferred;  function Err(AErr:TDeferredExceptionFunc):IDeferred;  property Result:TObject read GetResult write SetResult; end;]]&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;The use scenario of such interface will be:&lt;br /&gt;&lt;br /&gt;1. Give reference to IDeferred to some long running asynchronous operation.&lt;br /&gt;2. Add result and error handlers using Add and Err methods of that IDeferred.&lt;br /&gt;3. After long running asynchronous operation ends just assign result to Result property, or if exception is raised - assign that exception object to Result property. &lt;br /&gt;&lt;br /&gt;So lets go through first listing according to that scenario&lt;br /&gt;&lt;br /&gt;Function QueuedAsyncDownload  downloads url into TStream in separate thread. It takes IDeferred as parameter or creates new one if it is omitted and returns that IDeferred.&lt;br /&gt;After download started result handling function is added to IDeferred using .Add method. &lt;br /&gt;Error handler is added next.&lt;br /&gt;After TStream is received it is just set as result of IDeferred.&lt;br /&gt;And that result is used as parameter to first anonymous success function in IDeferred's queue. If result assigned to IDeferred is Exception object then  success functions are discarded from IDeferred's queue until error handling function is met, and that Exception is used as parameter for that error handler.&lt;br /&gt;Each of functions (success and error) should also return Result object or nil and the IDeferred queue will be processed again according to that result. If nil is returned - that means no result so no function will be called from IDeferred queue.&lt;br /&gt;&lt;br /&gt;Looks like very confusing and too complex design at first glance. And also this is not common way to make things in Delphi. You may ask -  Why not just create TThread descendant and to make all the things there with proper synchronization of course?&lt;br /&gt;But when you have to do several asynchronous operations one after other based on result of previous operation  code appears not so simple and clear.&lt;br /&gt;I'll try to make several examples of such things in my future posts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/724433477148659254-8732909425863623645?l=xdenser.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xdenser.blogspot.com/feeds/8732909425863623645/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://xdenser.blogspot.com/2010/01/asynchronous-operations-using-deferred.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/724433477148659254/posts/default/8732909425863623645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/724433477148659254/posts/default/8732909425863623645'/><link rel='alternate' type='text/html' href='http://xdenser.blogspot.com/2010/01/asynchronous-operations-using-deferred.html' title='Asynchronous  operations using Deferred object'/><author><name>xdenser</name><uri>http://www.blogger.com/profile/17488675591312565990</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-724433477148659254.post-4642305673072892950</id><published>2009-12-01T14:03:00.000-08:00</published><updated>2009-12-02T16:17:05.762-08:00</updated><title type='text'>JavaScript like setTimeout function</title><content type='html'>Delphi standard TTimer component is not handy in some situations - for example, when you need  to run something with delay only one or several times, or when you want to use timer in "non-form" unit. New Delphi 2009/2010 anonymous functions feature allows to create JavaScript like setTimeout function.&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: delphi"&gt;&lt;![CDATA[function setTimeout(proc:TProc;msTimout:Integer):Integer; ]]&gt;&lt;/script&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;TProc&lt;/span&gt; here is anonymous function type declared in &lt;span style="font-style: italic;"&gt;SysUtils&lt;/span&gt; unit.&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: delphi"&gt;&lt;![CDATA[ type   TProc = reference to procedure;]]&gt;&lt;/script&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;setTimeout&lt;/span&gt; returns integer Id of timeout. One may cancel running timeout using &lt;span style="font-style:italic;"&gt;cancelTimeout&lt;/span&gt; function. Everything is like in JavaScript.&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: delphi"&gt;&lt;![CDATA[function cancelTimeout(TimeoutId:Integer):boolean; ]]&gt;&lt;/script&gt;&lt;br /&gt;Now you may setup timeout inplace.&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: delphi"&gt;&lt;![CDATA[setTimeout(procedure    begin      ShowMessage('this is called after 1000 ms');    end,    1000); ]]&gt;&lt;/script&gt;&lt;br /&gt;My realization of &lt;i&gt;setTimeout&lt;/i&gt; function may be downloaded from &lt;a href="http://www.xdenser.com/downloads/xds_timers.pas"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;br /&gt;&lt;blockquote&gt;The "timeouted" procedure is called in main program thread context. &lt;/blockquote&gt;&lt;br /&gt;So code like this:&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: delphi"&gt;&lt;![CDATA[procedure TForm1.Button1Click(Sender: TObject);var   timoutId:Integer;begin  timoutId := setTimeout(procedure   begin    ShowMessage('SomethingLongRunning timout!');   end,   60000  );  for i:=0 to 1 000 0000 do SomethingLongRunning;  cancelTimeout(timoutId);end;]]&gt;&lt;/script&gt;&lt;br /&gt;will not work as wanted and &lt;i&gt;ShowMessage&lt;/i&gt; will be called after exit from procedure &lt;i&gt;TForm1.Button1Click()&lt;/i&gt;, until you make periodic calls to &lt;i&gt;Application.ProcessMessages&lt;/i&gt; from &lt;i&gt;SomethingLongRunning&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/724433477148659254-4642305673072892950?l=xdenser.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xdenser.blogspot.com/feeds/4642305673072892950/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://xdenser.blogspot.com/2009/12/javascript-like-settimeout-function.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/724433477148659254/posts/default/4642305673072892950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/724433477148659254/posts/default/4642305673072892950'/><link rel='alternate' type='text/html' href='http://xdenser.blogspot.com/2009/12/javascript-like-settimeout-function.html' title='JavaScript like setTimeout function'/><author><name>xdenser</name><uri>http://www.blogger.com/profile/17488675591312565990</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
