Mogre events and delegate signatures.

Kodachi_Garou

07-02-2007 16:43:42

I write this new post with a remark and a suggestion. Events and delegates in Mogre do not currently implement the .NET convention signature, namely:

public void EventHandler(object sender, EventArgs e);

My question is: why not? Since delegates only come up at the .NET level anyway, there shouldn't be any compatibility problem to make them respect this signature. On the other hand, the interoperability rewards are tremendous, since I could automatically connect my own .NET convention handlers to Mogre's own events in a transparent and automatic way, and also use my own events to trigger Mogre based delegate handlers.

It's an extremely favorable change, and I would like Mogre's developers to consider it. The faster it gets implemented, the less troubles it will cause to applications depending on Mogre, and the future possibilities will be manifold.

I hope this suggestion will be accepted, but I'll be happy to list many more arguments in its favour, since the events and delegates interplay is such a critical part of .NET development efforts.

Best regards,

Gonçalo

Bekas

08-02-2007 06:29:38

I write this new post with a remark and a suggestion. Events and delegates in Mogre do not currently implement the .NET convention signature, namely:

public void EventHandler(object sender, EventArgs e);

My question is: why not?

It's simpler from the wrapper tool's point of view. For each Ogre method it produces a delegate with the same signature.
For example, for ResourceGroupListener:
public ref class ResourceGroupListener abstract sealed
{
public:
delegate static void ResourceGroupScriptingStartedHandler( String^ groupName, size_t scriptCount );
delegate static void ScriptParseStartedHandler( String^ scriptName );
delegate static void ScriptParseEndedHandler( );
delegate static void ResourceGroupScriptingEndedHandler( String^ groupName );
delegate static void ResourceGroupLoadStartedHandler( String^ groupName, size_t resourceCount );
};

To get the EventArgs, there would have to be one EventArgs class for each method:
public ref class ResourceGroupListener abstract sealed
{
public:
ref class ResourceGroupScriptingStartedEventArgs : EventArgs
{
public:
String^ groupName;
size_t scriptCount;
};

ref class ScriptParseStartedEventArgs : EventArgs
{
public:
String^ scriptName;
};

ref class ResourceGroupScriptingEndedEventArgs : EventArgs
{
public:
String^ groupName;
};

ref class ResourceGroupLoadStartedEventArgs : EventArgs
{
public:
String^ groupName;
size_t resourceCount;
};

delegate static void ResourceGroupScriptingStartedHandler( Object^ sender, ResourceGroupScriptingStartedEventArgs^ e );
delegate static void ScriptParseStartedHandler( Object^ sender, ScriptParseStartedEventArgs^ e );
delegate static void ScriptParseEndedHandler( Object^ sender, EventArgs^ e );
delegate static void ResourceGroupScriptingEndedHandler( Object^ sender, ResourceGroupScriptingEndedEventArgs^ e );
delegate static void ResourceGroupLoadStartedHandler( Object^ sender, ResourceGroupLoadStartedEventArgs^ e );
};

Seems like EventArgs bloat. Is everyone comfortable with this ?
On the other hand, the interoperability rewards are tremendous, since I could automatically connect my own .NET convention handlers to Mogre's own events in a transparent and automatic way, and also use my own events to trigger Mogre based delegate handlers.
Can you give an example of what you are trying to do ?

Kodachi_Garou

08-02-2007 11:23:29

I understand your point, but I'm not sure if I agree that this is bloating... especially since it's automatically generated. Still, I do agree that this point is somewhat subjective and debatable, so I'll leave it in limbo for now.

However, I would like to discuss a bit more in depth about the benefits of adopting the .NET convention signature, and for that I'll just point out two examples of reusing delegates in an application.

1. Imagine that I have a physics' world being used with Ogre, and I have a method for updating the physics' object position into a SceneNode:

public void UpdatePosition(object sender, EventArgs e)
{
node.Position = body.Position;
}


Now I have to decide when to run the update code. If both Ogre and the physics' library follow the .NET convention, I can choose whether to attach the update to the FrameEnded event or to the WorldStepped event, for instance, without a single change in the method definition.

2. Finally, imagine that I want to generalize event handling to a group of Updatable objects. For that, I define an interface IUpdatable, with a single Update method:

public interface IUpdatable
{
public void Update(object sender, EventArgs e);
}


With this, so long as I'm working with events that follow the .NET convention, I can choose to which one do I attach the Update function, without changing the objects' code. Merely the attachment changes. Also, in the implementation it's possible to specialize and overload the function so more specific signatures are captured. It's even possible to link the Update to mouse clicks, database events or any other convention event.

It's just that it makes things that much more flexible and powerful, in my point of view, and more .NET-like. I'm currently implementing a component-based data-driven game-object system and problems like this come up all the time, since I want to be able to connect multiple methods to multiple callers and basically interop everything with everything.

I'm not sure I could get my point across, but there are tons of reasons why it would be worth it.

Cheers,

Gonçalo

Bekas

08-02-2007 13:27:02

Fair point, unless someone has an objection it will be implemented for next release.

Kodachi_Garou

10-02-2007 13:15:33

Thanks for the approval, Bekas! This will certainly bring some new possibilities to using Mogre.

Just one more thought regarding events and delegate signatures. This one may not be adequate for all cases, but here goes.

Suppose I take an event from the ResourceGroupListener:

delegate static void ScriptParseEndedHandler( Object^ sender, EventArgs^ e );

If this delegate signature only applies to events coming from ResourceGroupListener objects, one can write, without loss of generality:

delegate static void ScriptParseEndedHandler( ResourceGroupListener^ sender, EventArgs^ e );

Since all managed classes derive from the Object class, this new signature is type-equivalent to the first one, and any method respecting the common .NET signature (object sender, EventArgs e) will be able to attach to it.

However, there is a subtle difference between the two declarations. By declaring it in the second way, I guarantee that only objects of the ResourceGroupListener type are sending these events, i.e. that no other objects are declaring and raising ScriptParseEnded events. In this way, I can now write more specific Handler methods directly, like:

public void TakeCareOfScriptParseEndedEvent(ResourceGroupListener^ sender, EventArgs^ e)
{
}


And use the sender object directly as a ResourceGroupListener without the need to cast. Also, in the .NET IDE, intellisense will automatically generate these specific-kinds of signatures when attaching new delegates, so it's rather convenient :)

Please note that the more general and important step is just following the .NET convention. This is only to point out that in the same way that you can make the event throw a more specific type of EventArgs, you can make specify a more concrete sender object. It may be adequate or not, depending on which objects are raising which events.

Best regards,

Gonçalo

Bekas

10-02-2007 13:42:41

That's a good idea, I prefer the more specific sender too.
And it's perfectly applicable since for every event there's only one type that raises it.

Thanks for the feedback :)

Bekas

23-03-2007 21:05:26

I looked into the idea and there's only one issue:
if the delegate returns a value (like FrameListener's) or has a 'out' parameter (like RenderQueueListener's), how should they be handled ?

-Additional 'ReturnValue' property in EventArgs class
-Readonly properties in EventArgs but read/write for 'out' parameters
-Properies in EventArgs but fields for 'out' parameters (so that it's clear which are the 'out' ones)
-'Out_' prefix for properties of 'out' parameters.

Any ideas?