Common Practices: Return Values
Table of Contents
Introduction
In Structured Text, it is possible to return References to types as a result of a method/property/function. In the TwinCAT documentation, it is even recommended to do so to allow access to single elements of a returned struct. This, however, should be avoided as it can lead to dangerous and unpredictable behavior in the runtime. The reason is that especially functions should not use any static variables, and so they most likely will return a reference to a value on the call-stack. This means the data after the call is not to be trusted, and the reference might point to something else.
In most cases, it is better to work with Interfaces instead of Pointers/References. If you need to access a single element, you could also check if an implementation utilizing Fluent Interfaces might work for you.
You should never return a Reference/Pointer/Interface to data on the call-stack. This includes values returned inside a VAR_OUTPUT block.
Avoid Returning References or Pointers in Functions
Why functions must avoid returning interface references or pointers
Stack operations: Functions operate on the stack, where returning interface references or pointers can lead to unexpected behavior or memory corruption.
Avoidance of global data: Global data within functions is discouraged to maintain modularity and prevent unintended side effects.
Prevention of memory leaks: Dynamically generated data within functions can cause memory leaks if not managed properly.
Exceptions for returning interfaces, references, and pointers:
Functions may return interfaces, references, or pointers if the referenced data is passed to the function, ensuring proper memory management.
Guidelines for Methods and Properties
Methods and properties may return interface references or pointers if:
The data belongs to the object instance.
The data belongs to the class (static data).
It's a factory method with clear indications, providing dynamically generated data and offering the means to destroy it
For objects/interfaces, it’s required to provide a destruct method it must contain
__DELETE(THIS);
For references to type structs, one member must contain the address of it. E.g.
myAddress :POINTER TO <type>;
Otherwise it’s not possible to delete it again becauseADR
will return just the address of your variable.
Tips for Handling Return Values:
Instead of returning interface references or pointers directly, consider passing referenced data to functions to avoid stack-related issues and promote cleaner code.
Employ proper memory management techniques, such as deallocating dynamically allocated memory, to prevent memory leaks.
Utilize factory methods judiciously, ensuring they provide clear documentation and handling for dynamically generated data.