The require-return-values compiler option performs static analysis to verify that all logical code paths in ABL user-defined functions, non-VOID methods, and property getters include RETURN value statements. This helps developers to identify missing RETURN value statements during compilation, reducing the chance of runtime errors and improving overall code reliability. Omitting a RETURN value may result in unexpected behavior and make debugging more difficult. Using this option during development can highlight potential issues before they become runtime errors, and it can also assist in troubleshooting by revealing fragile code that may not behave as intended.

Enabling the option and identifying violations

To enable the feature, use the require-return-values compiler option. For information on enabling compiler options, see Set compiler options.

During compilation, if the option is enabled and a violation is detected, a message is displayed:
All code paths in user-defined function, method, or property getter "name" must return a value due to the "require-return-values" compiler option. (19822)

The message identifies the name of the user-defined function, method, or property getter with the violation. It does not identify which path or line is missing the RETURN value statement. You need to examine your code to determine how to make the appropriate fixes.

User-defined function, non-VOID method, or property getter block

If there are no control flow statements within the user-defined function, non-VOID method, or property getter, then the main block of the user-defined function, non-VOID method, or property getter requires a RETURN value statement. The following example shows a user-defined function that is not compliant with the require-return-values compiler option:

/* basic.p */
/* Not compliant with require-return-values */

FUNCTION retint RETURNS INTEGER ():

    MESSAGE "function retint".
    
END FUNCTION.

MESSAGE "function return" STRING(retint()).

Add a RETURN value statement to clear the warning/error, as shown in the following example:

/* basic.p */
/* Compliant with require-return-values */

FUNCTION retint RETURNS INTEGER ():

    MESSAGE "function retint".
    RETURN 1.
    
END FUNCTION.

MESSAGE "function return" STRING(retint()).

As long as the user-defined function, non-VOID method, or property getter ends with a RETURN value statement, then the code is compliant. If it does not end with a RETURN value statement, then you must make sure all other code paths are compliant.

Verifying all other code paths provide a RETURN value statement involves control flow analysis of ABL programs.

Verifying other code paths are compliant

As stated previously, you simply need to end each user-defined function, non-VOID method, or property getter with a RETURN value statement in order to make your code compliant. However, if this is not desired, then you can add RETURN value statements to other constructs. The following sections describe different statements that alter the flow from within ABL and how the require-return-values compiler option affects them. Before and after code examples are shown, along with information on how to make the code compliant. The assumption is that the containing user-defined function, method, or property getter does not end with a RETURN value statement, so other statements and blocks must be made compliant instead.

IF…THEN…ELSE statement

In an IF...THEN...ELSE statement, both the IF and ELSE portions require a RETURN value statement. Having one within either, but not both, never satisfies the require-return-values option. If you only have an IF clause, then you must add an ELSE clause and include a RETURN value statement for both.

    /* Not compliant with require-return-values */
    DEFINE VARIABLE boolVar AS LOGICAL NO-UNDO INITIAL FALSE.
    
    IF boolVar THEN
        RETURN 1.

    /* Compliant with require-return-values */
    DEFINE VARIABLE boolVar AS LOGICAL NO-UNDO INITIAL FALSE.
    
    IF boolVar THEN
        RETURN 1.
    ELSE
        RETURN 0.

CASE statement

In a CASE statement, there must be an OTHERWISE clause that includes a RETURN value statement, and all WHEN..THEN clauses must also contain a RETURN value statement.

    /* Not compliant with require-return-values */
    DEFINE VARIABLE casetest AS INTEGER NO-UNDO INITIAL 3.
    
    CASE casetest:
        WHEN 1 THEN
            RETURN 2.
        WHEN 2 THEN  
            RETURN 4.
    END CASE.

    /* Compliant with require-return-values */
    DEFINE VARIABLE casetest AS INTEGER NO-UNDO INITIAL 3.
    
    CASE casetest:
        WHEN 1 THEN
            RETURN 2.
        WHEN 2 THEN  
            RETURN 4.
        OTHERWISE
            RETURN 0.
    END CASE.

Nested control flow statements

Control flow statements can appear within each other. As long as each inner statement or block is compliant, then the outer statement or block is also compliant. To satisfy the require-return-values compiler option, it must be the case that there are no statements after the block.

Limitations of control flow and exception handling

The require-return-values compiler option performs static control flow analysis. It does not evaluate runtime conditions or rely on exception handling. As a result:

  • CATCH and FINALLY blocks do not satisfy the requirement.
  • A THROW statement at the end of a method is not considered a valid substitute for a RETURN statement.

    To resolve the compiler warning, you must include a RETURN value statement in all code paths, even if some paths end in THROW. For example:

    ...
      UNDO, THROW NEW Exceptions.ERecordNotFound("Record not found").
      RETURN "". /* Unreachable but required for compiler */
    END METHOD.
Additionally, the compiler assumes that any conditional path can fail, so constructs like:
IF condition THEN RETURN value.
IF NOT condition THEN RETURN value.
do not guarantee compliance. You must include an ELSE RETURN value or a fallback RETURN value statement to make sure that all logical paths return a value.

By requiring explicit RETURN value statements in all code paths, the require-return-values compiler option promotes predictable behavior and helps reduce the likelihood of runtime errors caused by missing return values.