Allow Actions/Functions to be passed as a parameter
3693
Views
22
Comments
On our RadarOn our Radar
Service Studio
Allowing functions to be passed as a parameter has been supported in many popular languages including Java, JavaScript, Python, and PHP.  Adding this functionality will make OutSystems code more dynamic.

Well-Known JavaScript Example:

// $() is an alias of jQuery()
$(function(){
    // code goes here
});
2016-04-21 20-09-55
J.
 
MVP
Will this not screw up the "TrueChange" ?
If you make it more dynamic, runtime errors will increase....

Merged this idea with 'Action,Destination as a parameter' (created on 19 Aug 2014 04:48:18 by K N)
When we create an Action or a ScreenAction, it's impossible to make a parameter with 'Action' or 'Destination' data type.
 
If it becomes possible, we can reduce a lot of SUs and get high maintenability.


This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James
Merged this idea with 'Delegates' (created on 25 Apr 2018 15:14:25 by Jade Ritchie Annand)

This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James

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



This comment was:
- originally posted on idea 'Delegates' (created on 25 Apr 2018 by Jade Ritchie Annand)
- merged to idea 'Action,Destination as a parameter' on 21 Mar 2021 17:08:53 by Justin James


This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James
Changed the category to
Backend


This comment was:
- originally posted on idea 'Delegates' (created on 25 Apr 2018 by Jade Ritchie Annand)
- merged to idea 'Action,Destination as a parameter' on 21 Mar 2021 17:08:53 by Justin James


This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James
2016-04-21 20-09-55
J.
 
MVP

What would be the advantage?





This comment was:
- originally posted on idea 'Delegates' (created on 25 Apr 2018 by Jade Ritchie Annand)
- merged to idea 'Action,Destination as a parameter' on 21 Mar 2021 17:08:53 by Justin James


This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James

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.



This comment was:
- originally posted on idea 'Delegates' (created on 25 Apr 2018 by Jade Ritchie Annand)
- merged to idea 'Action,Destination as a parameter' on 21 Mar 2021 17:08:53 by Justin James


This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James

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 comment was:
- originally posted on idea 'Delegates' (created on 25 Apr 2018 by Jade Ritchie Annand)
- merged to idea 'Action,Destination as a parameter' on 21 Mar 2021 17:08:53 by Justin James


This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James

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.



This comment was:
- originally posted on idea 'Delegates' (created on 25 Apr 2018 by Jade Ritchie Annand)
- merged to idea 'Action,Destination as a parameter' on 21 Mar 2021 17:08:53 by Justin James


This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James

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?



This comment was:
- originally posted on idea 'Delegates' (created on 25 Apr 2018 by Jade Ritchie Annand)
- merged to idea 'Action,Destination as a parameter' on 21 Mar 2021 17:08:53 by Justin James


This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James
Merged this idea with 'Dependency injection - actions as input parameters' (created on 18 Mar 2021 15:32:07 by Terry Dutton)

This comment was:
- originally posted on idea 'Delegates' (created on 25 Apr 2018 by Jade Ritchie Annand)
- merged to idea 'Action,Destination as a parameter' on 21 Mar 2021 17:08:53 by Justin James


This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James

I'm imagining a widget you could drag into an action and set certain kinds of inputs and outputs on it (kind of like an event trigger widget, but with outputs as well as inputs). Then the action it's in gains an input parameter that accepts any action whose inputs and outputs match what you set.

A feature like this would make actions much easier to test, especially those that rely on integration calls (as we could pass in mock integrations for testing). It would also allow modules to be decoupled from their dependencies, which would greatly reduce publishing times.

It's already possible to pass client actions in this manner, albeit in a roundabout way (you can create a javascript node, give it an Object-type output parameter, and set the value to be a client action. Then you can pass that action as an Oject-type input to other actions). A more streamlined way, and a way to do it with server actions too, would be ideal.



This comment was:
- originally posted on idea 'Dependency injection - actions as input parameters' (created on 18 Mar 2021 by Terry Dutton)
- merged to idea 'Delegates' on 21 Mar 2021 17:07:34 by Justin James


This comment was:
- originally posted on idea 'Delegates' (created on 25 Apr 2018 by Jade Ritchie Annand)
- merged to idea 'Action,Destination as a parameter' on 21 Mar 2021 17:08:53 by Justin James


This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James
Merged this idea with 'Allow actions as action parameters' (created on 12 Feb 2016 12:19:55 by Pedro Rodrigues)

This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James
It would be nice if it was possible to define "template" actions, i.e. actions that have one or more actions as input parameters and use them in their body. The idea is not new, it is what is known as the template method pattern (see: https://en.wikipedia.org/wiki/Template_method_pattern) or the strategy pattern (see: https://en.wikipedia.org/wiki/Strategy_pattern). 
This would help minimize code duplication.
An example is the need to log information just before and just after an action. If we want to do this for 30 different actions, we have to place the log actions on each of the 30 actions. If we could define a template action, we would only need to define a single "template" action and "wrap" each call to the 30 different actions with the template action.

Java and .Net already allow for lambda functions/expressions. This means that this could be done without much problems.

This comment was:
- originally posted on idea 'Allow actions as action parameters' (created on 12 Feb 2016 by Pedro Rodrigues)
- merged to idea 'Action,Destination as a parameter' on 21 Mar 2021 17:09:54 by Justin James


This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James
2016-04-21 20-09-55
J.
 
MVP
I don't think it's a matter of the possibility.

It's more, how do you keep TrueChange(tm) in order.
Imho, the reason why while-loops, advanced programming patterns are NOT implement is to make sure the application is technically always correct, so you don't end up with unexpected runtime errors.

hence they don't promote adv. queries, using [2] in lists etc.




This comment was:
- originally posted on idea 'Allow actions as action parameters' (created on 12 Feb 2016 by Pedro Rodrigues)
- merged to idea 'Action,Destination as a parameter' on 21 Mar 2021 17:09:54 by Justin James


This comment was:
- originally posted on idea 'Action,Destination as a parameter' (created on 19 Aug 2014 by K N)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:10:26 by Justin James
Merged this idea with 'Make screen action an input parameter type' (created on 17 Nov 2015 15:47:30 by Joris van Geffen)
When a web block has multiple elements which normally trigger a screen action, externally assigning a different screen action to these elements can be don't in a nice way.

The elements themselves should trigger a notify event with a message which indicates the element which was triggered. Then it is up to the consumer to create a screen action in which the message is used to determine which action flow to follow.

As an example, say a web block was created in which there is a save and cancel button. The consumer of this web block creates a screen action in which handles the notify event. Within the screen action an if statement is placed to check if the message of the notify event was save or cancel. Then the true or false flow will actually handle both flows within the same screen action.

It is my opinion that it would be nicer to have input parameters of the type screen action in which you can assign a reference to an external screen action. That way the consumer can create screen actions for a specific purpose which get triggered within the web block.

Following the example above, it would mean that the web block gets 2 input parameters of the type screen action; SaveAction and CancelAction. The consumer defines 2 screen actions; SaveScreenAction and CancelScreenAction and assigns them to the matching parameters. Then the save and cancel buttons within the web block can trigger these screen actions.

The advantage of this is that it becomes possible to create more generic web blocks which act more like native controls where it is possible to reference a screen action like a button control.


This comment was:
- originally posted on idea 'Make screen action an input parameter type' (created on 17 Nov 2015 by Joris van Geffen)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:12:24 by Justin James
You mean call-backs. I'm not sure whether I would be in favour of that, apart from the fact that technically it's not trivial, as in the context of the web block, those actions (and their context) do not exist.

This comment was:
- originally posted on idea 'Make screen action an input parameter type' (created on 17 Nov 2015 by Joris van Geffen)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:12:24 by Justin James
The alternative is to have more custom events instead of just one notification event. In that way it is also possible to bind to a specific event without the need to analyse a string value just to see what happened.

The current way of working requires insight into the web block one is consuming, which is something you don't want to bother other developers with. in my opinion a web block should be self contained and clearly understandable without the need to dive into it so determine how it can be used.

This comment was:
- originally posted on idea 'Make screen action an input parameter type' (created on 17 Nov 2015 by Joris van Geffen)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:12:24 by Justin James
2016-04-21 20-09-55
J.
 
MVP
isn't that the job of the develope of the webblock itself?



This comment was:
- originally posted on idea 'Make screen action an input parameter type' (created on 17 Nov 2015 by Joris van Geffen)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:12:24 by Justin James
Well, that depends on the type of web block you have. If you always have a Save and a Cancel button, you may put them in a web block (being standard UI elements etc.). But to handle them, it would be nice if you could, from the web block, trigger Screen Actions in the consuming screen. Currently you're stuck with a single OnNotify.

This comment was:
- originally posted on idea 'Make screen action an input parameter type' (created on 17 Nov 2015 by Joris van Geffen)
- merged to idea 'Allow Actions/Functions to be passed as a parameter' on 21 Mar 2021 17:12:24 by Justin James