Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Challenge of best writing "IF country IN ('FR','DE','BE','IT')" inside IF / without CASE

Sandra_Rossi
Active Contributor

Hello,

this is a question and a challenge at the same time 😉

I'd like your opinion about the best writing of a case inside a IF condition, to avoid repeating the same variable again and again:

IF country = 'FR' OR country = 'DE' OR country = 'BE' OR country = 'IT'.<br>ENDIF.

Best writing means a best combination of easy to write and to maintain, short, performing, smart, etc., but of course it's completely subjective, there's no good and bad answer, except people will prefer one or another.

There is no straight ABAP construct to simplify it except CASE, which cannot be used inside IF, but there are many workarounds, which one do you prefer and use?

The challenge is to NOT use CASE, as shown here:

CASE country.
  WHEN 'FR' OR 'DE' OR 'BE' OR 'IT'.
ENDCASE.

For information (in case you're looking for it): Clean ABAP - Prefer CASE to ELSE IF for multiple alternative conditions.

Have fun!

Sandra

PS: no price to win 😉

16 REPLIES 16

chaouki_akir
Contributor

I think I would move values to a range.

REPORT zza.
PARAMETERS country TYPE char2.
DATA eu_countries TYPE RANGE OF char2.

LOAD-OF-PROGRAM."
eu_countries = VALUE #( ( sign = 'I' option = 'EQ' low = 'FR' )
( sign = 'I' option = 'EQ' low = 'DE' )
( sign = 'I' option = 'EQ' low = 'BE' )
( sign = 'I' option = 'EQ' low = 'IT' )
).

START-OF-SELECTION.
IF country IN eu_countries.
message i000(38) with country 'is in Europe'.
ENDIF.

jack_graus2
Active Contributor
0 Kudos
IF country CA |{ 'FR' }{ 'DE' }{ 'BE' }{ 'IT' }|.
ENDIF.

0 Kudos

I guess this one is really a bad idea = true for any country code containing one of these characters B, D, E, F, I, R or T 😉

jack_graus2
Active Contributor

A variant on the answer of chaouki.akir:

TYPES:
tt_country TYPE RANGE OF country.

IF country IN VALUE tt_country(
sign = 'I'
option = 'EQ'
( low = 'FR' )
( low = 'DE' )
( low = 'BE' )
( low = 'IT' ) ).
ENDIF.

fedaros
Advisor
Advisor
0 Kudos

Hi sandra.rossi Trick question.

I don't like to go against best practices but is necessary need to understand what they want to do, to properly ignore it where follow may reach a worst situation.

The guidance is to prefer CASE instead IF to keep code clean, but in my opinion it only make sense to cover cases like one option exclusive... CASE A, B, C, D... not with OR's because this can have an additional pattern point to "groups".

Extending the situation of OR's, I may reach "groups" of countries and in such scenario I may prefer IF/ELSIF + RANGE keep my clear, concise and reusable as I probably need this information of groups used elsewhere.

IF country in lr_Europe.
ELSIF country in lr_America.
ELSIF country in lt_Asia.

ENDIF.

Regards, Fernando Da Rós

fedaros
Advisor
Advisor

Follow another option that I may use in rare scenarios, but in my opinion is worst than range:

DATA(country) = CONV t005-land1( 'FR' ).
DATA(lv_temp) = |*{ country };*|.
IF 'FR;DE;BE;IT;' CP lv_temp.
ENDIF.

0 Kudos

It doesn't seem to work:

DATA(country) = CONV t005-land1( 'FR' ).
DATA(lv_temp) = |{ country };*|.
IF lv_temp CP 'FR;DE;BE;IT;'.
  WRITE |{ Country } is part of FR;DE;BE;IT;|.
ELSE.
  WRITE |{ Country } is NOT part of FR;DE;BE;IT;|.
ENDIF.

Sorry, due to missing code/test I didn't catch my two mistakes, follow a code that works:

  DATA(country) = CONV t005-land1( 'FR' ).
  DATA(lv_temp) = |*{ country };*|.
  IF 'FR;DE;BE;IT;' CP lv_temp.
    WRITE |{ country } is part of FR;DE;BE;IT;|.
  ELSE.
    WRITE |{ country } is NOT part of FR;DE;BE;IT;|.
  ENDIF.

Is it possible that you update directly your answer, just to clarify at the source? Thanks!

Tomas_Buryanek
Active Contributor
IF is_country_eu( country ).
ENDIF.
-- Tomas --

Sandra_Rossi
Active Contributor

Hi fedaros, sure.

I don't think there's just one "best way" to organize the code. So, sometimes it may looks better to use one way, sometimes another way. I guess it should be discussed one example at a time, and finally deduce the rules and preferred ways if there are some agreements (like it's done in the Clean ABAP guide).

Business rules are sometimes very complex, so making indented would be against this other Clean ABAP rule: Keep the nesting depth low.

A workaround is possibly using BRF+ or any other business rule management system.

Sandra_Rossi
Active Contributor

Proposal after ideas from chaouki.akir, jack.graus2, tomas.buryanek and fedaros:

IF in_list( val = country list = |{ 'FR' };{ 'DE' };{ 'BE' };{ 'IT' }| sep = ';' ).
ENDIF.

Ryan-Crosby
Active Contributor

As you had stated that business rules can sometimes be very complex (and also subject to change), I would potentially opt for BRF+ depending on what needs to happen inside the IF. Call BRF+ and as long as my contract for inputs/outputs does not require change (requires some forethought/assumption), then the resulting actions be modified without ever having to recompile the program.

joltdx
Active Contributor

Regular expressions are rarely easy to read and maintain, but this simple example might be an exception

IF matches( val = country regex = 'FR|DE|BE|IT' ).
ENDIF.

Sandra_Rossi
Active Contributor
0 Kudos

Hmmm nice but alas the performance of POSIX regular expressions is really very bad... Possibly PCRE (from ABAP 7.55), would be interesting to see what is its performance compared to a simple IF/CASE.

Sandra_Rossi
Active Contributor

This is a summary of all answers. I'll try to update and add indicators of performance, legibility, maintainability, etc.

  1. IF country IN countries. (countries = VALUE #( sign = 'I' option = 'EQ' ( low = 'FR' )...) chaouki.akir Link
  2. IF country IN VALUE tt_country( sign = 'I' option = 'EQ' ( low = 'FR' )... jack.graus2 Link
  3. IF 'FR;DE;BE;IT;' CP |*{ country };*|. fedaros Link
  4. IF matches( val = country regex = 'FR|DE|BE|IT' ). jorgen_lindqvist41 Link
  5. IF is_country_eu( country ). tomas.buryanek Link
  6. Use BRF+ ryan.crosby2 Link
  7. IF in_list( val = country list = |{ 'FR' };{ 'DE' };{ 'BE' };{ 'IT' }| sep = ';' ). sandra.rossi Link
  | Example code                              |
──┼───────────────────────────────────────────┼
1 | • DATA countries TYPE RANGE OF land1.     |
  | • countries = VALUE #( sign = 'I' option  |
  |   = 'EQ' ( low = 'FR' ) ( low = 'DE' ) ). |
  | • IF country IN countries.                |
──┼───────────────────────────────────────────┼
2 | IF country IN VALUE tt_country(           |
  |   sign = 'I' option = 'EQ' ( low = 'FR' ) |
  |   ( low = 'DE' ) ).                       |
──┼───────────────────────────────────────────┼
3 | IF 'FR;DE;' CP |*{ country };*|.          |
──┼───────────────────────────────────────────┼
4 | IF is_country_eu( country ).              |
──┼───────────────────────────────────────────┼
5 | IF matches( val = country regex =         |
  |     'FR|DE|BE|IT' ).                      |
──┼───────────────────────────────────────────┼
6 | Use BRF+                                  |
──┼───────────────────────────────────────────┼
7 | IF in_list( val = country list =          |
  |     |{ 'FR' };{ 'DE' };|.                 |