ABAP News for Release 7.40 – ABAP Objects
For ABAP Objects itself – meaning the statements for dealing with classes and objects in ABAP – there are two small but nice improvements in Release 7.40.
Parameter Interface of Functional Methods
Before Release 7.40 a functional method could have only importing parameters besides its returning parameter.
A functional method can now have exporting and changing parameters besides its returning parameter.
In functional method calls you can use the additions EXPORTING, IMPORTING, and CHANGING to pass parameters.
Example
The following kind of functional method declaration and invocation was not possible before Release 7.40.
CLASS class DEFINITION.
PUBLIC SECTION.
CLASS-METHODS do_something IMPORTING p1 TYPE i
p2 TYPE i
EXPORTING p3 TYPE i
p4 TYPE i
RETURNING VALUE(r) TYPE i.
ENDCLASS.
…
IF class=>do_something( EXPORTING p1 = 333
p2 = 444
IMPORTING p3 = a1
p4 = a2 ) = 0.
“work with a1, a2
ENDIF.
Interfaces in Test Classes
You know that you have to implement all the methods of each interface that you include in your classes with the INTERFACES statement.While this is OK for normal classes, since the user expects the interfaces to be implemented, it can be become rather tedious in test classes of ABAP Unit. Especially when creating test doubles by implementing interfaces in test classes it is cumbersome to implement (sometimes many, many ) empty interface methods that are not needed for testing. And since empty method implementations are reported by the extended program check, you even have to add a pragma ##needed to each of those!
Fortunately, there is now a new addition PARTIALLY IMPLEMENTED to the statement INTERFACES that can be used in test classes and makes an end to these problems (don’t tell me that you don’t have such problems since you are not testing …).
Example
The following example is an excerpt from an test include of a http-handler class. Since a http-handler normally works with objects like request or response of the ICF-framework, for standalone testing you have to create appropriate test doubles (mock framework) by implementing the according interfaces. In the case shown here, a class for a mock request is created by implementing if_http_request. Before Release 7.40 this was rather awkward, since you had to implement all of the about 50 interface methods! In Release 7.40 you have to implement only those that are needed for testing.
Before Release 7.40
CLASS mock_request DEFINITION FOR TESTING FINAL.
PUBLIC SECTION.
INTERFACES if_http_request.
ENDCLASS.
CLASS mock_request IMPLEMENTATION.
METHOD if_http_request~get_form_field.
value = SWITCH spfli-carrid( name WHEN ‘carrid’ THEN ‘LH’
ELSE space ).
ENDMETHOD.
METHOD if_http_entity~set_cdata. ENDMETHOD. “##needed
METHOD if_http_entity~set_data. ENDMETHOD. “##needed
METHOD if_http_entity~add_multipart. ENDMETHOD. “##needed
METHOD if_http_entity~append_cdate. ENDMETHOD. “##needed
…
ENDCLASS.
Release 7.40
CLASS mock_request DEFINITION FOR TESTING FINAL.
PUBLIC SECTION.
INTERFACES if_http_request PARTIALLY IMPLEMENTED.
ENDCLASS.
CLASS mock_request IMPLEMENTATION.
METHOD if_http_request~get_form_field.
value = SWITCH spfli-carrid( name WHEN ‘carrid’ THEN ‘LH’
ELSE space ).
ENDMETHOD.
ENDCLASS.
Hi,
thank's for posting this blog.
So far I looked forward to the new features of ABAP syntax in 7.40 but allowing exporting and changing parameters in functional methods shocks me a bit! What shall it be good for? Allowing this mix of returning- exporting- and changing-parameters in my optionion just leads to overloading methods with more than one responsibility and causing side-effects.
On the other side the feature "PARTIALLY IMPLEMENTED" let's me shout "Well done SAP!".
Regards,
Dirk
Hi Dirk,
Allowing exporting and changing parameters in functional methods does not mean that you should now go and create extensive parameter interfaces. The programming guideline for slim method interfaces is of course still valid and the ideal method has still some few importing and one returning parameter.
Nevertheless, the technical restriction that a functional method should only have importing parameters besides its returning parameter was a bit severe and needlessly inhibited some very nice patterns. One I have shown above (I used that in my programs, the moment the feature appeared; use case: fetching and checking some internal tables with one returning parameter that tells me, if fetching and checking was succesful).
Another one is method chaining. If you have a class where each instance method returns the self reference me, you can write code without the need of explicit reference variables.
Before 7.40:
DATA in TYPE REF TO if_demo_input.
in = cl_demo_input=>new( ).
in->add_field( CHANGING field = dobj_1 ).
in->add_field( CHANGING field = dobj_2 ).
...
in->request( ).
With 7.40:
cl_demo_input=>new(
)->add_field( CHANGING field = dobj_1
)->add_field( CHANGING field = dobj_2
...
)->request( ).
Horst,
I like method chaining, but not yet in ABAP. For the simple reason that it is still not possible to add the linebreaks at a reasonable place, like so:
cl_demo_input=>new( )
->add_field( CHANGING field = dobj_1 )
->add_field( CHANGING field = dobj_2 )
->request( ).
This would give a syntax error, as well as this:
cl_demo_input=>new( )->
add_field( CHANGING field = dobj_1 )->
add_field( CHANGING field = dobj_2 )->
request( ).
The only version in which method chaining is possible is the one you proposed above, filling the line-break in the parameter list:
cl_demo_input=>new(
)->add_field( CHANGING field = dobj_1
)->add_field( CHANGING field = dobj_2
...
)->request( ).
This looks a bit "broken" to me. Are there plans to allow the other notation?
Regards,
Rüdiger
Hi Rüdiger,
In ABAP there are strict rules, where you must use at least one whitespace (blank character or linebreak) and where you can't. You must use one or more whitespace between tokens (there are enough complaints about this too) but you cannot use a whitesapce within a token and especially not behind or in front of a selector. It is not possible to write "struct - comp", "class => comp", "oref -> comp". That's how it is and currently there are no plans to change that.
One reason is, of course, backward compatibility:
DATA result TYPE string.
DATA struct TYPE string.
DATA -comp TYPE STRING.
CONCATENATE struct -comp INTO result.
Changing the fundamental whitespace rules of ABAP is such a fundamental thing that it cannot be done without a versioning of the language (dream). E.g. a new version where all lists must be comma separated to circumvent ambiguities as above.
Regards,
Horst
I totally agree with Dirk. Working with only methods that have a returning paramter will automatically reduce the size of your methods. Chances are there that if the method can only return 1 thing, it only performs 1 task.
Best regards, Robin.
Hello Horst,
Thanks for the "glimpse" of the ABAP 740.
When using the RETURNING, EXPORTING, It would fun to decide which variables would be returned as RETURNING vs which would be sent back as EXPORTING.
Regarding the PARTIALLY IMPLEMENTED, you have mentioned:
Can it be used out side the Test class - class without addition FOR TESTING?
Thanks,
Naimesh Patel
Why, with RETURNING you define the returning parameter and with EXPORTING you define exporting parameters. You assign the variables to the parameters in the method as you wish.
No, PARTIALLY IMPLEMENTED can be used in test classes only.
Hi Horst,
I'm really excited about the progress of our language. Recently I was able to start using the features of version 7.02 in my clients and I have reduced lines and intermediate variables drastically. I look forward to using the 7.4 features soon.
I have two questions for you:
1. What about operator overloading? Any plans for this?
2. What about basic type boolean? Currently, there is no single mode or standard way to follow. Sometimes i found char types with a flag, others constants with 0/1, others tristate boolean ('-' = False, 'X' = True, space = Undefined)... I think it's quite necessary to ensure homogeneity of code and it can reduce a bit the database costs and space in disk.
Best regards,
Alex
Hi Alex,
Aren't some ABAP operarators not overloaded already since they behave differently for different types? OR what do you wish?
About Boolean, you are not alone http://scn.sap.com/people/horst.keller/blog/2013/06/22/abap-news-for-release-740--new-internal-table-functions#comment-366989
Best
Horst
I'm referring to this operator overloading
Thanks for your reply.
Sure, I looked this up. The "overloading" we have up to now is only for built-in types (e.g. VALUE behaves differently for elementary, structured or table types). But there is no overloading planned for self defined types.
Currently, with logical functions it's possible to omit comparison in IFs:
IF matches( val = lv_text regex = '[[:alpha:]]+' ).
ENDIF.
However, if a method is declared as returning an ABAP_BOOL parameter, it's impossible to write the code the same way:
IF lo_myobj->method( ).
ENDIF.
It would be great to unify boolean functions/methods behaviour. Don't you think so? (;
I think so, but I'm only a documentation writer ..
Well I think that the absence of booleans is not a big thing.
Implementing method overloading in the language is a bigger (wanted) issue...
Hi,
thanks for making this concept more easy....
Hi Horst,
good blog, thanks, always interesting to read up on the new features of ABAP just around the corner. Do you have any plans for an updated version of your ABAP Objects book to include all of these? If so I'll be placing an order...
In fact yes. We're currently writing an ABAP Language Book as successor of ABAP Objects (less tools, less UI, more language) that describes modern expression enabled ABAP and includes the 7.40 stuff. We passed the deadline several times already but I hope to find some time in autumn ...
Excellent, I look forward to that.
I didn't find the following feature in any dream list or wish list by Horst or anybody else:
Custom Predicate Methods
Like system predicate functions, the developer can define methods as predicate methods, by flagging the (new 🙂 ) checkbox "Predicate Method" in the method's attributes view.
Only requirement for setting this flag is that the method has a return parameter of elementary data type CHAR1 (of course, something like FLAG or XSDBOOLEAN will be the concrete data element in all cases).
Predicate methods can be used like system functions in boolean expressions, but it is not necessary to compare their result value with 'X' or space (or ABAP_TRUE or ABAP_FALSE):
Example: If the methods is_variant and allows_variants in the following example are predicate methods, we could write:
if lo_article->is_variant( ) and lo_order->allows_variants( ).
lo_order->insert_variant( lo_article ).
endif.
Regards,
Rüdiger
On a first glance, I have two observations to add:
But I'm informed that our developers are already thinking about a general solution and maybe there will be a general short form
IF expr.
...
ENDIF.
in an upcoming SP.
Best
Horst
This was more than I dared to expect! Looking forward to the SP! (But, yes, I got the "maybe" too).
As fas as I can guess, this might be the forthcoming functionality: The parser detects that the IF condition is not a complete logical expression but a general expression, and auto-completes the generated bytecode to form a logical expression: It will compare the result with 'X' (or additionally use '<> 0' for numerical results?)
Regards,
Rüdiger
Yep, an idea to cut the Gordian knot could be simply a short form:
... expr [IS NOT INITIAL] ...
But what also must be considered: the short form alredy exists!
... [expr IN] seltab ...
-> The parser must exclude expresssions that are selection tables.
Maybe, maybe ...
Best
Horst
For multiple expressions with OR, i like to write this way.
CASE abap_true.
WHEN lo_article->is_variant( ) OR lo_order->allows_variants( ).
lo_order->insert_variant( lo_article ).
ENDCASE.
Hi Manish,
I have seen this idiom elsewhere, but - to state it frankly - I don't like it. It's not natural to put the constant ABAP_TRUE at a place in the code where a decision variable is expected.
In my opinion, the ABAP_TRUE belongs to the right-hand side: The relevant thing is the expression itself. It deserves the higher attention that is spent to the first part of a statement.
Regards,
Rüdiger
I had seen it in radio button handling code. 'X' next to Case, and a number of radiobutton names next to When. At a time only of them would be true.
Yes, admittedly, this is a use case which seems an exception from the rule. Any idea to improve this code is welcome:
case ABAP_TRUE.
when P_RB_USD.
...
when P_RB_CHF.
...
when P_RB_EUR.
...
endcase.
(which is obviously better readable than
if P_RB_USD EQ ABAP_TRUE.
...
elseif P_RB_CHF EQ ABAP_TRUE.
...
elseif P_RB_EUR EQ ABAP_TRUE.
...
endif.
)
Well yes, we know that patterns like the following are widely used:
CASE constant.
WHEN expression1.
...
WHEN expression2.
...
ENDCASE.
But this is not good style and it should be the other way around;
CASE expression.
WHEN constant1.
...
WHEN constant2.
...
ENDCASE.
The new SWITCH operator does not support the first but only second pattern!
OK, for radio buttons or similar scenarios you can write already nowadays :
CASE 'X'
WHEN radio1.
...
WHEN radio2 OR radio3.
...
ENDCASE.
This will not vanish, so why discuss it here?
Note that the above CASE is already a kind of short form, since each WHEN stands for something like
IF 'X' = radio2 OR 'X' = radio3.
...
-> No need/possibility to write CASE/WHEN shorter.
Best
Horst
Thanks for pointing to the new SWITCH syntax.
AFAIS, it doesn't help with the above radiobutton example, though.
Also, in the example from the docu
... = SWITCH string( sy-index
WHEN 1 THEN 'one'
WHEN 2 THEN 'two'
WHEN 3 THEN 'three'
ELSE THROW cx_overflow( ) ).
I don't like the type "string" at the prominent place.
I would be a friend of SWITCH, if the type was optional, like this:
... = SWITCH( sy-index
WHEN 1 THEN 'one'
WHEN 2 THEN 'two'
WHEN 3 THEN 'three'
ELSE THROW cx_overflow( ) ).
since naturally, at the place directly following the SWITCH keyword, we are expecting the decision variable or decision expression, which is the most important part of the switch/case expression.
The type could be inferred automatically, or there could be a default type (STRING, say).
P.S. (edited): Just saw in the docu that the automatic type inference could be used with 'SWITCH # ( sy-index ...'
SWITCH is a constructor operator for constructor expressions. The general syntax is:
... operator type( ... ).
The type can always be specified with # if it can be inferred at the current position.
B.T.W. ABAP News for Release 7.40 - Constructor Operators COND and SWITCH
I spy with my little eye ...
(Sneak Preview 7.40, SP08)
Wow, that's great news!
Will this work like a tacit "IS NOT INITIAL", or does it only work for expression results of data type ABAP_BOOL ?
'xactly. The return value can have any type.
It will not be any expression but functional method calls only.
Hi,
Thanks for your post. It is really helpful.
Hi,
Quite helpful post
!Thanks
In my current fun project Neo4a: The Neo4j ABAP Connector I came across a strange behaviour and I don't know why:
Assume we have a method declared as
The following statement is syntactically correct:
But if I want to use inline declaration on the importing parameter, I'm getting a syntax error:
Is it intended so or a kernel problem?
(NW 7.40 SP8, Kernel 742 SP19)
Inline declarations can be used at write-only positions and - of course not - at read-only positions.
Maybe just a misunderstanding: this is - of course - "importing" from the callers view
.
The same without requesting the RETURNING parameter works:
Oooopsi,
....
I´ll check it out tomorrow.
The reason for that is somewhat hidden in Declaration Positions.
Actual parameters for output parameters and return values of methods for standalone method calls
-> Not for method calls as RHS or in expressions. syntax error in:
DATA(d1) = demo=>main( IMPORTING exp = DATA(d2) ).
In the following case, you also get a syntax error.
IF 1 = demo=>main( IMPORTING exp = DATA(d1) ).
ENDIF.
The compiler interpretes operand positions in expressions always as read-only positions.
The workaround for your case is:
demo=>main(
IMPORTING exp = DATA(d2)
RECEIVING ret = DATA(d1) ).
So, my original answer wasn't too wrong but admittedly too shortsighted
,
Thank you! Never would have guessed.
Finally a "Daseinsberechtigung" (sorry, no English word available: the right to exist) for the keyword RECEIVING
right to exist ....
Hello Horst,
how come this syntax compiles?
and this not?
The whole programm is here.
Without EXPORTING the error message is
Error message
which is obviously not true, because I can put there a method call but with EXPORTING.
Hi.
I also have the following issue with ABAP syntax.
The following code can be activated:
IF _posting_allowed( i_par = COND #( WHEN 1 = 1 THEN 1 ) ) = abap_true.
ENDIF.
But if I remove "= abap_true", we get the message "Error in logical expression".
IF _posting_allowed( i_par = COND #( WHEN 1 = 1 THEN 1 ) ).
ENDIF.
Any ideas?