{{fbdoc item="title" value="SUB Pointer"}}----
Data type that stores a pointer to a ##[[KeyPgSub|SUB]]## procedure

{{fbdoc item="syntax"}}##
	[[KeyPgDim|dim]] //variable// [[KeyPgAs|as]] [[KeyPgSub|Sub]] [[[KeyPgCdecl|CDecl]]|[[KeyPgPascal|Pascal]]|[[KeyPgStdcall|StdCall]]] [( [//parameter_list//] )] [= //initializer//]
##
{{fbdoc item="param"}}
		##//parameter_list//##: parameter[, parameter[, ...]]
		##//parameter//##: ##[[[KeyPgByref|ByRef]]|[[KeyPgByval|ByVal]]] //identifier// [[[KeyPgAs|As]] //type//] [= //default_value//]##
			##//identifier//##: the name of the variable referenced in the subroutine
			##//type//##: the type of variable
			##//default_value//##: the value of the argument if none is specified in the call
		##//intializer//##: address of a subroutine to set as the intial value

{{fbdoc item="desc"}}
	A ##[[KeyPgSub|Sub]]## pointer is a procedure pointer that stores the memory location of compiled code.  If no intializer is given the default initial value is zero (0).
	
	The memory address for the ##[[KeyPgSub|Sub]]## procedure can be assigned to the variable by taking the address of a subroutine with ##[[KeyPgOpProcptr|ProcPtr]]## or ##[[KeyPgOpAt|Operator @ (Address of)]]##.
	
	The procedure must match the same ##[[KeyPgSub|Sub]]## declaration as the declared ##[[KeyPgSub|Sub]]## pointer.
	
	To call the subroutine assigned, use the ##//variable//## name as if it were a normal declared ##[[KeyPgSub|Sub]]##.
	
	One of the primary uses for ##[[KeyPgSub|Sub]]## pointers is to create callback procedures:
		**""-""** A callback ##[[KeyPgSub|Sub]]## is a ##[[KeyPgSub|Sub]]## that is passed through an argument (a ##[[KeyPgSub|Sub]]## pointer) to another procedure which is expected to call back (execute) the "argument" at a convenient time.
		**""-""** If the callback ##[[KeyPgSub|Sub]]## is completely executed before the invocation returns to the caller code, then the callback process is said to be "synchronous".
		**""-""** If the invocation immediately returns to the caller code, and the callback ##[[KeyPgSub|Sub]]## and the caller's next code are running in parallel, then the callback process is said to be "asynchronous".

{{fbdoc item="ex"}}
{{fbdoc item="filename" value="examples/manual/datatype/subptr.bas"}}%%(freebasic)
	sub Hello()
		print "Hello"
	end sub

	sub Goodbye()
		print "Goodbye"
	end sub

	dim x as Sub() = procptr( Hello )

	x()

	x = @Goodbye  '' or procptr(Goodbye)

	x()
%%
{{fbdoc item="filename" value="examples/manual/datatype/subptr2.bas"}}%%(freebasic)
Sub s0 ()
  Print "'s0 ()'"
End Sub

Sub s1 (Byval I As Integer)
  Print "'s1 (Byval As Integer)'", I
End Sub

Sub s2 (Byref S As String, Byval D As Double)
  Print "'s2 (Byref As String, Byval As Double)'", S, D
End Sub

Dim s0_ptr As Sub () = @s0
Dim s1_ptr As Sub (Byval I As Integer) = @s1
Dim s2_ptr As Sub (Byref S As String, Byval D As Double) = @s2

s0_ptr()
s1_ptr(3)
s2_ptr("PI", 3.14)
%%
{{fbdoc item="filename" value="examples/manual/datatype/subptr3.bas"}}%%(freebasic)
' Example of advanced callback Sub mechanism (asynchronous) to implement a key pressed event:
' (the user callback Sub address can be modified while the event thread is running)
'   - An asynchronous thread tests the keyboard in a loop, and calls a user callback Sub each time a key is pressed.
'   - An UDT groups the common variables used (callback Sub pointer, character of key pressed, thread end flag),
'       and the static thread Sub plus the thread handle.
'   - An UDT instance pointer is passed to the thread, which then transmits it to the callback Sub each time.
'   - The callback Sub prints the character of the key pressed character,
'       but if the key pressed is <escape> it orders the thread to finish.
'   - As the user callback pointer is a member field of the UDT, it can be modified while the thread is running.


'' UDT for thread environment
  Type threadUDT
	Dim As Sub (Byval As ThreadUDT Ptr) callback             '' callback Sub pointer
	Dim As Integer threadEnd                                 '' thread end flag
	Dim As String s                                          '' character of the key pressed
	Declare Static Sub threadInkey (Byval p As Any Ptr)      '' static thread Sub
	Dim As Any Ptr threadHandle                              '' handle to the thread
  End Type

'' thread Sub definition
  Sub threadUDT.threadInkey (Byval p As Any Ptr)
	Dim As threadUDT Ptr pt = p                              '' convert the any ptr to a threadUDT pointer
	Do
	  pt->s = Inkey
	  If pt->s <> "" Andalso pt->callback > 0 Then           '' test condition key pressed & callback Sub defined
		pt->callback(p)
	  End If
	  Sleep 50, 1
	Loop Until pt->threadEnd                                 '' test condition to finish thread
  End Sub

'' user callback Sub definition
  Sub printInkey (Byval pt As threadUDT Ptr)
	If Asc(pt->s) = 27 Then                                  '' test condition key pressed = <escape>
	  pt->threadEnd = -1                                     '' order thread to finish
	  Print
	Else
	  Print pt->s;
	End If
  End Sub

'' user main code
  Dim As ThreadUDT t                                         '' create an instance of threadUDT
  t.threadHandle = Threadcreate(@threadUDT.threadInkey, @t)  '' launch the thread, passing the instance address
  t.callback = @printInkey                                   '' initialize the callback Sub pointer
  Threadwait(t.threadHandle)                                 '' wait for the thread finish
%%

{{fbdoc item="diff"}}
	- New to ""FreeBASIC""

{{fbdoc item="see"}}
	- ##[[KeyPgSub|Sub]]##
	- ##[[KeyPgOpProcptr|ProcPtr]]##
	- ##[[KeyPgOpAt|Operator @ (Address of)]]##

{{fbdoc item="back" value="CatPgStdDataTypes|Standard Data Types"}}
