Extensions system playing

BlitzMax Forums/MiniB3D Module/Extensions system playing

Picklesworth(Posted 2007) [#1]
So I am building a few things into MiniB3D to make it pleasantly extendible / modular. I started fresh with my previously very messy Extensions system today, this time with a different approach.
Instead of going straight at extensions, I am making a little events system first, and only then will I bother looking at portable Extensions. (Of course, the events system is pretty much all we will need).
However, since the TEvent type is stolen by BlitzMax's official modules, this is actually an "Actions" system. Actions fits better anyway since event sounds passive whereas this is quite direct.



It isn't anything impressive (just the tiny beginnings), and pretty useless right now, but here is Actions.bmx:
Rem
Portable Actions System for MiniB3D
(Note: Would be an Events System, but TEvent is taken and it is slightly different anyway)

This system uses an idea of Actions and Responses.
Actions are really containers of any number of Responses, and it is possible to assign variables
to responses so that they can be specifically selected by a specific action's OnAction Callback.

This design means that actions work in a very simple way (merely function pointers), which makes
it easy to build an extensions system using actions.
End Rem

Type TAction
	Field List_Responses:TList=New TList
	Field Callback_Update(Action:TAction)=TAction.Update_Default
	
	Method Update()
		Callback_Update(Self)
	End Method
	
	Method SetUpdateCallback(FunctPtr_CallbackUpdate(Action:TAction))
		Callback_Update=FunctPtr_CallbackUpdate
	End Method
	
	Method AddResponse:TLink(Response:TResponse)
		Local ResponseLink:TLink
		ResponseLink:TLink=List_Responses.AddLast(Response)
		Return ResponseLink
	End Method
	
	Function Update_Default(Action:TAction)
		For Local Response:TResponse = EachIn Action.List_Responses
			Response.Execute()
		Next
	End Function
End Type

Type TResponse
	Field Callback_Response()
	
	Method Execute()
		Callback_Response()
	End Method
	
	Method SetFunction(FunctPtr_Response())
		Callback_Response=FunctPtr_Response
	End Method
	
	Function Create:TResponse(FunctPtr_Response())
		Local NewResponse:TResponse=New TResponse
		NewResponse.SetFunction(FunctPtr_Response)
		Return NewResponse
	End Function
End Type


An example of how I used this (with Klepto2's version):
In TCamera.bmx, at the top, I added
Global Action_TCamera_CreateCamera:TAction=New TAction

Then at the top of the CreateCamera function in that file:
Action_TCamera_CreateCamera.Update()

(All that is behind the scenes).

Then, in any example program that creates a camera:
'Callback function for Response
Function ResponseFunct_CreateCameraDebug()
	WriteStdout("This is a Response function!!!!")
End Function

Local Response_CreateCameraDebug:TResponse=New TResponse 'Create a new Response
Response_CreateCameraDebug.SetFunction(ResponseFunct_CreateCameraDebug) 'Connect the response to a callback function

Action_TCamera_CreateCamera.AddResponse(Response_CreateCameraDebug) 'Assign the response to an Action

Watch the console!


Really a simple matter of function pointers at the moment. The next step is adding data to responses and passing data to response functions. (And documenting this thing).
What I hope to achieve is different from a regular events system. For this, I want actions and their responses to carry some variable data.
For example, it should be possible to have a bunch of responses to the TMesh_LoadMesh Action that each load particular file formats. When that action's (in this case custom) Update function is called, a response is selected that loads the necessary format. (This information would be a bit of extra data attached to it... somehow. Either an extended Type or a variable map. A hash table would be intersting, but a waste of time since there probably won't ever be more than 3 values stored).

To actually be of use, a Response needs to know what instance of a type its Action came from. (Again, can't be completely hard-coded since it isn't always going to happen).

As for streamlining this thing... Yes, I realize it isn't the nicest or the most logical in this presentation. That is because of my ugly (huge) variable names, weirdly organized code and because the Actions end of it is not behind the scenes as it will be. Also, there should be a TResponse.Create function since creating a New object and adding a callback function is always done anyway.
(And no, this is not how it will be in the end; this is really just a demonstration of how fun function pointers are. I am sure that a lot will change...)


This is just about it for the first bit of tossing it together, I think, so any suggestions for the next steps are welcome.


Blueapples(Posted 2007) [#2]
How is this different from the Hooks system? Maybe I am missing something, but it looks just like it, but instead of directly adding a hook function you wrap it in a TResponse object.

I can see some value here if you add quite a bit more and make it all OO, as Hooks is pretty much pure procedural.