In the absence of OOP - which I understand, based on the model - it would still be nice to have delegates that can match particular actions, and that a delegate type could be a parameter for an action.

I actually made an attempt at making delegates/callbacks (attached) but late in the process, I got a rather stern lesson about how bad reflection is at handling structs in .NET.

I made it so that you could make a Structure with exactly the same layout as the Actions you were expecting to call, e.g.

...and then an example Action with those same parameters:

Then I had the actual Callbacks - here was my sample flow:

CreateCallback took the ESpace and the name of the Structure:

You could choose which Action to bind the Callback to via BindCallback:

Make a local variable of the Structure type and assign parameters to it:

...and then call the actual Callback with those parameters:

It almost worked. I could read things out of the parameters, and the breakpoint in TestEmailCallback got hit:

I couldn't get the results back, though. The ToObject(parameters) makes a boxed copy of the structure, and FieldInfo.SetValue(structure, value) actually makes a boxed copy of the structure every time it sets the field, and so loses the field.

There's __makeref and SetValueDirect and weird things like that, but absent being able to do that from the OutSystems side or being able to convert a generic object to a specific structure, I think I will have to abandon my efforts - or maybe thing of a less-cool way of doing it.

Anyhow, I'd like this as an OutSystems feature at some point so that I don't have to do weird things with Switches everywhere :)

Also, sorry for being a bit insane.

-- Ritchie Annand

Created on 25 Apr 2018
Comments (6)

Changed the category to Backend

What would be the advantage?

Same as delegates in other languages - you can pass in a comparison action or a factory action or an event listener action.

It's not as though there's no way to do it now - you can make actions that, say, take a static entity ID or text or an integer and throw things through a switch statement, but it does limit the functionality you can put in separate modules and it can be a bit of a maintenance headache.

Tiago's been showing us "the OutSystems way" of splitting up modules into a more visual-focused MyModule and a more data and services-focused MyModule_Core, but anything that needs something like a delegate basically has to stay in the same module as what it needs to call back to right now.

Might make for more consistent "event actions", like On Row Save or On Change being able to be assigned directly or to a delegate.

If delegate has parameters with structure type it allows sending not just text value from web block to avoid coding/decoding some structure to JSON and back.
Also delegate allows calling  defined in upper layer eSpace actions from referred eSpace and simplify separation of functionality in different eSpaces. Otherwise there will be switch and all actions are in referred eSpace together with used entities definitions.

This is, by a long shot, the best and the most underrated idea over here and we don't have an answer by OutSystems as of yet.

I had a lot of situations where I needed this, one just now: I am building a bot framework generic component that will handle and encapsulate all communication with the bot services. Then I want to delegate the responsibility of programming the behaviour of the bot to a consumer module, but I can't to that. I need to either create a template that uses light BPT's to handle a messaging queue or make available an internal webservice. Both workarounds are poor substitutes for callbacks, which is something very common and very necessary.

I rebadged the idea to imagine it working the way a proper OutSystems feature would work, but it probably won't get any traction, either: https://www.outsystems.com/ideas/6302/placeholder-actions

I was disappointed in the way my Callbacks attempt worked in large part because it would have been ideal to put the values back in the structure as exactly the type they are supposed to be.

That said, it could be modified fairly easily to still have a structure for all the input parameters (those are fine) but to have all the output parameters sit in an IDictionary<string, string> or an IDictionary<string, object> and have a GetCallbackResult(CallbackObject, ResultKey) return that value. It's inelegant and doesn't work directly for results that want to return structures, say (unless you hook in a JSONSerialize/JSONDeserialize in there?) but it would be better than nothing.

It would also require the callback's first parameter be an object that could be used to assign the results instead of just assigning the results to the structure, e.g. SetCallbackResult(CallbackObject, ResultKey).

If that's something that would actually help, I could carve out some time at some point to try to make an example?