Events system

Monkey Forums/Monkey Programming/Events system

ziggy(Posted 2014) [#1]
I've been using my own events system for Jungle Gui. While I think it is a very solid and easy to use system, it has the problem to rely on Reflection and increasing too much compilation time on Monkey. Also, method correctness is solved at runtime, wich is not as nice as it would be by using Delegates.

In my ideal world, Monkey would have Delegates, and we could just add and remove method references to a list, and invoke them later, without having to use reflection, but that's not possible, and I supose it's not in Mark's plans to add this functionality anytime soon.

We could get something *similar* by manually using interfaces, but that's not dynamic. You cannot decide which method to be called at any time, it's always the interface-defined method, And also, any single class that handles the same event for different objects need to select which is the sender object before performing its actions, and that generates very dirty code (a la Java). I really dislike using interfaces to workaround the lack of delegates. Java, at last, allows the creation of inner classes to make this a bit better (I still dislike it, but at last, this is something).

So, all in all, Does anybody have a good implementation of events that solves my scenario without using Reflection?

EDIT: I see that the delegates system could be easily implemented into Monkey but I supose Mark does not want to make such this change into the language, Anyway, if there's any interest, my idea of implementation is here: http://www.monkeycoder.co.nz/Community/posts.php?topic=8127#81432


Gerry Quinn(Posted 2014) [#2]
How about a messaging system, like Windows?

Every GUI object is a window with its own ID, which gets passed messages in a standard form via its parent window. Use overrideable functions to implement non-standard functionality. I'm thinking of something like MFC, if you're familiar with it.

But maybe you are looking for something more general than a system of windows and controls.


Skn3(Posted 2014) [#3]
I use this heavily in all of my projects:
https://github.com/skn3/callbacks

It is a fairly simple approach, but it has proven to work nicely on 2 large scale app projects so far.

[update]
here is an example:
Import skn3.callbacks

Global CALLBACK_DO_SOMETHING:= RegisterCallbackId("Do Something")

Function Main:Int()
	Local myClass1:= New MyClass("myClass1")
	Local myClass2:= New MyClass("myClass2")
	Local myClass3:= New MyClass("myClass3")
	
	FireCallback(CALLBACK_DO_SOMETHING, Null, Null)
End

Class MyClass Implements CallbackReciever
	Field name:String
	
	Method New(name:string)
		Self.name = name
		
		'add callbacks to this class
		AddCallbackReciever(Self, CALLBACK_DO_SOMETHING)
	End
	
	Method OnCallback:Bool(id:Int, source:Object, data:Object)
		Select id
			Case CALLBACK_DO_SOMETHING
				Print "CALLBACK_DO_SOMETHING called for " + name
		End

		'return to not block further callbacks
		Return False
	End
End



ziggy(Posted 2014) [#4]
@Skn3: That's as a Java listener, isn't it? It's functional but what I want to do is to be able to call any arbitrary method on runtime. I mean, at runtime being able to modify the callback.

All this could be sort of fixed if we could have a compile-time statically typed GetMethod that, as being resolved at compile time, doesn't require reflection to work.


ziggy(Posted 2014) [#5]
That's how I have actualy implemented my events system (That's a form with 2 buttons and a text field, that performs several actions when buttonsw are pressed, text in the textfield is modified, or the form is resized:
Class MyForm Extends Form
	Field butClose:Button
	Field butChangeColor:Button
	Field textField:TextField
	Method OnInit()
		butClose = New Button
		butClose.Parent = Self
		butClose.Text = "Click me to close this form"
		
		'Add a method to the EventHanler:
		'The "ButClose_Clicked" method of "Self" will be automatically invoked when the butClose is clicked. No more code involved.
		butClose.Event_Click.Add(Self, "ButClose_Clicked") 
		
		butChangeColor = New Button
		butChangeColor.Parent = Self
		butChangeColor.Text = "Click here to change form color"
		butChangeColor.Position.Y = 40
		butChangeColor.Event_Click.Add(Self, "ButChangeColor_Clicked")
		
		textField = New TextField
		textField.Parent = Self
		textField.Position.Y = 80
		textField.AutoAdjustSize = False
		textField.Size.SetValues(200, 20)
		
		textField.Event_TextModified.Add(Self, "TextField_TextModified")
		
		Self.Event_Resized.Add(Self, "FormResized")
	End
	
	Method FormResized(sender:Object, e:EventArgs)
		Self.Text = "New size: " + Self.Size.X + ", " + Self.Size.Y
	End
	
	Method ButClose_Clicked(sender:Object, e:MouseEventArgs)
		Self.Dispose()
	End
	
	Method ButChangeColor_Clicked(sender:Object, e:MouseEventArgs)
		Self.TipText = "Back color has been changed."
		Self.BackgroundColor = New GuiColor(1, Rnd(0, 255), Rnd(0, 255), Rnd(0, 255))
	End
	
	Method TextField_TextModified(sender:Object, e:EventArgs)
		Print "Text has been modified on the text field!"
	End
End

I do really like how the events system is desiged EXCEPT for this:
butChangeColor.Event_Click.Add(Self, "ButChangeColor_Clicked")
As it requires reflection to get a sort of "method pointer", this is evaluated at runtime, so coding errors are not detected untill the code is executed. Then, also, it involes reflection, which increases a lot the compilation time.
Pros of the system is how dynamic it is. You can attach any method at any time to the Event, as long as it has the appropriated method signature (parameters). Also, more than one method can be associated to each event, and they all will be executed. You can even call a method in any class instance, when an event happens on another class instance. That's a lot like obejct messaging system, I don't think all this can be done with only interfaces, but if anyone has any other idea... ?

@Gerry Quinn
How about a messaging system, like Windows?

I already has this for the "lower level" stuff on the Gui system, so it's faster, etc. but it's not very convenient for higher level coding of a Gui system. It forces big dispatch methods where you select the msg constant and call a given method, etc... that's exactly what I don't want to provide in my gui!