Sunday, June 23, 2013

The Essence of Functional Programming and ABAP.

So what the .... is this 'Functional Programming'?
It is a programming paradigm that typically avoids using mutable state. (Whatever does that mean?)

Functional programming avoids side effects (change of state) during execution of a function. Compare that to imperative style programming, like in ABAP, where usually state can be changed by commands/statements e.g. for I/O, database operations, global variables, buffering etc.

Stateful programming is a major cause of bugs in software programs. It introduces complexity, uncertainty and affects readability of code that in turn causes bugs during initial development and even more during maintenance. Such code is not easily understandable and other programmers end up making unintentional changes during maintenance phase.

In my view, readability of a program is not about good looking, handsome or beautiful code. Nevertheless, some developers achieve the objective of writing *good-looking* code by hiding all the code inside a method / routine that does not even gets or returns any parameter. So the main program is probably just a few calls of such routines, that might even have lengthy comments, along with all the stars and moons around it. And it does *look* good and clean.

I would consider a program, function or method as readable, if I can use my brain as a virtual m/c or a Runtime Environment for the code, and depending on the known parameters or state at a given point, I could  effectively run the program in my head, pass through the flow with a decent level of accuracy and have an understanding of the results. Obviously in the process I'll have to check the values in database tables etc. but you get the idea.

Now, object oriented programming might have solved many other issues with software development but I don't think Readability or even Debuggability is one of them. When you are reading code and trying to run it in your head, it works quite well till you hit a global variables, attributes, instances etc. that are populated through another function, method or constructor. Brain starts hurting. First of all it's not really a programming language runtime environment, secondly you use the same environment for so many different programming languages and paradigms now on top of it, you are asking it to run code that does not provide complete instruction, definition of data-structures or data. So it just basically starts sending signals to use debugger, try 'Where Used', look for event listeners, design or tech documents, UML diagrams, match the design pattern etc.    

Basically, I found the idea of avoiding state changes quite fascinating and it does seem like, with a little exaggeration, the holy grail for producing relatively error free and maintainable software. Though I don’t have any data to prove this but I've around 15 years of experience in software development, mostly with solving problems in my own or others’ code so  it’s probably just my intuition.

Even before I started exploring the main idea behind functional programming, I've always been a bit cautious in my programming style. e.g. avoid use of global variables and writing functions/methods/routines with proper input / output parameters without trying to access global data from within, unless when really pressed on the performance and has to implement buffering etc. To give you another example of a cautious style, I hesitate using [ LOOP at ITAB ASSIGNING <FS> ] and will rather use [ LOOP AT ITAB into wa_itab ], to avoid any possibility of making unintentional changes to original ITAB Data. The reason for being cautious is that the developer who is going to maintain my code after me, might make some changes to the reference data while trying to do some local operations, without even realizing the impact of such change e.g. in case the ITAB is a changing parameter in a BADI implementation , customer-exit or in any other method/function. 

I would rather avoid a feature of programming language that improves performance but also opens the door for silly mistakes later that could affect the correctness or maintainability of the program. I think it's better to solve the performance issues on application level with an efficient design and logic (e.g. better program flow, algorithm )  and on database level with effective use of indexes and data-models etc.

So coming back to the point, in functional programming, functions are like mathematical function that takes input and returns an output without changing state in that process of computation. e.g. add(1,1)returns 2.
Compare that to a function in ABAP, for example, BAPI_ORDER_CREATE (fictional but you’ll get the idea) . This also takes input and returns an output e.g. an order number. But while trying to generate that Order, it makes several changes to the state like database change, number range increment output/print of a document, download file/IDoc , trigger another process or interface etc.


Now, I might be wrong in my interpretation of the idea behind functional programming but one thing I've learned about the process of learning;  It’s OK to start with even a hazy conceptual understanding of a new concept through analogy and comparison with an already known subject. It provides a starting point from where you can improvise as you explore further into an alien subject. That's Ok, but where is the analogy? I had the same question. I mean how would you create, say a Purchase Order, using a mathematical style function that makes no changes to state. Or how can we create a purchase order using a functional programming style?


So while I found the idea behind functional programming quite fascinating and clearly beneficial too, how to achieve something substantial in an industrial programming environment was an equally intriguing question.
Exploring a bit further, I realized that there might be a bit of compromise required in some cases but there are some special features in a functional programming language environment to support the main essence that is stateless programming. 


A good overview of functional programming can be found at Haskell Wiki.
Functional programming requires that functions are first-class, which means that they are treated like any other values and can be passed as arguments to other functions or be returned as a result of a function.
Haskell wiki has good summary of following Language features of a functional programming language that makes it possible to write stateless and relatively stateless functions e.g.:
  1. Higher Order Functions : are functions that take other functions as their arguments. So if SAP ABAP could have such feature then you can compose another function / computation by passing one function to another function like a parameter.  Further Reference : http://www0.cs.ucl.ac.uk/teaching/3C11/book/ch4.pdf
  2. Purity : Referes to Language feature that prohibits side effects.
  3. Recursion : [ just a link to wikipedia and not a Google style Joke for recursion ]
Now, I do understand that ABAP is not a functional programming language and it does not support any of these features except for recursion ( that too without any in-built optimization for tail recursion) but my intention is to look into the possibility of bringing some of the functional programming goodness (avoid state changes) into my ABAP design/programming style. Obviously, pure functional programming style will be more beneficial for parallel or distributed programming, but concept of immutable data can be useful even in normal scenario.

To add further on the topic of recursion in ABAP, I tried converting a simple iteration ( loop ) to recursive style function, just to show the performance implication and obviously recursive style will not be suitable in ABAP, if you are dealing with a large data-set. Without any optimization for tail recursion, each function call is kept in the call stack memory till the end so it's not really efficient in terms of memory consumption or performance, even if you write tail recursive function. Due to memory consumption, there could also be a limit on the depth of recursion that can be achieved, in case you are dealing with large data-set.

The function Z_RAM_TEST_ITERATE_ITAB is just a recursive replacement for normal LOOP statement.
Note that in new ABAP release it could be easier to read itabsmore like array access...so in place of READ TABLE itab blah blah.. you can actually use wa = itab[index] etc.
FUNCTION z_ram_test_iterate_itab.
*"--------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(I_INDEX) TYPE  I DEFAULT 1
*"     VALUE(I_ITAB) TYPE  STANDARD TABLE
*"--------------------------------------------------------------
  FIELD-SYMBOLS : <fs_itab> TYPE c.

  READ TABLE i_itab ASSIGNING <fs_itab> CASTING INDEX i_index.
  CHECK sy-subrc EQ 0.
*   Record found so now try iterating next otherwise it will come 
*   out at this point.

*   Do some calculation etc. here
*    WRITE /: <fs_itab>  .
*   Now go on...
    i_index = i_index + 1.

  CALL FUNCTION 'Z_RAM_TEST_ITERATE_ITAB'
    EXPORTING
      i_index                = i_index
      i_itab                 = i_itab.

ENDFUNCTION.

Following screenshot of ABAP debugger shows the call-stack for a recursive function.


Also, this chart below is just for an indication of performance difference ( it's not an exact comparison though):


But if you are not dealing with huge data sets then recursive style can be useful in writing testable, provable and readable functions compared to iterative loops. Just to mention that some other programming languages/compilers don't support tail call optimization too but developers have come up with clever tricks to handle it using a decorator that re-writes the function to raise an exception, in order to remove the unnecessary function from the call-stack. An example is here :
..shows a python decorator which implements tail call optimization. It does this by throwing an exception if it is it's own grandparent, and catching such exceptions to fake the tail call optimization.
I'll add the list of other references for functional programming at the end of this post...later.

There is no conclusion as far as this Blog post is concerned...apart from the obvious fact that ABAP Language and ABAP Programmers, both have a lot to learn and improve :)

References for Functional Programming :


Ref. Remarks
Functional Programming HOWTO :
Functional programming
The rise of fimperative programming
OO Programming Vs. Functional Programming - A Comparison of Concepts
OO and FP
Functional thinking: Immutability
Mastering recursive programming

5 comments:

  1. IMO recursive functions are not an improvement over traditional loops, they are simply a side effect of not having mutable data.

    Consider that for loops using an incrementing number or while loops checking a flag are impossible since these values cannot change. They are also the only way of working with immutable linked lists.

    ReplyDelete
    Replies
    1. Thanks for your comment Andy.

      Agree that recursion is not an improvement rather a way to handle iteration while maintaining the restriction of immutability in a *functional programming language*.

      Not to mention that there are some cases where recursive patterns comes more naturally to developers, while writing modular code, specially if you are traversing backwards, even in non-functional language.

      For example, if you want to write a function to find out which programs will be impacted, if you change a data-element in data-dictionary that might have been used in several tables, programs. Also, those program routines/tables might have been called in other programs too. In such case, recursive implementation seems to be obvious choice.
      Similarly there could be other cases where recursive data-structures are required.

      However, the question that I am trying to explore is:

      Is it feasible to impose the immutability restriction in a non-functional language just as a manual application code/design level constraint ( as language itself is not putting that constraint in place ) and still manage to get some benefits associated with the concept of immutability.

      Thanks,
      Ram


      Delete
    2. Without language support, immutability is an up hill struggle. For example in java Creating an immutable class is relatively easy but then what if I want to "copy" that object with a new field? Manually copying every field plus the new one is a lot of code.

      Use erlang instead.

      Delete
  2. ABAP is a born imperative language, and added with some object - oriented features. So I think there's no way to take benefit of functional programming thinking in ABAP at all.

    ReplyDelete
    Replies
    1. Thanks Jun for your comment...so unless a language was born Functional, there is no other way to apply functional *thinking* with it?

      Delete

Info : Comments are reviewed before they are published. SPAMs are rejected.

Copyright