You use delegates when you need to call some code that is not known at compile time. For example you are creating a library with a function that does very heavy calculations and takes a lot of time to complete. Because of that, from time to time you want your library to send back some data (to the app that uses it) about its progress and maybe let the calling app decide if it wants to cancel the operation (random example that comes to mind, a windows update that takes too long time to complete and makes your system crawl and you cannot work, so you are MS and want to give some reliable info back to the user about the progress and allow him to cancel the %^%&#@ update).
This can be nicely done with a delegate. You can define one as:
Code: Select all
DELEGATE LongProcessProgressReportDelegate(oInfo AS ProgressInfo) AS LOGIC
Code: Select all
CLASS ToolInLibrary
EXPORT oProgreesDel AS LongProcessProgressReportDelegate
METHOD HeavyCalculations() AS VOID
// ...
IF MuchTimePassedSoMustReportBack
LOCAL somedata AS ProgressInfo
// ...
somedata:TimeRemaining := 17 years
IF .not. SELF:oProgreesDel:Invoke(somedata)
// cancel operation
ELSE
ENDIF
The calling code, the one which uses your library, would then need to implement a method with that signature (you know what I mean ):
Code: Select all
CLASS TheRealApp
METHOD DoSomeWork() AS VOID
LOCAL oTool AS ToolInLibrary
// ....
oTool:oProgreesDel := ProgressCallbackMethod
oTool:Heavycalculation()
// wait and wait and wait...
RETURN
METHOD ProgressCallbackMethod(oInfo AS ProgressInfo) AS LOGIC
SELF:DisplayProgressInfoToUser(oInfo)
IF UserIsCompletelyAngryWithDelay()
RETURN FALSE
ENDIF
RETURN TRUE
END CLASS
Another way to implement the above scenario, would have been to declare an interface IProgressReport with a method member named ProgressCallbackMethod() and require the calling code to implement this interface, but this is probably overkill, to request such a thing just for a single callback method.
Btw, .Net has brought this concept a step further, by introducing EVENTs, which are basically a warper around delegates, but their mechanism is the same and they require the exact same delegate type. In the sample above, you can replace the line
Code: Select all
EXPORT oProgreesDel AS LongProcessProgressReportDelegate
Code: Select all
EXPORT EVENT ProgreesDel AS LongProcessProgressReportDelegate
Anyway, again this post got a lot larger than planned, hope it clarifies things about delegates a bit, instead of making them look even weirder
Chris