The X# Documentation Project - new topics last week
Posted: Tue Feb 20, 2018 2:30 pm
Hi Karl,
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:
and then simply use (simplified code)
Your library code knows nothing about the actual code that will be actually called at runtime, it only knows (and enforces) that the method that will be called at runtime must and will have those specific parameters and return type that you specified in the delegate.
The calling code, the one which uses your library, would then need to implement a method with that signature (you know what I mean ):
This will work nicely at runtime, your library will be giving updates to the main app in a type safe and fast manner. Instead of invoking a delegate, you could possibly use just Send() to call a method in the calling code, we had that in VO for decades you will say. Yes, but this is not type safe, there is no parameter and return type cheeking at compile time, so you can accidentally easily use wrong params in the ProgressCallbackMethod() callback, which will throw an error at runtime only. With the delegate system, all is checked at compile time and the calls are guaranteed to be made correctly.
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
with
and it is the same thing more or less. So usually you are using delegates with events (like all those events in the Form class, which all use the "EventHandler" DELEGATE), but there are cases where you still need to use a delegate in its simple form, specified in a LOCAL or class var, for example when needing to provide a callback to a Win32 API function. A delegate instantiated and holded in a LOCAL also has the advantage that it can be passed around in your code just like any other variable and instantiated by various places in your code. But admittedly, there are very few cases where you would really need to do that.
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
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