Using chained statements to imitate varargs in ABAP
In other programming languages (like Java for example) there is a concept called varargs for method parameters. Instead of having to build an array by hand you can just pass your elements separated by a comma to the method and the runtime/compiler will make an array for you and pass it to the method. It looks like this:
public void log(String... entries) {
Arrays.asList(entries).forEach(System.out::println);
}
// Using an array as the actual parameter
String[] entries = {"Log entry one", "Log entry two", "Log entry three"};
log(entries);
// Using varargs
log("Log entry one", "Log entry two", "Log entry three");
In ABAP however there is no concept of varargs. It actually is in conflict with named parameter passing and optional and default parameters. So for the logging method above we would probably write two methods instead, one taking only a single log entry as an argument and the other taking a table of log entries so that the caller does not need to wrap the method call in a loop, like this:
CLASS lcl_logger DEFINITION.
PUBLIC SECTION.
CLASS-METHODS:
log IMPORTING iv_text TYPE string,
log_table IMPORTING it_entries TYPE stringtab.
ENDCLASS.
CLASS lcl_logger IMPLEMENTATION.
METHOD log.
WRITE: / iv_text.
ENDMETHOD.
METHOD log_table.
LOOP AT it_entries ASSIGNING FIELD-SYMBOL(<lv_text>).
log( <lv_text> ).
ENDLOOP.
ENDMETHOD.
ENDCLASS.
With 7.40 ABAP syntax the log_table
-call is not too bad, as you can just initialize the internal table inline using the VALUE
statement, like this:
log_table( VALUE #( ( `Log entry one` ) ( `Log entry two` ) ( `Log entry three` ) ) ).
But there is also another possibility which does not need the log_table
-method at all. I have never seen it in any ABAP code until I recently randomly saw a code section in an ABAP book where a chained statement was used in a functional method call, which I did not even know was possible. With that you could do something like this:
log(:
`Log entry one` ),
`Log entry two` ),
`Log entry three`
).
This is not technically related to varargs because at compilation the chained statement will just be split up in individual method calls and the method will be called three times. However, the syntax for the call looks similar and there might be some situations where it could be easier to read or maintain than individual method calls or wrapping them in a helper method.
A word of warning though. In the programming guidelines for chained statements there is a chapter on method calls where it warns you about using them with more advanced interfaces or techniques. For example returning parameters and expressions using them especially with inline declarations in interaction with chained statements will lead to unexpected behavior.
Here’s a more advanced example using CL_SALV_TREE
-methods. One can argue if it increases or decreases readability and maintainability.
mo_object_tree->get_columns( )->get_column(:
'OBJECTNAME' )->set_visible( abap_false ),
'COMPONENT' )->set_visible( abap_false ),
'COMPONENTTYPE' )->set_visible( abap_false ),
'PARENTCOMPONENT' )->set_visible( abap_false )
.
Wow! I did not know that it was possible at all...
Actually i prefer the style used in the CL_DEMO_OUTPUT(see interface IF_DEMO_OUTPUT) class. The self-reference("me") is the RETURNING param in the method calls. The developer can keep on chaining to his/her content 🙂
IMO the problem with such a construct is debugging, esp. if you wanna debug a specific method. You would have to step through all the preceding methods until you reach the reqd. point.
BR,
Suhas
I agree, classes using the builder pattern are always a pleasure to use, however I have yet to find one in the wild (with the exception of cl_demo_output). Probably because they are quite time-consuming to implement (internal state validation is needed at each method call, for example no end_section before begin_section was called etc.).
Hello Fabian,
I would define two OPTIONAL parameters in a single method, using a logic based on IS_SUPPLIED to check the actual case.
regards,
JNN
You can certainly do that for the two example methods.
Using two optional parameters for either fill the first or the second one does bring some problems with it though, like the dreaded illegal parameter combination exception, additional complexity in unit testing and wrapper methods not working as intended because of IS SUPPLIED being masked by the default values of the wrapper method.
That why I personally prefer the do_something_by_name do_something_by_ref approach (for lack of method overloading in ABAP) which does give you compile time safety in comparison to a runtime parameter validation in a single method.
Good stuff, Thanks 🙂
Thank you for showing the different ways of doing this. For me it's debug "able". Is it easier to debug one way than the other. My guess is that it depends on what you are used to.
Michelle
Good stuff, I used and worked for me.
amazing thanks for sharing
rofile