Function Modules, Methods and Type Safety
Contents
The main reason to have a static type system in a programming language is that the compiler can catch your mistakes without having to execute the code. In ABAP, even this is not so straightforward.
Weak, Static Types
ABAP has weak, static types. Implicit type conversions are easy:
|
|
An integer easily converts to a string and can still be used like an integer afterwards. As a comparison, Erlang has strong, dynamic types (and also single assignments):
|
|
In Erlang, converting a type to another requires a function that takes the source type and returns the destination type, or fails. The possibility that a conversion fails, of course, exists in ABAP also, it’s just not as explicit (ie. does not look like a function call):
|
|
…Except When Types Are Enforced
However, implicit conversions don’t apply universally. This snippet:
|
|
will fail to compile with the following error message:
In PERFORM or CALL FUNCTION “SUBROUTINE”, the actual parameter “LV_INTEGER” is incompatible with the formal parameter “IM_STRING”.
Ie. an integer is not a string and will not be automatically converted to one. This makes sense and is fairly intuitive. What also makes sense, but is less intuitive, is how methods in classes work:
|
|
This will fail to compile with the following message:
“LV_INTEGER” is not type-compatible with formal parameter “IM_STRING”.
Ie. an integer is not a string and will not be automatically converted to one, more or less how parameters also work in FORM
. The reason why I describe this as less intuitive comes down to the syntax: elsewhere in code =
means that an implicit conversion will take place, except here in a method call, parameter = value
may look identical to a normal assignment, but will not behave like one. I appreciate that the sanity check happens, but more than once I have been surprised to get the compile error.
…Except When Types Are Not Enforced
It wouldn’t be ABAP if there wasn’t an exception to the above rule. The following compiles:
|
|
But crashes at runtime:
Type conflict when calling a FORM.
Which makes sense since neither the existence of the subroutine:
Call (PERFORM) to a non-existent external routine.
Nor the existence of the report it should be contained in is checked:
Program “ZREPORT2” not found.
Ie. when the called subroutine exists in a different report, compilation provides no guarantees about anything. Only runtime execution will tell the truth.
Something similar goes on with function modules. The following compiles:
|
|
But crashes at runtime:
Type conflict during a function module call
Ie. an integer is not a string and will not automatically be converted to one and we’ll only tell you this at runtime, and only if you happen to execute the function module. The existence of the function module is only checked at runtime, too.
This means that a function module on a rare code path can crash the day it is finally executed for the first time. It also means that changing the type of a variable or an attribute can turn a previously working function module call into a crashing one and that this will only be apparent at runtime (ie. could be too late). And it also means that changing the parameters of a function module can also produce these crashes without any warning.
We have static types, but they are only enforced at runtime.
SAP does have a feature called “Extended Check” that will catch these errors:

Extended Check


But running this check is off the normal “write code-compile-run” path and can be hard to remember to run without a disciplined use of a checklist. And it also doesn’t really effectively catch errors that would be caused by changes to classes or function modules (as the clients are spread far and wide).
Generic Types
There are unfortunately also options for subverting type safety in methods:
|
|
CSEQUENCE
is a generic type that accepts a char-type or a string, with other types producing the normal “is not type-compatible with formal parameter” compilation error. another_static_method
also accepts it as a parameter, since it could well contain the required type (CHAR20
). The obvious question is: “What if im_generic
is an incompatible type?”
The answer is that the program will compile and will then crash at runtime:
Type conflict in method call.
The method accepting the generic type should immediately convert the input into some specific type to regain type safety, except in the cases that the methods it calls also explicitly accept the same generic type. Using the parameter in its generic form bypasses type checks and results in a situation where whether the method crashes or not will be entirely up to the parameter that the caller happens to use and these different behaviors will only be apparent at runtime. Even worse, Extended Check will not catch these cases.