Outsourcing of elements to a subroutine
Since release 3.27 you may select a subset of your diagram and automatically outsource it to a new subroutine just in a flash!
Imagine the following example of a statistical calculation. It starts with the manual input of some numerical values, then computes their average and finally derives the standard deviation.
You may want to decompose this algorithm. Let's start with the standard deviation. Select all elements involved in this part of the computation:
To convert the selected part into a subroutine you may:
- select menu item "Diagram › Outsource",
- select context menu item " Outsource", or
- enter <Ctrl><F11>.
You will simply be prompted for a routine name:
That's all what you have to do (most times, at least)! Structorizer will automatically analyze what arguments the routine needs and whether it is to return a value, then it will move the elements to the new routine created with this signature and also push the routine diagram to the Arranger. If the main diagram had not been in the Arranger before then it will be pushed there, too:
In the original diagram, the selected elements will have been substituted with the respective routine call. The replacing CALL element is automatically selected (and hence highlighted). Note that the result is immediately ready for execution!
If the parent diagram hadn't resided in the Arranger then a new group will be created named after it. The new subroutine diagram will automatically join all arrangement groups its parent diagram has been member of (see the red box in the screenshot below).
Looks nice? Well, but what about diagram regions that produce more than a single value, which other parts of the algorithm rely on? Let's try with the input part next — it introduces both the count variable and the readings array, which are both used by subsequent code:
Rather than creating and sharing a dedicated record (struct) type for exactly this routine return value, the converter makes use of the ability to fill arrays ad-hoc with values of different types (which is still simpler in Structorizer, but also bound to cause trouble on export to several programming languages, on the other hand).
In Arranger, the new subroutine will also be member of the arrangement group (the bounding box of which can be visualised by switching on the "Show groups" checkbox):
And how is the CALL integrated in the main program? Let's have a look:
As you can see, an array variable with a generic name is introduced to receive the values from the routine, then the values are extracted one by one and put into the actual target variables. (This method may not look so nice but is very effective in Structorizer. We have to admit, of course, that it may cause trouble on code export to some strictly typed languages, where you would have to make use of record/struct types instead. A future release might make use of the record concept already introduced with release 3.27 here.)
Consequently, outsourcing the average calculation is just as easy as before:
So we get the third subroutine in a blink, too.
The main program has shrunk a lot, this way:
It should not be necessary to mention that the outsourcing can of course be undone in the main routine (and redone etc.). The undoing in the parent diagram will not delete the created subroutines, however. You may simply remove ("drop") them if you want to get rid of them.
Note, on the other hand, that the emerged group of diagrams is consistent now. It is ready to be saved as arrangement, simply by selecting the group entry in the Arranger Index (right panel) and clicking the "Save changes" item in the context menu. You will be offered to store the group either as compressed archive or as a set of nsd files with a referencing arrangement list file:
Admittedly, this was only half the truth - there are cases where Structorizer may not cope with correctly identifying the needed parameters and result values. Then you will have to accomplish the result yourself. But we think that even in these cases the "Outsourcing" function will facilitate your job to decompose an algorithm grown too complex. Let's see an example in the following section.
Outsourcing with record types or includables involved
Consider the following algorithm, which simply derives a slightly modified date from a given date (without calendar corrections). Here a record type is involved, which the main program and the outsourced subroutine (from the selected elements) will have to share. You start the outsourcing as described above:
But Structorizer detects that the type Date defined in the main program must also be known to the subroutine diagram and thus decides that it has to be tranferred to an Includable diagram that both main and subroutine need to include. Therefore you will be asked for a name for that additional diagram:
After having commited the question, you will obtain two new diagrams, the includable and the subroutine:
The main program will have changed as follows:
As you can see in the Analyser report list, the result is not quite correct. A record variable cannot simply be introduced by assignment (unless the assigned value is a record initializer). So we must re-introduce a declaration like the one moved to the subroutine (where it is also necessary, so it wouldn't have helped just not to select the declaration before outsourcing — in that case the subroutine would have been defective instead). For the current version of Structorizer an automatic solution of this situation is still slightly too complex.
By the way: If the record type had already been included by the main routine (instead of having been defined locally) before outsourcing, however, then the subroutine would have inherited that include item automatically without asking.
Remark with respect to the arrangement groups introduced with release 3.29: On outsourcing, Structorizer ensures that the derived subroutine and a possible includable diagram will automatically be added to all groups the originating diagram is member of, such that consistency is preserved.
Counter-indications against outsourcing
There are algorithm subsets, however, which cannot easily be outsourced. Not surprisingly, they are usually provoked by unstructured diagram elements like Jumps (EXITs). If the selected region of the diagram contains EXIT elements, which intend to direct the control flow to targets outside the selection then we get in deep trouble. Look at the following nonsense example. It contains a CASE selection with several kinds of outbreaking elements — exiting the inner loop, the outer loop, the entire application, or the current routine or program, respectively:
If we liked to outsource the selected elements then three of the Jumps point outwards the subset, only the empty Jump (equivalent to leave ) has a target inside the selection: the input instruction beneath the FOR loop. The exit command is not a problem, either — its semantics is independent of its location, it will always abort the entire execution. With the 2-level leave it is different: its target is the REPEAT loop, which will be outside the routine and hence unreachable, the leave 2 instruction is going to be illegal therefore. The return instruction, on the other hand, will change its semantics drastically: Instead of ending the outer program it would now just leave the subroutine, this way compromising the program logic. (And there is no easy way to maintain or restore the original logic.)
Structorizer tries to detect such cases and vividly warn off outsourcing element sets of that kind:
If you really know what you do and you have an idea how to mend the defects provoked by the outsourcing then you may go on, otherwise you better back off.
Note that Jump elements of type throw (exit on error) don't usually cause trouble because the TRY context of the replacing CALL element remains the same. |