spinettaro / delphi-event-bus

Delphi Event Bus (for short DEB) is an Event Bus framework for Delphi
Apache License 2.0
466 stars 110 forks source link

[Suggestion] - Return value from posting an event to the same thread #8

Closed edwinyzh closed 4 years ago

edwinyzh commented 7 years ago

Is it reasonable to make the TEventBus.Post method be able to return a value (can be any type of value, a TObject or TValue? not sure)?

The idea is like the `SendMessage' winapi.

It's very necessary, in case we use an event to represent an action (a concept borrowed from Redux action.

That being said, I want to achieve an application architecture, where:

And it must come in handy if the event posting would be able to return values when posting to the same thread.

Not sure if I have described it clearly, but I mainly have inspired by Redux Framework.

I hope this makes sense.

And this stackoverflow question might help understanding my suggestion: React.js - flux vs global event bus

wxinix commented 4 years ago

I believe - with the new interface-typed event, you can freely add returned value in user-defined interface-typed event.

spinettaro commented 4 years ago

I didn't get it to be honest @edwinyzh . The return type of post would be the same of the passed one? https://github.com/spinettaro/delphi-flux-seed satisfies your request?

edwinyzh commented 4 years ago

I didn't get it to be honest @edwinyzh . The return type of post would be the same of the passed one? https://github.com/spinettaro/delphi-flux-seed satisfies your request?

The requirement is simple - turn the eventbus from unidirectional to bi-directional.

wxinix commented 4 years ago

@edwinyzh

You can make it "bi-directional" with the latest interface-typed event. You can delegate the callback to the event emitter via a designated user-defined interface event method. Is that what you are looking for?

Overall, bidirectional communication would make the work flow hard to manage. It is just like the infamous "GOTO" of procedural languages.

In a one-to-many publisher/subscriber setting while in thread mode other than TThreadMode.Posting, DIRECTLY returning a value from IEventBus.Post does NOT make any sense. Pointless in my eyes. It unnecessarily complicates the design of delphi_event_bus, which is intended (as I see it) to be a lightweight and flexible Event Bus framework.

edwinyzh commented 4 years ago

@wxinix,

You explained it very well! I'm convinced ;) You are right, it seems that directly returning a value by in a 1-to-many eventBus system doesn't make much sense and make things complicated as well!

Actually I can/already achieved bidirectional communication by sending back something like TEventReceivedYourReuqest ;)

I'll check the new interface-typed event, but I'm current hesitant to upgrade because I'm using a customized TEventBus, maybe sometime later.

Thank you for all you guys' contribution to the EventBus lib!

wxinix commented 4 years ago

@edwinyzh The latest delphi_event_bus framework makes use of interface-typed event, instead of TObject in previous version. This means - when routing an event from the event emitter to subscriber methods, there is no longer internal copying of the event object --- the emitter and subscription methods are now dealing with the same event object.

Thanks to @spinettaro , for this new framework design, which is very neat and greatly improves on previous versions.

This allows us to implement a "bidirectional communication" like below:

TOnEventReceived = reference to procedure(AMessage: string); // You can use anonymous methods, or method ptrs

IMyFunkyEvent = inteface
['{3522E1C5-547F-4AB6-A799-5B3D3574D2FA}']
  procedure Set_OnEventReceived(AValue: TOnEventReceived);
  function Get_OnEventReceived: TOnEventReceived;
  property OnEventReceived: TOnEventReceived read Get_OnEventReceived write Set_OnEventReceived; 
end;

Then from the subscriber method (assuming Posting thread mode), you can callback the emitter:

[Subscribe]
procedure OnMyFunkyEvent(AEvent: IMyFunkyEvent);
begin
  // manage the event
  if Assigned(AEvent.OnEventReceived) then
   AEvent.OnEventReceived(); // Calling back the emitter here to send back stuff
end;

Thus you see, a "bidirectional communication" is easily accomplished via this new interface-typed event, which should meet your requirement.

edwinyzh commented 4 years ago

@wxinix,

Thanks for the demonstration, It's VERY GOOD! GREAT! In my experience I believe cloning of the event objects with the slow Extended RTTI has been the bottleneck of performance in some situations!

I should have checked the updated readme file for DEB 2.0 ;)

edwinyzh commented 4 years ago

One side effect of the 2.0 change - for each event you'll have to define an object and an interface ;)

spinettaro commented 4 years ago

thanks @wxinix for the explanation :) . @edwinyzh pay attention with the bidirectional communication as we have seen in other frameworks, ie Flux from Facebook, having a unidirectional flow is much better in term of readability, maintainability and troubleshooting sessions...

dkounal commented 4 years ago

My stupid question is: finally, EventBus is freeing any Event object after replying?

Also, I believe the above example should exist also in the frontpage readme file of EventBus

spinettaro commented 4 years ago

Now the events are interfaces. So we are relying on the reference counting mechanism for interfaces. MM is not required anymore.