Skip to Content
Author's profile photo Jörg Krause

Functional programming in ABAP – immutable variables

I know the title is confusing – of course no functional programming is possible in ABAP. But lately I read a bit about it and I try to adopt some things that seem useful to me. When I read about immutable objects or pure functions (no side effects) for the first time, It seemed very strange to me. In fact, going back to BASIC programming in school, the possibility to change a variable seemed to be the key capability of a computer program. But immutable does not seem that a variable is a constant – it can have different values every time the program runs. But during one run, it is only set once.

Applying this technique, we maybe have to use much more variable declarations as before, so what do we get in return for this effort`?

Look at this code snippet:

    types:
      begin of lty_s_material,
        material type string,
        description type string,
      end of lty_s_material,
      begin of lty_s_bom,
        header type lty_s_material,
        component type lty_s_material,
      end of lty_s_bom,
      lty_t_bom type standard table of lty_s_bom with default key.

    data(ls_material) = value lty_s_material(
      material = 'COMP'
      description = 'Computer' ).
    data(lt_bom) = value lty_t_bom(
      ( header = ls_material
        component = value #( material = 'SCR'
                             description = 'Screen' ) )
      ( header = ls_material
        component = value #( material = 'CPU'
                             description = 'Central processing unit' ) )
      ( header = ls_material
        component = value #( material = 'KYBD'
                             description = 'Keyboard' ) ) ).

    cl_demo_output=>write( 'Components of material :' && ls_material-material ).
    " fetch the first component
    ls_material = lt_bom[ 1 ]-component.
    cl_demo_output=>write( '1st Component :' && ls_material-material ).
    ls_material = lt_bom[ 2 ]-component.
    cl_demo_output=>write( '1st Component :' && ls_material-material ).
    ls_material = lt_bom[ 3 ]-component.
    cl_demo_output=>write( '1st Component :' && ls_material-material ).

    cl_demo_output=>display( ).

Here, I reuse a variable (ls_material) many times for different data sources. If you imagine this to be a real program with some more lines, this gets very confusing for a human that reads it. To figure out what ls_material stands for, one has to find always the last value assignment.The problem increases enormously when variables are global and can be changed throughout all methods (see The Global Variable Dilemma).

To avoid all this confusion, it’s better to use different variables

    data(ls_header_material) = value lty_s_material(
      material = 'COMP'
      description = 'Computer' ).
    data(lt_bom) = value lty_t_bom(
      ( header = ls_header_material
        component = value #( material = 'SCR'
                             description = 'Screen' ) )
      ( header = ls_header_material
        component = value #( material = 'CPU'
                             description = 'Central processing unit' ) )
      ( header = ls_header_material
        component = value #( material = 'KYBD'
                             description = 'Keyboard' ) ) ).

    data(ls_first_component) = lt_bom[ 1 ]-component.
    cl_demo_output=>write( '1st Component :' && ls_first_component-material ).
    data(ls_second_component) = lt_bom[ 1 ]-component.
    cl_demo_output=>write( '1st Component :' && ls_second_component-material ).
    data(ls_third_component) = lt_bom[ 1 ]-component.
    cl_demo_output=>write( '1st Component :' && ls_third_component-material ).

In this snippet, the variable names already reflect very well what they stand for and no variable is overwritten.

Of course, with the new expressions that ABAP introduced from 740 on, variable creation itself can be avoided:

    cl_demo_output=>write( '1st Component :' && lt_bom[ 1 ]-component-material ).
    cl_demo_output=>write( '1st Component :' && lt_bom[ 2 ]-component-material ).
    cl_demo_output=>write( '1st Component :' && lt_bom[ 3 ]-component-material ).

And this is, what I try to do as often as possible. A good variable is a variable that will not change. A better variable is no variable at all 🙂

Of course you can not always avoid changing a variable. It is often necessary when building sums in loops or when you count something. But if you keep in mind that you possibly do not want to change variable values after having them set once, you will get more robust code.

Assigned Tags

      8 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Jacques Nomssi Nzali
      Jacques Nomssi Nzali

      Hello Jörg,

      you makes a good point here: immutables make it easier to reason about the code. And without side effects, you are not forced to debug that often.

      I seem to always see a problem when you write "of course"

      • of course no functional programming is possible in ABAP.
        • Hmm, I will try hard to prove you wrong:
          • there are aspect of functional programming you can use in ABAP, but they are not enforced by the language. It is like the best practice of initializing variables before usage. You can do it "manually" without language support or use a constructor with language support.
          • You could implement a functional framework in ABAP and use it (cf. ABAP LISP / Scheme)
      • Of course you can not always avoid changing a variable.
        • Actually, with functional programming techniques (e.g. pure functions and recursion). you can: this code generates the same output as yours without loop and with only immutable variables:
          lcl_output=>display( it_bom = lt_bom
                               index = 1 ).

          given:

      CLASS lcl_output DEFINITION.
        PUBLIC SECTION.
          CLASS-METHODS display IMPORTING it_bom TYPE lty_t_bom
                                          index TYPE i.
      ENDCLASS.
      
      CLASS lcl_output IMPLEMENTATION.
      
        METHOD display.
          CHECK index BETWEEN 1 AND 3.
          cl_demo_output=>write( '1st Component :' && lt_bom[ index ]-component-material ).
          display( it_bom = it_bom
                   index = index + 1 ).
        ENDMETHOD.
      
      ENDCLASS.

      best regards,

      JNN

       

      Author's profile photo Jörg Krause
      Jörg Krause
      Blog Post Author

      I wrote "... no functional programming is possible ... " because ABAP can not treat functions as variables. But you are right: some aspects of functional programming have been implemented lately in ABAP.

      Concerning the variable changes: Using recursion for iterating is not practicable for large tables. The call stack will overwhelm. Since SAP is often about large data amounts, I insist on my affirmation: you can not always avoid changing variables. 😉

      Author's profile photo Enno Wulff
      Enno Wulff

      of course no functional programming is possible in ABAP.

      see here: https://blogs.sap.com/2017/02/26/functional-programming-simulate-curry-in-abap/

      Author's profile photo Jörg Krause
      Jörg Krause
      Blog Post Author

      Thanks Enno, I knew this post before...

      This is a framework to simulate functional programming using dynamic code generation. I do not consider this as a functional programming capability of ABAP.

      Author's profile photo Enno Wulff
      Enno Wulff

      Yes, you are right! I wasn't aware that it uses code generation...

      Author's profile photo Joachim Rees
      Joachim Rees

      Hi Jörg,

      not sure if I got the concept right or maybe missed something:

      So an immutable variable is set once (per program run) and then cannot be changed anymore (during this run);

      I see how this knowledge ("value will not change") can be helpful when debugging, but I don't see how in your 2nd example this is enforced:

      Without looking at the context, you can’t be sure, that variable ls_first_component-material is not changed somewhere else in the code, can you?

       

      So your point probably is: there's no way to enforce the concept in ABAP, but you can benefit from it by convention (as you did in your 2nd example, with using 3 different variables), right?

       

      best
      Joachim

       

      Author's profile photo Jörg Krause
      Jörg Krause
      Blog Post Author

      Yes, you are right. To me, not changing variables is a matter of programming style. Wherever I can, i create my variables with a "VALUE #" expression for initial population (this is not possible when a method with generic typed output is populating the var). With that, a directive like "lv_my_var = something_else" can be considered evil and should no longer appear in the coding.

      However, there is a possibility to prevent a variable from being changed: declare it as a public read-only attribute of a data provider class (see blog The Global Variable Dilemma). Then use the data provider class in a local variable, which would blow up the code. So I prefer the "programming style" solution.

      Author's profile photo Joachim Rees
      Joachim Rees

      Hey Jörg,

      thanks for clarifying! I vaguely remembered the Blog "Global Variable Dilemma", and no see that I even already commented on it 🙂

      best
      Joachim