Use of functions and methods

Topics:

  1. Evaluate returned error information of a POU [++]
  2. Use return value of a function/method [+]
  3. Do not call functions/methods within themselves [+]

Evaluate returned error information of a POU

If a function, a method or a function block returns error information, always evaluate it.

Static Analysis:

Thematically recommended Static Analysis rules:

Negative sample:

PROGRAM Sample_neg 
VAR
    fbFileOpen    : FB_FileOpen;      // FileOpen-FB for logger
    bFileOpenExec : BOOL;             // Execute FileOpen-FB
END_VAR
// NON COMPLIANT: error information of fbFileOpen will not be used
fbFileOpen(
    sPathName := 'C:\TestFile.txt',
    nMode     := FOPEN_MODEWRITE OR FOPEN_MODETEXT,
    ePath     := PATH_GENERIC,
    bExecute  := bFileOpenExec,
    tTimeout  := T#3S);

Positive sample:

PROGRAM Sample_pos 
VAR
    fbFileOpen        : FB_FileOpen;  // FileOpen-FB for logger
    bFileOpenExec     : BOOL;         // Execute FileOpen-FB
    bFileOpenError    : BOOL;         // Error flag of FileOpen-FB
    nFileOpenErrorID  : UDINT;        // Error code of FileOpen-FB
END_VAR
// COMPLIANT: error information will be handled
fbFileOpen(
    sPathName := 'C:\TestFile.txt',
    nMode     := FOPEN_MODEWRITE OR FOPEN_MODETEXT,
    ePath     := PATH_GENERIC,
    bExecute  := bFileOpenExec,
    tTimeout  := T#3S,
    bError    => bFileOpenError,
    nErrId    => nFileOpenErrorID);
 
IF bFileOpenError THEN
    F_DoSomethingUsefulHere();        // Handle error here
END_IF

Use return value of a function/method

The return value of a function/method should be used, i.e. queried and evaluated, at the call point of the function/method. This is especially useful if an error value is returned in this way. However, exceptions are also possible where the return value does not have to be used in every call of the function/method.

Static Analysis:

Check with the help of Static Analysis rule:

General program elements for this rule:

(* Function for all samples in this rule: Adds a message to logger system.
   Returns TRUE if successful, FALSE on Error. *)
FUNCTION F_AddLogMessage : BOOL 
VAR_INPUT
    sMessage        : WSTRING;        // Message to be logged 
    dtTimestamp     : DATE_AND_TIME;  // Timestamp of the message
END_VAR

Negative sample:

PROGRAM Sample_neg
VAR
    dtNow           : DATE_AND_TIME;  // Actual system time
END_VAR
// NON COMPLIANT: return value of function will not be used
F_AddLogMessage(sMessage := "Test Message", dtTimestamp := dtNow);

Positive sample:

PROGRAM Sample_pos
VAR
    dtNow           : DATE_AND_TIME;  // Actual system time
    bSendMessageOk  : BOOL;           // Used to check if sending of message was successful
END_VAR
// COMPLIANT: return value of function will be used
bSendMessageOk := F_AddLogMessage(sMessage := "Test Message", dtTimestamp := dtNow);
 
IF NOT bSendMessageOk THEN 
    F_DoSomethingUsefulHere();        // Handle error here
END_IF

Do not call functions/methods within themselves

Functions / methods should not call themselves directly or indirectly, in order to avoid recursions. In programming languages other than IEC61131, recursions should also be used advisedly.

Static Analysis:

Check with the help of Static Analysis rule:

Negative sample:

FUNCTION F_Sample_neg : DWORD
VAR_INPUT
    nFac : DWORD;     // The faculty of this value will be calculated
END_VAR
--------------------------------------------------------------------
IF nFac = 0 THEN 
    F_Sample_neg := 1;
ELSE
    // NON COMPLIANT: implicit recursion. F_Sample_neg_IndirectFac calls F_Sample_neg
    F_Sample_neg := nFac * F_Sample_neg_IndirectFac(nFac := (nFac - 1));
END_IF
--------------------------------------------------------------------
--------------------------------------------------------------------
FUNCTION F_Sample_neg_IndirectFac : DWORD
VAR_INPUT
    nFac : DWORD;     // The faculty of this value will be calculated
END_VAR
--------------------------------------------------------------------
F_Sample_neg_IndirectFac := F_Sample_neg(nFac := nFac);

Positive sample:

FUNCTION F_Sample_pos : DWORD
VAR_INPUT
    nFac : DWORD;     // The faculty of this value will be calculated
END_VAR
VAR
    nTemp   : DWORD;  // Temporary variable used to calculate faculty
    nCount  : DWORD;  // Counter variable used to calculate faculty
END_VAR
--------------------------------------------------------------------
nTemp := 1;
 
IF nFac > 0 THEN 
    FOR nCount := 1 TO nFac DO
        nTemp := nTemp * nCount; 
    END_FOR 
END_IF 
 
F_Sample_pos := nTemp;

 

See also: