Skip to Content
Technical Articles
Author's profile photo Raden Prabowo

Functional Programming in ABAP Series: PART I (Introduction)

Background

In computer coding, it’s super important to write really good code. Good code doesn’t just make programs run faster, it also helps developers work better. But figuring out what makes code good can be tricky, and it’s not just about making things run quickly.

Good code has things like being easy to test, easy to keep up, easy to use again, and easy to add more stuff to. These things are like measuring sticks for how tough and reliable the code is. But knowing how to make code like that isn’t always clear, so we look into ways to help us write clean code.

One cool way to do this is by using functional programming. It’s a style of coding inspired by math, and it’s all about using expressions and putting functions together. We separate pure functions, which only do one thing and don’t mess with anything else, from impure ones, which do more things. This helps make our code not just easy to understand but also makes testing and modifying way simpler.

In ABAP (a programming language), Object-Oriented ABAP is a great way to use functional programming ideas. It’s not a perfect solution for everything, but it really helps us think about problems in new ways.

Functional Programming in A Nutshell

Functional programming is programming using functions.
Functional programming is like building with LEGO blocks, combining functions to build a new and different use of function.

Let’s take a look at the provided Haskell code examples, showcasing the essence of functional programming:

even :: (Integral a) => a -> Bool
even x
   | x `mod` 2 == 0 = True
   | otherwise = False

Here, I’ve defined a function called even that takes an integral value, x, and returns a boolean indicating whether x is even. I’ve used guards (|) to make the code concise and expressive which is the main characteristic of functional programming.

odd :: (Integral a) => a -> Bool
odd = not . even

In this example, I leverage the composition operator (.) to define the odd function succinctly. I take advantage of the previously defined even function, showcasing the power of composing functions to create new ones.

filter :: (a -> Bool) -> [a] -> [a]
filter _ [] = []
filter pred (x:xs)
 | pred x = x : filter pred xs
 | otherwise = filter pred xs

The filter function showcases a common higher-order function in functional programming. I take a predicate function,, and a list of any type [a], returning a new list containing only the elements that satisfy the predicate. This serves as a clear example of functional programming’s emphasis on using higher-order functions for concise and expressive code.

In this function, I highlight the recursive technique — a fundamental aspect of functional programming. Recursion is not only a technical approach but also a distinctive way of thinking. Embracing recursion allows me to break down complex problems into simpler, more manageable sub-problems, fostering code elegance and a deeper understanding of functional programming principles.

ghci> filter odd [1..100]
[1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99]
ghci> filter even [1..100]
[2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100]

These examples demonstrate Haskell’s functional programming features, emphasizing the concise and declarative nature of the code. The use of higher-order functions, immutability, and function composition contributes to the readability and maintainability of the codebase. These principles form the basis for our exploration of functional programming in Object-Oriented ABAP in the subsequent sections.

INTERFACE zif_predicate
  PUBLIC .

  METHODS evaluate IMPORTING value      TYPE any
               RETURNING VALUE(result) TYPE abap_bool.

ENDINTERFACE.

The zif_predicate interface serves as a contract or blueprint for classes that implement a specific method signature, in this case, the evaluate method. I’ve defined it to establish a common contract that the zcl_predicate_even and zcl_predicate_odd classes adhere to.

The purpose of this interface is to declare a method, evaluate, that takes a value and returns a boolean result. Its usage lies in ensuring that all classes implementing this interface adhere to a consistent contract. In this context, I use the interface to implement a higher-order function through the application of dependency injection.

even :: (Integral a) => a -> Bool
even x
   | x `mod` 2 == 0 = True
   | otherwise = False

ABAP

CLASS zcl_predicate_even DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
   INTERFACES zif_predicate.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_predicate_even IMPLEMENTATION.
  METHOD zif_predicate~evaluate.
   FIELD-SYMBOLS <value> TYPE i.
   ASSIGN value TO <value>.
   result = COND #( WHEN <value> MOD 2 = 0
                    THEN abap_true
                    ELSE abap_false ).
  ENDMETHOD.
ENDCLASS.

In both languages, I’ve defined a predicate to check if a number is even. The ABAP implementation uses an interface zif_predicate to establish a common contract and the evaluate method mirrors the Haskell logic. Additionally, I exemplify the application of dynamic programming in ABAP to adeptly handle generic data types, which is common in the functional programming world.

odd :: (Integral a) => a -> Bool
odd = not . even

ABAP

CLASS zcl_predicate_odd DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
  INTERFACES zif_predicate.
  PROTECTED SECTION.
  PRIVATE SECTION.
  METHODS negate IMPORTING truth TYPE abap_bool
              RETURNING VALUE(result) TYPE abap_bool.
ENDCLASS.

CLASS zcl_predicate_odd IMPLEMENTATION.
  METHOD zif_predicate~evaluate.
   result = negate(
             CAST zif_predicate(
               NEW zcl_predicate_even( )
                 )->evaluate( value = value ) ).
  ENDMETHOD.

  METHOD negate.
   result = COND #( WHEN truth = abap_true
                 THEN abap_false
                 ELSE abap_true ).
  ENDMETHOD.
ENDCLASS.

Here, I define the odd predicate in Haskell by negating the even predicate. In ABAP, I encapsulate this logic in the zcl_predicate_odd class, which internally leverages the zcl_predicate_even class to evaluate evenness and then negate it. In this part, I use function composition in both languages. In functional programming, I believe function composition is the key to handling complexity.

filter :: (a -> Bool) -> [a] -> [a]
filter _ [] = []
filter pred (x:xs)
 | pred x = x : filter pred xs
 | otherwise = filter pred xs

ABAP

CLASS zcl_filter DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
 METHODS get_filtered IMPORTING predicate  TYPE REF TO zif_predicate
                                value_tab  TYPE ANY TABLE
                      RETURNING VALUE(result) TYPE REF TO data.

  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_filter IMPLEMENTATION.
  METHOD get_filtered.
   FIELD-SYMBOLS <result_tab> LIKE value_tab.
   CREATE DATA result LIKE value_tab.
   ASSIGN result->* TO <result_tab>.
   LOOP AT value_tab ASSIGNING FIELD-SYMBOL(<value>).
     IF predicate->evaluate( <value> ) = abap_false.
       CONTINUE.
     ELSE.
       INSERT <value> INTO TABLE <result_tab>.
     ENDIF.
   ENDLOOP.
  ENDMETHOD.
ENDCLASS.

In both languages, I’ve implemented the filter function as a higher-order function. In Haskell, it operates on lists, and in ABAP, it uses a generic table structure. The ABAP implementation defines a class zcl_filter that takes a predicate and a table of values, returning a filtered result.

In imperative programming languages, including ABAP, I always prefer to use loops over recursive methods. Handling generic data here becomes more complex but still acceptable. In this method, I observe the utilization of higher-order functions in ABAP through the implementation of dependency injection.

While in functional programming, functions are considered first-class citizens, in Object-Oriented Programming (OOP), objects take on this primary role.

CLASS zcl_demo_fp DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
 INTERFACES if_oo_adt_classrun.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_demo_fp IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
   TYPES ty_t_integer TYPE STANDARD TABLE OF i WITH EMPTY KEY.
   DATA(filter) = NEW zcl_filter( ).
   DATA(even) = CAST zif_predicate( NEW zcl_predicate_even( ) ).
   DATA(odd) = CAST zif_predicate( NEW zcl_predicate_odd( ) ).
   DATA value_tab TYPE ty_t_integer.

   " get even number from 1 to 100
   out->write( `Even Numbers` ).
   DATA(even_number) = filter->get_filtered(
                       predicate = even
                       value_tab = VALUE ty_t_integer( FOR i = 1 THEN i + 1 UNTIL i = 100
                                                       ( i ) )
                     ).

   ASSIGN even_number->* TO FIELD-SYMBOL(<even_number>).
   IF <even_number> IS ASSIGNED.
     value_tab = CORRESPONDING #( <even_number> ).
     DATA(string_even) = REDUCE string( INIT evens TYPE string
                                      FOR <even> IN value_tab
                                      NEXT
                                      evens = COND #( WHEN evens IS INITIAL
                                                      THEN <even>
                                                      ELSE |{ evens }, { <even> }| ) ).
     out->write(
       EXPORTING
         data   = |[{ string_even }]| ).
   ENDIF.

   " get odd number from 1 to 100
   out->write( `Odd Numbers` ).
   DATA(odd_number) = filter->get_filtered(
                       predicate = odd
                       value_tab = VALUE ty_t_integer( FOR i = 1 THEN i + 1 UNTIL i = 100
                                                       ( i ) )
                     ).

   ASSIGN odd_number->* TO FIELD-SYMBOL(<odd_number>).
   IF <odd_number> IS ASSIGNED.
     CLEAR value_tab.
     value_tab = CORRESPONDING #( <odd_number> ).
     DATA(string_odd) = REDUCE string( INIT odds TYPE string
                                      FOR <odd> IN value_tab
                                      NEXT
                                      odds = COND #( WHEN odds IS INITIAL
                                                      THEN <odd>
                                                      ELSE |{ odds }, { <odd> }| ) ).
     out->write(
       EXPORTING
         data   = |[{ string_odd }]| ).
   ENDIF.
  ENDMETHOD.
ENDCLASS.

The final part of my ABAP code (zcl_demo_fp) showcases the usage of the defined classes and predicates, similar to how the examples were demonstrated in GHCi for Haskell. In my demo class, I create instances of the filter, even, and odd predicates, apply them to a range of integers, and output the results.

Conclusion

Functional Programming Insights: We learned why higher-order functions and function composition are super important in functional programming. Understanding these concepts helps us make the most out of functional programming.

Natural Implementation in Object-Oriented Programming: Some people think that functional programming is only for certain languages, but I showed how these ideas can work smoothly in Object-Oriented Programming (OOP). Using dependency injection, I made higher-order functions work well. With functional method composition, I found a natural way to combine functions (using functional method) in an OOP setup.

We’ve made good progress with using functional programming ideas, but there’s more to learn. To write really great code, we need to understand things in a more detailed way. So, in the next part, we’re going to look at a real-world example. We’ll explore how to design things in a smart way, using ideas from functional programming. Our goal is to show how these ideas can help us create clean code.

Our adventure is not finished yet. We’re ready to go deeper into the mix of functional programming and Object-Oriented ABAP. This could change the way we usually design and make software. Stick around as we uncover more about how these ideas can make a big difference in how we create software that works well.

Assigned Tags

      9 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Lars Hvam
      Lars Hvam

      A higher order function takes functions as input and returns a function, https://en.wikipedia.org/wiki/Higher-order_function

      Function composition takes two functions and creates a new function, https://en.wikipedia.org/wiki/Function_composition

      In functional programming, functions are treated as first class citizens, https://en.wikipedia.org/wiki/Functional_programming

       

      All of which is not possible in ABAP? The examples are object oriented programming in ABAP?

      Author's profile photo Raden Prabowo
      Raden Prabowo
      Blog Post Author

      Hello Lars,

      Thank you for your comment. I'm unclear about your specific question, but I'll share my thoughts on the topic you raised.

      As I know ABAP is an imperative procedural/ object-oriented programming language. ABAP does not treat a function as a first-class citizen, the closest behavior of this is by using an object-oriented paradigm which is an object as a first-class citizen.

      In more specific terms,
      higher-order function: A function is called higher-order if it takes a function as an argument or returns a function as a result. But often, the functional programmer would say that a higher-order function is a function that takes a function as an argument, whereas a function that returns a function as a result is called a currying/ curried function. In ABAP it can only be achieved by using dependency injection (object-oriented).

      In mathematics, function composition is defined like this: (f . g)(x) = f (g(x)).
      This means that composing two functions is the equivalent of calling one
      function with some value and then calling another function with the result
      of the first function. In Haskell, function composition is pretty much the same thing. We do function composition with the . function, which is defined like this:

      (.) :: (b -> c) -> (a -> b) -> a -> c
      f . g = \x -> f (g x)

      In ABAP we can achieve this by leveraging the functional method of a class/ object.

      CLASS zcl_demo_fp DEFINITION
        PUBLIC
        FINAL
        CREATE PUBLIC .
      
        PUBLIC SECTION.
       INTERFACES if_oo_adt_classrun.
        PROTECTED SECTION.
        PRIVATE SECTION.
        methods add IMPORTING val1 type i
                              val2 type i
                    RETURNING VALUE(result) type i.
      ENDCLASS.
      
      CLASS zcl_demo_fp IMPLEMENTATION.
        METHOD if_oo_adt_classrun~main.
         DATA(number) = add( val1 = 3
                             val2 = add( val1 = 5
                                         val2 = add ( val1 = 1
                                                      val2 = 7 )
                                        )
                            ).
          out->write( number ).
          
        ENDMETHOD.
        METHOD add.
          result = val1 + val2.
        ENDMETHOD.
      ENDCLASS.

      As I mentioned before I use object-oriented ABAP to implement functional programming concepts. There is nothing new in the example/ ABAP implementation above, I just translate the basic functional programming concepts into ABAP language leveraging object-oriented programming in ABAP to get used to the concepts.

      Author's profile photo JHONEY BAIRSTOW
      JHONEY BAIRSTOW

      hmm

       

      Author's profile photo Matthew Billingham
      Matthew Billingham

      Ew. Haskell uses Integral (which is among other things the area under a curve) to indicate an Integer.

      Can you explain why what you're doing is using dependency injection?

       

       

      Author's profile photo Raden Prabowo
      Raden Prabowo
      Blog Post Author

      Hello Matthew,

      Thank you for your comment. That is an excellent question; in fact, it's inspiring me to write another blog post about dependency injection in ABAP. While there are already some blog posts on the topic, such as this one and this one. But still, I want to write my perspective about dependency injection.

      Now, I'm going to re-explain why my ABAP example employs dependency injection.
      please get focused on this code

      CLASS zcl_filter DEFINITION
        PUBLIC
        FINAL
        CREATE PUBLIC .
      
        PUBLIC SECTION.
       METHODS get_filtered IMPORTING predicate  TYPE REF TO zif_predicate
                                      value_tab  TYPE ANY TABLE
                            RETURNING VALUE(result) TYPE REF TO data.
      
        PROTECTED SECTION.
        PRIVATE SECTION.
      ENDCLASS.
      
      CLASS zcl_filter IMPLEMENTATION.
        METHOD get_filtered.
         FIELD-SYMBOLS <result_tab> LIKE value_tab.
         CREATE DATA result LIKE value_tab.
         ASSIGN result->* TO <result_tab>.
         LOOP AT value_tab ASSIGNING FIELD-SYMBOL(<value>).
           IF predicate->evaluate( <value> ) = abap_false.
             CONTINUE.
           ELSE.
             INSERT <value> INTO TABLE <result_tab>.
           ENDIF.
         ENDLOOP.
        ENDMETHOD.
      ENDCLASS.

      In the given code, the dependency is the zif_predicate interface, and it is injected into the get_filtered method as a parameter (parameter injection).

      Here's a breakdown of the dependency injection in the above code:

      1. The get_filtered method takes two parameters: predicate (of type REF TO zif_predicate) and value_tab (of type ANY TABLE).
      2. The predicate parameter represents a dependency, and it is expected to be an instance of a class that implements the zif_predicate interface.
      3. Inside the get_filtered method, the predicate parameter is used to evaluate each element in the value_tab table, which is its implementation can be changed in run time.

      By passing the predicate as a parameter to the get_filtered method, we allow external code to determine the filtering logic, thus adhering to the principles of dependency injection.

       

      Example code that does not use dependency injection

      CLASS zcl_predicate_odd DEFINITION
        PUBLIC
        FINAL
        CREATE PUBLIC .
      
        PUBLIC SECTION.
        INTERFACES zif_predicate.
        PROTECTED SECTION.
        PRIVATE SECTION.
        METHODS negate IMPORTING truth TYPE abap_bool
                    RETURNING VALUE(result) TYPE abap_bool.
      ENDCLASS.
      
      CLASS zcl_predicate_odd IMPLEMENTATION.
        METHOD zif_predicate~evaluate.
         result = negate(
                   CAST zif_predicate(
                     NEW zcl_predicate_even( )
                       )->evaluate( value = value ) ).
        ENDMETHOD.
      
        METHOD negate.
         result = COND #( WHEN truth = abap_true
                       THEN abap_false
                       ELSE abap_true ).
        ENDMETHOD.
      ENDCLASS.

      The zcl_predicate_odd class takes a dependency on another class, zcl_predicate_even,
      but, instead of injecting it, the dependency instantiation is hard-coded within the method itself.

      Author's profile photo Matthew Billingham
      Matthew Billingham

      OK, I see it now. Thanks.

      I use dependency injection routinely - I just couldn't see the injection point!

      Author's profile photo Raden Prabowo
      Raden Prabowo
      Blog Post Author

      please check my blog post talking about dependency injection

      Author's profile photo Jelena Perfiljeva
      Jelena Perfiljeva

      FYI: there was a post about this in 2015.

      Author's profile photo Raden Prabowo
      Raden Prabowo
      Blog Post Author

      Hello Jelena,

      Thank you for your comment. I've read the mentioned post, and it's indeed a good blog post about functional programming. However, there are significant differences between my post and the one you referred to. If you haven't noticed these distinctions, it's possible that you didn't read my post all the way through.

      Let me highlight the key differences between the two:

      My post focuses on higher-level abstraction (design level), while the other post delves into syntax (lowest level/concrete level). The mentioned post doesn't cover the fundamental concepts of functional programming; it mainly discusses REDUCE, COND, VALUE, FOR, etc. – essentially syntax.

      As developers, we follow these steps in learning programming:

      1. Language proficiency
      2. Data structure and algorithm
      3. Design patterns

      The higher the number, the higher the level of abstraction (design patterns being the highest). Before reaching the design pattern stage, I need to explain the basic concepts of functional programming and how to implement them in ABAP. I believe my blog post is unique in this scope and fills a gap by covering concepts that haven't been addressed before.