Subflow: a replace or a function?

Hello everybody!

I am struggling a bit with the concept of a subflow. And I am not sure if I understand the concept 100% correctly. I read the manual and some topics in this forum about subflows. But still I am not sure if I understand it correctly. Please, correct me if I am wrong.

A subflow is a tidy mechanism that allows a programmer to combine commonly used nodes/handling in one. Meaning that a subflow allows nodes to be replaced with a subflow. Calling a subflow in a flow will not make an instance of the sublfow. The subflow acts like it replaces its content with the content of the subflow during execution. Everything is executed with the environment variables of the main flow. A subflow that is called on a multiple places, will "start" different subflows.

If I want to make a function, I should use link in and out to a flow. The flow will be my function and have different processes when called multiple time. Every process goes in that flow. In that flow the link in will be triggered and complete the flow with variables passed on via payload.

If I want make instances of a group of functions, I should make my own node. Then I have my own node with its own environment, like an instance. And stay in the environment of a flow.

Thanks in advance!

I don't think you use link nodes to get in/out of the subflow.

Basically you start a new subflow and at the top you have the input and output nodes.
You have to select how many outputs.
It is a given there has to be ONE input to the subflow. (No more)
But outputs are optional.

Be aware (as I just mentioned) the subflow can only have ONE input.
This can cause problems, but these can be overcome by formatting all incoming messages with either topic (or something) and then switching the messages to their correct parts in the subflow.

Variables are a bit tricky.
flow is local to that subflow.
To access the parent flow and global variables, there is a slight trick.
Sorry I can't remember off the top of my head, but it isn't quite as straight forward as it is normally.

I am pretty sure you are correct with the rest of what you say.

1 Like

You're right about what you write. My question is different. Please, let me rewrite my question.

A subflow will replace itself with its content when being called. There is no initialization of the subflow.-node. Meaning that the code in the subflow-node will be in the scope of the flow itself. A replacement to make code more clear to read.

When using link nodes, you can go to another flow. You will use the scope of the flow hte message gooes to. Here, there is also no initialization. You will be in the scope of the already initiazed flow. And keep mind that a flow can have multiple message flows in itself when being called multiple time via links.

A node will make an instance on the flow when being programmed. Node has initialization per node.

You haven't actually asked a question as far as I can see.

Forgot the sentence "I am correct with the following conclusion?" :wink:

Individual instances of a subflow can now have properties.

But is a sublfow an instance or a replace?
I still have a feeling that a subflow will be replaced by it's content when being called. A tidy mechanism and not an object or a function call.

I'm still not sure what you mean by "instance" or "replace". Aren't they the same thing? At least as far as subflows are concerned.

My understanding is that each use of a subflow is a separate "instance", each can have specific properties as mentioned by @Colin above. The contents aren't "replaced", they just are the contents of the subflow.

I'm also not sure about your use of "function" - whether you mean a function node, or a Javascript function within a node (or even a global function). Functions can also be "instances", depending on where they are created and how they're called.

I think I will make a test case to test it. If I make one subflow and implement it three different wires/processes. Will this subflow be called 3 times, or will there three different subflows being called?

With replacing I mean litteraly replacing. Like the #define in C. You define MAX as 8 and in the code everything with MAX will be replaced by the character 8. Now is C different than JavaScript with compiliation and runtime. But I think you will get my drift.

I think I've got it after maken some testing. A subflow is indeed replacement of the nodes defined in its template. Every subflow instance of the subflow template is it's own piece of code with its own scope (flow variables a.s.o.). Making it almost equal to a node regarding behavior and greaty way to tidy up the amount of nodes in a flow.

So, if I have repetitive code in my project and they should share data or commands, I must make a new flow with links.

1 Like

I liked the way you rephrased the definition of Subflows.

If I had to ilustrate with a didactic example, to explain the env variables and scope of the flow variables, it would be like below:

Code inside a function node (only node inside the subflow):

let reveal = env.get("hit");
flow.set("reveal", reveal);
node.warn(reveal);
return msg;

[{"id":"abf4e58f.f6ecd8","type":"subflow","name":"Subflow 1","info":"","category":"","in":[{"x":260,"y":100,"wires":[{"id":"ae738333.f44"}]}],"out":[{"x":480,"y":100,"wires":[{"id":"ae738333.f44","port":0}]}],"env":[{"name":"hit","type":"num","value":"3"}],"color":"#DDAA99","status":{"x":160,"y":30,"wires":[]}},{"id":"ae738333.f44","type":"function","z":"abf4e58f.f6ecd8","name":"Hit","func":"let reveal = env.get(\"hit\");\nflow.set(\"reveal\", reveal);\nnode.warn(reveal);\nreturn msg;","outputs":1,"noerr":0,"x":370,"y":100,"wires":[[]]},{"id":"4ffc9b47.f51954","type":"tab","label":"Subflows - Context and Env. Variables","disabled":false,"info":""},{"id":"8af8415.18c4bc","type":"subflow:abf4e58f.f6ecd8","z":"4ffc9b47.f51954","name":"Hit 1","env":[{"name":"hit","value":"1","type":"num"}],"x":350,"y":220,"wires":[["1ee3d4bd.c22dab","ae2617f5.882028","275f4561.d2038a"]]},{"id":"df0456d0.06d348","type":"inject","z":"4ffc9b47.f51954","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"0.5","x":210,"y":220,"wires":[["8af8415.18c4bc"]]},{"id":"1ee3d4bd.c22dab","type":"subflow:abf4e58f.f6ecd8","z":"4ffc9b47.f51954","name":"Hit 2","env":[{"name":"hit","value":"2","type":"num"}],"x":470,"y":160,"wires":[["275f4561.d2038a"]]},{"id":"ae2617f5.882028","type":"subflow:abf4e58f.f6ecd8","z":"4ffc9b47.f51954","name":"Hit 3","env":[],"x":470,"y":280,"wires":[["275f4561.d2038a"]]},{"id":"92e7562.c9d31a8","type":"debug","z":"4ffc9b47.f51954","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":830,"y":220,"wires":[]},{"id":"4c528dfe.26ec84","type":"inject","z":"4ffc9b47.f51954","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":190,"y":80,"wires":[["829ab29b.9a22c"]]},{"id":"829ab29b.9a22c","type":"change","z":"4ffc9b47.f51954","name":"","rules":[{"t":"set","p":"reveal","pt":"flow","to":"mainflow","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":80,"wires":[[]]},{"id":"275f4561.d2038a","type":"change","z":"4ffc9b47.f51954","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"reveal","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":620,"y":220,"wires":[["92e7562.c9d31a8"]]}]
1 Like

I'm still not sure I (or you) understand the distinction between subflows and functions. Do you mean "make a new subflow" or are you thinking that you have to make a whole new flow to have multiple uses of the same overall structure?

I think that documentation about scope of variables could be a bit better.

Function as in function node or the definirtion of a function? But, I think I should have made my scope clear. My quesion was if a subflow is replace or something like a function. I know that it is a 'replace' with its own workmemory.