Callback

Callback procedures

Description
   From Wikipedia: A callback, also known as a "call-after" function, is 
   any executable code that is passed as an argument to other code; that 
   other code is expected to call back (execute) the argument at a given 
   time. This execution may be immediate as in a synchronous (or blocking) 
   callback, or it might happen at a later time as in an asynchronous (or 
   deferred) callback.

Example
   Example where a mathematical function is an argument in plot function 
   call:
   (the invocation is implemented by calling the 'PlotF()' procedure, and 
   the callback function is the 'Linear()', 'Sinusoidal()', or 
   'Quadratic()' function)
   Type MathFunction As Function( ByVal x As Double ) As Double

   Function Linear( ByVal x As Double ) As Double
      Return x
   End Function

   Function Quadratic( ByVal x As Double ) As Double
      Return x * x
   End Function

   Function Sinusoidal( ByVal x As Double ) As Double
      Return Sin(x)
   End Function

   Sub PlotF( ByVal f As MathFunction )
      PSet( -15, f(-15) )
      For x As Double = -15 To 15 Step 0.1
         Line -( x, f(x) )
      Next
   End Sub

   Screen 19
   Window (-15,-10)-(15,10)

   PlotF( @Linear )
   PlotF( @Sinusoidal )
   PlotF( @Quadratic )

   Sleep
         
The three callback processes are synchronous because each callback function 
is completely executed before 'PlotF()' returns to the caller code.

   Similar plotting example (as above) but with a asynchronous callback. 
   Here an artificial delay is added. A more realistic case would be if the 
   data to be plotted is retrieved form a web-server with a response time 
   larger than acceptable for the main loop of our program (prevent 
   blocking behavior):
   #include "fbthread.bi"

   Type MathFunction As Function( ByVal x As Double ) As Double

   Sub ThreadPlot( ByVal p As Any Ptr )
      Sleep 1500, 1  '' sleep added only to check the asynchronous way of the callback
      Dim f As MathFunction = p
      Window (-15,-10)-(15,10)
      PSet( -15, f(-15) )
      For x As Double = -15 To 15 Step 0.1
         Line -( x, f(x) )
      Next
   End Sub

   Function PlotF( ByVal f As MathFunction ) As String
      Print "Plotting requested"
      ThreadDetach( ThreadCreate( @ThreadPlot, f ) )
      Return "Plotting request taken into account"
   End Function

   Function Linear( ByVal x As Double ) As Double
      Return x
   End Function

   Function Quadratic( ByVal x As Double ) As Double
      Return x * x
   End Function

   Function Sinusoidal( ByVal x As Double ) As Double
      Return Sin(x)
   End Function

   Screen 19

   Print PlotF( @Linear )
   Print PlotF( @Sinusoidal )
   Print PlotF( @Quadratic )

   '' following code added only to check the asynchronous way of callbacks
   Print "Main program continues ";
   For I As Integer = 1 To 15
      Print ".";
      Sleep 200, 1
   Next I
   Print
   Print "Main program finished"

   Sleep
         
The three callback processes are asynchronous because the 'PlotF()' 
function returns immediately, and each callback function is executed in 
parallel with the caller's next code, from a 'ThreadPlot()' thread created 
(previously) by 'PlotF()' for each of them.

   Example of a callback function for comparing values in a array to be 
   sorted by the qsort algorithm:
   (the invocation is implemented by calling the 'qsort()' procedure, and 
   the callback function is the 'CmpVarLenStr()' function)
   #include "crt/stdlib.bi"

   Function CmpVarLenStr cdecl( ByVal p1 As Any Ptr, ByVal p2 As Any Ptr ) As Long  '' compare 2 var-len strings
      Dim As String Ptr ps1 = p1
      Dim As String Ptr ps2 = p2
      If *ps1 < *ps2 Then
         Return -1
      ElseIf *ps1 > *ps2 Then
         Return 1
      Else
         Return 0
      End If
   End Function

   Sub PrintList( array() As String)  '' print a var-len string list
      For I As Integer = LBound(array) To UBound(array)
         Print array(I)
      Next I
      Print
   End Sub

   Dim forename(1 To 12) As String = {"Madison", "Emily", "Hailey", "Sarah", "Kaitlyn", "Hannah", _
                              "Jacob", "Christopher", "Nicholas", "Michael", "Matthew", "Joshua" }

   Print "LIST OF UNSORTED FORENAMES:"
   PrintList( forename() )

   qsort( @forename(LBound(forename)), UBound(forename) - LBound(forename) + 1, SizeOf(String), @CmpVarLenStr )

   Print "LIST OF SORTED FORENAMES:"
   PrintList( forename() )

   Sleep
         
The callback process is synchronous because the callback function is 
completely executed (several times), (successively) called by 'qsort()', 
before 'qsort()' returns to the caller code.

See also
   * Sub Pointer
   * Function Pointer
   * Threads
   * OBJECT built-in and RTTI info

