Page 1 of 1
Asynchronous callbacks
Posted: Wed Feb 15, 2023 12:33 pm
by Oso
I've noticed the widespread use of new programming terms since coming to PureBasic, but not necessarily new techniques. Many appear to be concepts that were in use since the very dawn of programming, but with new names for what was an established technique — often names that aren't even meaningful and don't properly describe the concept.
Callbacks is one of those. Another new term,
code smells, on the other hand, is reasonably descriptive.
Nevertheless, I'm curious about the concept of asynchronous callbacks. The below might suggest it would commence inside a thread, but thought I'd seek others' ideas on how you interpret this term.
"This execution may be immediate as in a synchronous callback, or it might happen at a later point in time as in an asynchronous callback. Programming languages support callbacks in different ways, often implementing them with subroutines, lambda expressions, blocks, or function pointers. " -
https://en.wikipedia.org/wiki/Callback_ ... ogramming)
Re: Asynchronous callbacks
Posted: Wed Feb 15, 2023 2:19 pm
by NicTheQuick
Oso wrote: Wed Feb 15, 2023 12:33 pmNevertheless, I'm curious about the concept of asynchronous callbacks. The below might suggest it would commence inside a thread, but thought I'd seek others' ideas on how you interpret this term.
You are right. Asynchronous callbacks were usually called from a thread. Otherwise they could not be asynchronous. On the other side there are also synchronous callbacks which can only be called if you have some kind of main loop and an event handler which consists of some mechanisms to call that given callback. That is the case for example with (Wait)WIndowEvent().
Re: Asynchronous callbacks
Posted: Wed Feb 15, 2023 3:31 pm
by mk-soft
An example synchon callback is EnumWindows API. This only returns when all queries are finished.
Link:
viewtopic.php?p=577071#p577071 (See windows part)
An example asynchon callback under Linux is the libwebkit2gtk to get the HTML code. See WebKit_GetHtmlCode.
Here it gets complicated. When called, the callback function is passed and the function returns immediately. In the internal thread of the webkit the data is formed. If the data is complete, the passed callback is hooked into the main programme (where the WaitWindowEvent of PB also runs). This means that fetching the HTML code only works if the event loop is also running.
Link:
viewtopic.php?t=78274
It took me a while to figure out that you can't also wait for the data to be called up without the EventLoop running.
Re: Asynchronous callbacks
Posted: Thu Feb 16, 2023 11:15 pm
by Oso
Thanks for these replies NicTheQuick and mk-soft, I think what I can observe from asynchronous callbacks is that it's necessary to deal with the issue of timing — in as far as you're waiting for a process to do its work and you don't know exactly when that's going to complete.
mk-soft wrote: Wed Feb 15, 2023 3:31 pm
An example asynchon callback under Linux is the libwebkit2gtk to get the HTML code. See WebKit_GetHtmlCode.
This is going to have to be something I come back to at some point. I'd love to run your GTK example but just wish that I had the time to set up Ubuntu and PB

My Linux systems are all CentOS and Manjaro.
Re: Asynchronous callbacks
Posted: Thu Feb 16, 2023 11:33 pm
by mk-soft
Oso wrote: Thu Feb 16, 2023 11:15 pm
This is going to have to be something I come back to at some point. I'd love to run your GTK example but just wish that I had the time to set up Ubuntu and PB

My Linux systems are all CentOS and Manjaro.
Link Install PB on Manjaro (Testet with Raspberry Manjaro with packet manager pacman)
Simple Install of Purebasic ... (Part 2)
Must be the same for Manjaro (Intel)
Re: Asynchronous callbacks
Posted: Fri Feb 17, 2023 8:20 pm
by idle
call backs offer versatility they can be used synchronously or asynchronously. They provide a nice way to interleave events. For instance rather than processing and populating and returning a list or an array to a user you can use a callback function so the program only does one parse of the data. Say you're transforming data from a map into a list or array that's the time to consider a callback otherwise you would walk the map to populate the list of results and then the user would parse that list again. So it like N vs 2N plus the allow users to adapt the code.
Re: Asynchronous callbacks
Posted: Sat Feb 18, 2023 9:38 am
by Oso
idle wrote: Fri Feb 17, 2023 8:20 pm
call backs offer versatility they can be used synchronously or asynchronously. They provide a nice way to interleave events. For instance rather than processing and populating and returning a list or an array to a user you can use a callback function so the program only does one parse of the data. Say you're transforming data from a map into a list or array that's the time to consider a callback otherwise you would walk the map to populate the list of results and then the user would parse that list again. So it like N vs 2N plus the allow users to adapt the code.
Thanks for the reply Idle, but I'm a bit unclear about this. Although I've seen some variation in what people describe as a callback, the most consistent description I can find, seems to be this...
A callback is a function passed as an argument to another function.
That's a technique that I'm sure many of us have been using for a long time in various languages, without necessarily referring to it as a callback. What you describe though, seems to me like a thread that's going away to populate an array, rather than where the name of the function is passed as an argument. There's an example at
https://www.w3schools.com/js/js_callback.asp (it's a Javascript page but otherwise an ideal example) which shows the simple case of a calculator routine, in which the name of the function to display the result is passed as an argument to the routine myCalculator, to call at the point just before it finishes. This seems to match the description "A callback is a function passed as an argument to another function".
JavaScript Callbacks
Using a callback, you could call the calculator function (myCalculator) with a callback (myCallback), and let the calculator function run the callback after the calculation is finished — Example :
Code: Select all
function myDisplayer(some) {
document.getElementById("demo").innerHTML = some;
}
function myCalculator(num1, num2, myCallback) {
let sum = num1 + num2;
myCallback(sum);
}
myCalculator(5, 5, myDisplayer);
Re: Asynchronous callbacks
Posted: Sat Feb 18, 2023 3:59 pm
by mk-soft
Example with callback parameter ... (synchron callback)
Code: Select all
;-TOP
#ProgramTitle = "Main Window"
#ProgramVersion = "v1.01.2"
Enumeration Windows
#Main
EndEnumeration
Enumeration MenuBar
#MainMenu
EndEnumeration
Enumeration MenuItems
#MainMenuAbout
#MainMenuExit
EndEnumeration
Enumeration Gadgets
#MainList
#MainButton1
#MainButton2
EndEnumeration
Enumeration StatusBar
#MainStatusBar
EndEnumeration
; ----
Prototype protoDisplayCB(Value)
Procedure myDisplayListCB(Value)
AddGadgetItem(#MainList, -1, "Result = " + Value)
EndProcedure
Procedure myDisplayStatusCB(Value)
StatusBarText(#MainStatusBar, 0, "Result = " + Value)
EndProcedure
Procedure myCalculater(Value1, Value2, *Callback.protoDisplayCB)
Protected result
result = Value1 * Value2
*Callback(result)
EndProcedure
; ----
Procedure UpdateWindow()
Protected dx, dy
dx = WindowWidth(#Main)
dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
; Resize gadgets
ResizeGadget(#MainList, 5, 5, dx - 10, dy - 45)
ResizeGadget(#MainButton1, 10, dy - 35, 120, 30)
ResizeGadget(#MainButton2, dx - 130, dy - 35, 120, 30)
EndProcedure
Procedure Main()
Protected dx, dy, value
#MainStyle = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, 800, 600, #ProgramTitle , #MainStyle)
; Menu
CreateMenu(#MainMenu, WindowID(#Main))
MenuTitle("&File")
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
MenuItem(#PB_Menu_About, "")
CompilerElse
MenuItem(#MainMenuAbout, "About")
CompilerEndIf
; Menu File Items
CompilerIf Not #PB_Compiler_OS = #PB_OS_MacOS
MenuBar()
MenuItem(#MainMenuExit, "E&xit")
CompilerEndIf
; StatusBar
CreateStatusBar(#MainStatusBar, WindowID(#Main))
AddStatusBarField(#PB_Ignore)
; Gadgets
dx = WindowWidth(#Main)
dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
ListViewGadget(#MainList, 5, 5, dx -10, dy - 45)
ButtonGadget(#MainButton1, 10, dy - 35, 120, 30, "Update List")
ButtonGadget(#MainButton2, dx - 130, dy - 35, 120, 30, "Update Status")
; Bind Events
BindEvent(#PB_Event_SizeWindow, @UpdateWindow(), #Main)
; Event Loop
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Select EventWindow()
Case #Main
Break
EndSelect
Case #PB_Event_Menu
Select EventMenu()
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
Case #PB_Menu_About
PostEvent(#PB_Event_Menu, #Main, #MainMenuAbout)
Case #PB_Menu_Preferences
Case #PB_Menu_Quit
PostEvent(#PB_Event_CloseWindow, #Main, #Null)
CompilerEndIf
Case #MainMenuAbout
MessageRequester("About", #ProgramTitle + #LF$ + #ProgramVersion, #PB_MessageRequester_Info)
Case #MainMenuExit
PostEvent(#PB_Event_CloseWindow, #Main, #Null)
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
Case #MainButton1
value + 1
myCalculater(value, 10, @myDisplayListCB())
Case #MainButton2
myCalculater(value, 10, @myDisplayStatusCB())
EndSelect
EndSelect
ForEver
EndIf
EndProcedure : Main()
Re: Asynchronous callbacks
Posted: Sun Feb 19, 2023 12:08 am
by idle
mk-soft wrote: Sat Feb 18, 2023 3:59 pm
Example with callback parameter ... (synchron callback)
Code: Select all
;-TOP
#ProgramTitle = "Main Window"
#ProgramVersion = "v1.01.2"
Enumeration Windows
#Main
EndEnumeration
Enumeration MenuBar
#MainMenu
EndEnumeration
Enumeration MenuItems
#MainMenuAbout
#MainMenuExit
EndEnumeration
Enumeration Gadgets
#MainList
#MainButton1
#MainButton2
EndEnumeration
Enumeration StatusBar
#MainStatusBar
EndEnumeration
; ----
Prototype protoDisplayCB(Value)
Procedure myDisplayListCB(Value)
AddGadgetItem(#MainList, -1, "Result = " + Value)
EndProcedure
Procedure myDisplayStatusCB(Value)
StatusBarText(#MainStatusBar, 0, "Result = " + Value)
EndProcedure
Procedure myCalculater(Value1, Value2, *Callback.protoDisplayCB)
Protected result
result = Value1 * Value2
*Callback(result)
EndProcedure
; ----
Procedure UpdateWindow()
Protected dx, dy
dx = WindowWidth(#Main)
dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
; Resize gadgets
ResizeGadget(#MainList, 5, 5, dx - 10, dy - 45)
ResizeGadget(#MainButton1, 10, dy - 35, 120, 30)
ResizeGadget(#MainButton2, dx - 130, dy - 35, 120, 30)
EndProcedure
Procedure Main()
Protected dx, dy, value
#MainStyle = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, 800, 600, #ProgramTitle , #MainStyle)
; Menu
CreateMenu(#MainMenu, WindowID(#Main))
MenuTitle("&File")
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
MenuItem(#PB_Menu_About, "")
CompilerElse
MenuItem(#MainMenuAbout, "About")
CompilerEndIf
; Menu File Items
CompilerIf Not #PB_Compiler_OS = #PB_OS_MacOS
MenuBar()
MenuItem(#MainMenuExit, "E&xit")
CompilerEndIf
; StatusBar
CreateStatusBar(#MainStatusBar, WindowID(#Main))
AddStatusBarField(#PB_Ignore)
; Gadgets
dx = WindowWidth(#Main)
dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
ListViewGadget(#MainList, 5, 5, dx -10, dy - 45)
ButtonGadget(#MainButton1, 10, dy - 35, 120, 30, "Update List")
ButtonGadget(#MainButton2, dx - 130, dy - 35, 120, 30, "Update Status")
; Bind Events
BindEvent(#PB_Event_SizeWindow, @UpdateWindow(), #Main)
; Event Loop
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Select EventWindow()
Case #Main
Break
EndSelect
Case #PB_Event_Menu
Select EventMenu()
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
Case #PB_Menu_About
PostEvent(#PB_Event_Menu, #Main, #MainMenuAbout)
Case #PB_Menu_Preferences
Case #PB_Menu_Quit
PostEvent(#PB_Event_CloseWindow, #Main, #Null)
CompilerEndIf
Case #MainMenuAbout
MessageRequester("About", #ProgramTitle + #LF$ + #ProgramVersion, #PB_MessageRequester_Info)
Case #MainMenuExit
PostEvent(#PB_Event_CloseWindow, #Main, #Null)
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
Case #MainButton1
value + 1
myCalculater(value, 10, @myDisplayListCB())
Case #MainButton2
myCalculater(value, 10, @myDisplayStatusCB())
EndSelect
EndSelect
ForEver
EndIf
EndProcedure : Main()
Good example
Re: Asynchronous callbacks
Posted: Sun Feb 19, 2023 12:46 pm
by Oso
idle wrote: Sun Feb 19, 2023 12:08 am
mk-soft wrote: Sat Feb 18, 2023 3:59 pm
Example with callback parameter ... (synchron callback)
Good example
Thanks for the replies again mk-soft and idle, I'm just about to scrutinise this example to try to get a better understanding, so just sending a quick note mk-soft to let you know your efforts were not sent in vain

Re: Asynchronous callbacks
Posted: Sun Feb 19, 2023 2:52 pm
by Oso
mk-soft wrote: Sat Feb 18, 2023 3:59 pm
Example with callback parameter ... (synchron callback)
I looked at the code and tried it, thanks again for sending this. I see that this line...
Code: Select all
myCalculater(value, 10, @myDisplayListCB())
... is passing @myDisplayListCB as the procedure to call within myCalculater :
Code: Select all
Procedure myCalculater(Value1, Value2, *Callback.protoDisplayCB)
...which myCalculater then calls with this...
The question I have is whether we need to use a Prototype? To be honest, I'd deliberately left out Prototypes from my PB learning up to now and focus on the essentials, noting the below...
Prototypes — Description
For advanced programmers. Prototype allows to declare a type which will map a function
Do we have no choice but to use this in the callback?
The other thing I just want to check also, is whether in PB, the definition of callback is the same as is referred to in general, in other words
"A callback is a function passed as an argument to another function".
I assume the following would not be considered a callback, because OutputResult() — the procedure to call — is not passed as an argument...
Code: Select all
EnableExplicit
Procedure OutputResult(displayresult.i)
Debug displayresult.i
EndProcedure
Procedure Calculate(param1.i, param2.i)
Define result.i = param1.i * param2.i
OutputResult(result.i)
EndProcedure
Calculate(2, 4)
Re: Asynchronous callbacks
Posted: Sun Feb 19, 2023 3:17 pm
by mk-soft
I assume the following would not be considered a callback, because the procedure to call is not passed as an argument...
Of course, this is no longer a callback, but only a direct function call.
The question I have is whether we need to use a Prototype? To be honest, I'd deliberately left out Prototypes from my PB learning up to now and focus on the essentials, noting the below...
This is the best method to pass the parameters correctly to the callback.
May I ask how old you are and what you have programmed with before?
Maybe we can get you on the right path.
It looks like you still lack a few basics for programming.
Re: Asynchronous callbacks
Posted: Sun Feb 19, 2023 7:47 pm
by idle
@oso
Yes you should be using prototypes. The prototypes template provide the runtime information for the parameters types.