Functional ABAP – Functional Programming in ABAP ?!
Introduction
The idea to write a blog exploring the possibilities of functional programming in ABAP first came to my mind when I read Horst Keller‘s blogs on ABAP Language News for Release 7.40, SP08. Especially the REDUCE operator that is part of the new iterator expressions ( ABAP News for 7.40, SP08 – FOR Expressions) immediately reminded me of the reduce function in Clojure. As I was learning different function languages in my spare time anyway I started to try to implement some of the examples used in the functional programming tutorial in ABAP. After a twitter conversation with Uwe Fetzer and Fred Verheul (see Uwe’s blog Rosetta Code and ABAP) I decided to collect some of the code examples I created so far and share them in a blog.
A (very, very) short introduction to functional programming
Functional programming is one of the oldest programming paradigms, dating back as far as the late 1950s (cf. Functional programming – Wikipedia). Despite this long history, functional programming never gained widespread acceptance (compared to e.g. C or C++). However, in recent years there has been a growing interest in functional programming and functional programming languages again.
For example, the RedMonk Programming Language Ranking for January 2015 list with Scala (The Scala Programming Language), Haskell (Haskell Language) and Clojure (Clojure – home) three functional languages among the top 20 programming languages (cf. image below). In addition functional extensions to popular programming languages like Java have been developed (cf. Functional Java and How Functional is Java 8?).
There are numerous articles and discussions available on the internet regarding the advantages and/or disadvantages of function programming (e.g. Functional thinking: Why functional programming is on the rise and Advantages Of Functional Programming). In my opinion there are two key advantages that lead to the current interest in functional programming. Firstly, the possibility to develop specific abstractions is an integrated part of each functional language. Secondly, the property of functional languages of being side effect free simplifies the development of parallel programs.
Disclaimer
I don’t advocate the code examples I will show below for productive usage (at least not yet). With all the new language features getting added to the ABAP language Tobias Trapp‘s advice “Don’t try to be smart. Be smart.” is more valid then ever. In the context of what I’ll show below I would paraphrase Tobias’s statement as “Just because something is possible doesn’t mean it is a good idea to do it.”
Furthermore, it is important to keep in mind that ABAP is not (and most likely will never be) a functional programming language. In ABAP, it is not possible to pass functions as arguments to other functions. The ABAP compiler and runtime currently lack important features (e.g. tail call optimization, cf. Tail call – Wikipedia or What Is Tail Call Optimization? – Stack Overflow) of runtime engines for functional languages. Consequently, functional programming in ABAP is limited to certain cases. The examples shown below might also only run very slowly or only work for small input values compared to an imperative or object-oriented implementation.
Nevertheless, it is in my opinion quite interesting to see what is possible with the current version of the ABAP language.
Functional ABAP examples
In the following sections I’ll show some quasi functional implementations of different algorithms in ABAP. Note that all code examples in this blog a screen shots. There reason for this is that no syntax highlighting for ABAP is available. In order to simplify the usage of the code snippets is also create a pastie (Pastie) for each snippet and added a link to it below each screen shot.
Simple start
As a simple start to functional programming in ABAP let’s calculate the sum and the product of the values of an internal table. The code snippet below shows how this would be implemented in ABAP without the usage of any of the new language features. To calculate the sum and the product one would simply loop through the internal table and store the calculation result in a temporary variable. It would of course be possible to calculate the sum and the product using a single loop. However, I used two loops to make the similarity to the functional implantation more obvious.
#10078959 – Pastie – zcd_sum_and_product
Using the reduce table expression calculating the sum and the product can also be implemented as shown below.
#10078938 – Pastie – zcd_reduce_test
Note that in this case there is not much difference with respect to the code amount between the two solutions. In fact the classical solution using only one loop would be shorter than the functional one. The key advantage of the REDUCE operator is that it can be combined with other operators to create more expressive expressions.
Fizz-Buzz
The first a little more advanced algorithm I implemented using a functional paradigm in ABAP is the Fizz Buzz Test. The Fizz Buzz Test is a simple programming exercise I stated to use in job interviews for developers lately. Many implementations of the Fizz Buzz Test in different languages are documented on rosettacode (http://rosettacode.org/wiki/FizzBuzz). The goal of this test is to:
“Write a program that prints the numbers from 1 to 100. But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. For numbers which are multiples of both three and five print “FizzBuzz”.”
The code snippet below shows the implementation of the Fizz Buzz Test in “normal” ABAP without the usage of any of the new ABAP features. In lines 6 to 9 an internal table is initialized with the numbers 1 to 100. After that the lines 11 to 22 show the core implementation of the FIZZ BUZZ Test.
#10076806 – Pastie – zcd_fizz_buzz
An alternative implementation of of the Fizz Buzz Test using functional ABAP is shown below. It is immediately obvious that the second implementation is much more concise then the previous one. The implementation consists of a constructor expression for a string table (line 4). Using the FOR iterator expression the values form 1 to 100 are passed to a COND expression. The COND expressions uses a LET expression to create two local variables r3 and r5. r3 and r5 store the result of i MOD 3 and i MOD 5 respectively. Finally, the WHEN and ELSE clauses in lines 8 to 11 implement the core logic of the Fizz Buzz Test.
Besides being more concise, the functional implementation is in my opinion a lot cleaner then the classical one.
#10076802 – Pastie – zcd_functional_fizz_buzz
n!
Next I implemented the factorial function. The factorial of a positive integer n is defined as the product of the sequence n, n-1, n-2, …1. Furthermore, the factorial of 0 is defined as being 1. Using the the COND and the REDUCE operator the factorial function can be implemented as shown below. This functional implementation of the factorial function nicely resembles the definition. Therefore the functional implementation is in my opinion simpler to understand compared to the classical implementation.
Note, that the COND operator is not required in the implementation. The REDUCE operator would also handle the special case of 0 correctly. Nevertheless, I included the COND operator in order to have the function definition more clearly expressed in the code.
#10079013 – Pastie – zcd_functional_factorial
Fibonacci Sequence
The last algorithm I implemented using the functional operators is the Fibonacci sequence. I used a recursive approach for this implementation. The COND operator is used to represent the definition of the Fibonacci numbers (lines 13 – 18). In order to implement the recursive call I used a LET expression to invoke the Fibonacci function recursively (line 18). The two auxiliary variables x and y store the last and second to last element to the Fibonacci sequence for n-1 (lines 19 and 20). Finally the result of adding x and y is concatenated with the elements of the Fibonacci sequence for n-1 and returned (line 22).
#10076876 – Pastie – zcd_functional_fibonacci
What’s next?
As stated in the introduction it is quite interesting to see what is possible with the new ABAP features. However, there are still some open questions:
1. Performance
In the examples above I didn’t compare the performance of the classical ABAP solutions to the functional ones. It would be quite interesting to see how the different solutions compare with respect to performance. This might be the topic for a future blog post.
2. Productive usage scenarios
Another open question is which productive usage scenarios are suitable to apply the functional ABAP features. The examples above are implementation of mathematical algorithm. However, productive ABAP code usually deals with the handling of business objects (e.g. business partners). The first usage scenario that came to my mind is the usage of the FILTER operator (not shown in the examples above, cf.FILTER expression) to filter an internal table after some select (e.g. select from BUT000 and the filter the business partner type). However, It would be interesting to find further usage scenarios in which a functional solution offer advantages over the classical one.
3. Future ABAP versions
It will be really interesting to see what future ABAP version will offer. Maybe ABAP will in the future offer some functional features that are currently still missing.
Finally, I’d be interested to hear your opinion of the code examples I’ve shown above. Do you think this is something that should be used in productive code?
Christian
Once, you get used to operators like NEW, VALUE, CONV, CAST, COND, ... you will ask yourself how you could ever program without them 😉 .
E.g., I do a lot of string processing. Concatenating a string with
... && COND #( .... ) && ...
is so much better than splitting the concatenation and having IFs in between.
Same holds for construction of internal tables:
itab = VALUE #( ( ... ) ( COND #( ...) ) ( ...) ... ).
Again, not a series of APPENDs with IFs in between but you write it down as you need it.
Or passing an actual parameter:
meth( ... iso_langu = cond #( WHEN sy-langu = 'D' THEN 'DE' ELSE 'EN' ) ... )
Only a few examples of (my) daily life. Not so much about implementing full algorithms in a functional way, but how these little helpers also ease the "normal" programming in ABAP.
Hi Horst,
your are right. The one operator I currently use most is CAST. When programming in the BOL in CRM one hast to cast between interfaces and classes all the time. In this context CAST is really useful.
Christian
Yep, in my case I can't imagine how to use RTTI without CAST any more ...
Excellent blog post Christian, thanks for sharing!
I've been using some new operators mainly NEW, CAST and CONV and am very happy so far 🙂
Only problem is the internal fight I get into when I try to ponder the "if you can doesn't mean you should" x "because I can". 🙁
Cheers,
Custodio
Hi Christian,
nice work.
Every time I see this picture,
http://sogrady-media.redmonk.com/sogrady/files/2015/01/lang.rank_.plot_.q1152.png
I send it to my colleague and ask him to find ABAP.
Does anyone know why ABAP is missing?
Regards Christian
Hi Christian,
I guess the main reason that ABAP is not in the chart is that there are only very few ABAP projects on GitHub.
Christian
That's what I thought at first too. But there are languages in the ranking having even fewer GitHub projects. In the meantime we have to stick to this ranking to show the importance of the ABAP language. 😎
TIOBE Software: The Coding Standards Company
Pascal comes before ABAP? Oops 🙂
Basically i'm a big fan of these new types of functional expressions. They're so powerful and a pleasure to create. But imho there are downsides too. The expressions can grow very fast to a big uncomprehensible stack. Find a bug in such an expression without the ability to debug them can be quite cumbersome.
They sometimes rember me to regular expressions. Also a very powerful and underestimated tool. Both not properly used can lead to big messes. Every time i use functional or regular expression i try to put them in a separate method with a name indicating its purpose and back them up with unit tests. At first sight quite a amount of work, but in the long run the maintainer of the code (probably me) will thank a lot.
This is definitely correct. When implementing the Fibonacci sequence I had exactly this problem. There was a nasty bug (can't remember the details right now) which was quite hard to track down. However, IMHO this is mostly a tooling problem. If ABAP evolves further in the future the debugging and tracing tools must also be enhanced to allow to effectively work with the new features.
Actually, this should be the approach taken for all code. I know it is not (yet) common practice in the ABAP. But its also possible to write uncomprehensible code in ABAP without using regular expressions and functions 😉
Christian
Hey, I really like your blog. I’m only a little bit worried that the ABAP community could see me as a grumpy ol’ ABAP/4 developer who declines all new features. This is not the case and in fact I use these expressions in unit tests and I'm using them sometimes in productive scenarios.
BTW: I think it’s now time to start an obfuscated ABAP contest – with functional and regular expressions, macros and INSERT resp. GENERATE REPORT we are ready for it 😉
Cheers,
Tobias
I definitely didn't want you put you in the position of the grumpy old ABAP/4 developer. I just want to make sure people know what they are doing and your blog as well as the talk at #sitFRA articulated this very well.
As for the obfuscated ABAP contest: I'm in! 😀
Horst Keller just started the obfuscation contest: ABAP Obfuscation Riddle
Tobias, join the dino club like me......
However, I may be grumpy, and I may be old, but I'm all for code readability and for me, 2 loops as against a single reduce works better when it comes to maintaining the code.
I hate to nitpick, but wouldn't true functional programming actually use performs and functions? These are good examples of recursion in OO ABAP regardless.
Hi Rayn, your are not nitpicking. ABAP is not a functional language and one can only get so far with functional programming in ABAP. ABAPs procedural and OO roots are still visible in all the examples. Using preforms, function modules or methods doesn't change this.
Technically in the requirements for FizzBuzz test it only says "print", so you might have as well skipped the whole internal table business and just used WRITE inside the DO loop. 🙂 But in any case as Thorsten Franz would say - "fine ABAP craftsmanship".
Very interesting blog and points to even more reading material. Thank you for sharing!
Hi Christian
I started replying to your very interesting post, but ended up writing a blog (or a brain dump). So rather than putting it here as a reply, I've actually blogged what I was thinking.
Why we must take Functional Programming seriously.
Regards
Chris W
Hello Christian,
your examples of the new syntax make the code concise. Yes. Cool!
However, calling the result functional programming is misleading. It implies you could not have done it before. Side effect free functions and recursion can be implemented in old style ABAP. And this REDUCE operator is imperative, it does not accept a binary operator/function as argument.
So I prefer the terms expression oriented programming or functional style here.
I use expressions in production code, but I cannot think of ABAP unit test code without expressions anymore.
I had a problem with replacing a LOOP AT / INSERT INTO TABLE.. ENDLOOP with an VALUE #( FOR x IN table ( x-comp ) ) because the former will ignore duplicates and the later would dump.
best regards,
JNN
Hi Jacques (and Christian),
I have to agree with you here: the use of certain operators does indeed turn statements into expressions, but IMHO they're still almost as clumsy (verbose, etc) as their corresponding statement counterparts. And, what's maybe worse, not really functional.
I would expect that in a functional style the explicit loop would disappear (to be handled by the FOR/REDUCE/etc construct), but here each FOR expression keeps using additional variables and the loops stay explicit.
Of course that's all due to the fact we can't pass functions to these operators. But as long as that doesn't change, I see no future for functional programming in ABAP 🙁 .
Fred
Very interesting blog, good for pratice algorithm.
Very good! Let´s expand it!
Awesome!!!
Hello Christian,
very interesting blog! More geeky than the "usual stuff" in my opinion. I don't think functional programming is mainstream where I come from. I still remember how I failed my first university exam in Prolog/Haskell terribly. But once you "get it", it is not so difficult. I heard that in US these things are more commonly used - like Haskell, but I can't comment on that. Anyway I have two doubts here, but I can only support the claims of those who named them already.
a) productive scenarios - I am not sure where I would use the power of this approach. Now let's put the performance aside (assuming we have HANA 😉 ). I can't think of any classes of problems I solve in my everyday business that would work better (whatever "work" means here) done functionally. I will be carefully monitoring the comments here waiting for ideas I have not stumbled upon myself, but I am afraid there won't be many. If this approach brought the normal "reports" closer to the "normal mortals" (like queries so that you don't need a developer), that would immediately switch gears for the idea. But this is going the other direction - more tricky stuff, not less.
b) support and maintenance - first of all I must remind the team here that there are still customers not allowing OO ABAP, because people "don't get it". I can't imagine functional ABAP coming to the mainstream practice before OO ABAP 😉 Even if it was allowed, how many people around you/us would use it? So the number of people with the skill would push the price of maintenance of such code sky high. That's why people won't even start with it in my opinion. Being able to read and carefully fix such program after a year (of heavy productive usage) can also pose a challenge 😉 Imagine having a program full of regexes. I know the power of regexes, but I intentionally don't use them because the next time I work on my own ❗ code I need to "decode" these things before I can start the real work.
I didn't mean to spoil the party, of course. I understand (assume so) that the whole idea is more a playful exercise of a smart person for fellow geeks. In that case it is a wonderful idea exercising many language constructs in a innovative and powerful way and I admire the idea and the depth to which you thought about it and informed us about it. Really - respect!
cheers Otto
Hi Otto,
I take this as a compliment 😀 . Thanks.
I fully agree with this statement. Currently I don't see any areas in productive scenario in the classical SAP applications like ERP or CRM where something would work better if implemented functionally. However, as Horst Keller pointed out in his first comment there are some operators that significantly simplify the code for common tasks (e.g. NEW, CAST or CONV). These operators allow for more concise and readable code and are therefore very useful in productive scenarios. If you take a look at functionality developed in the latest EhP you'll see these constructs used more and more in SAP standard code as well.
This is also true for any ABAP program without any "fancy" features like OO 😉 . Maintainability is a important topic and is challenging regardless of the used development paradigm. Therefore, it's important to only use the new features were they improve readability. For example, the FILTER can express very clearly which elements of an internal table are copied into a second internal table. So there will be cases where I'll use FILTER instead of the common LOOP. Nevertheless there are still cases where the LOOP is a more natural choice then FILTER.
Christian
Hi Otto
I've addressed some of your concerns at greater length in my blog responding to this one (See Why SAP Should take Functional Programming Seriously); however, I should like to make a few brief comments here
Well, the absence of evidence is not the evidence of absence.
Just because you cannot find an example from your everyday work does not mean that one does not (or cannot) exist. It just means that such a solution lies outside the boundaries of your experience.
This way of thinking is exactly the trap I described in my blog about "The Inertia of Expertise". The success of our current solutions often blinds us to the possibility that other (possibly better) solutions could exist.
This is not to say that the current solution is not a good one; my point here is that in order to keep a genuinely open mind about which solution really is the "best", in addition to examining new technology, we must always be willing to challenge our own thought processes.
However, anyone who has undertaken such a mental self-examination finds it to be quite uncomfortable. We naturally dislike thinking about our own thoughts and challenging ourselves to the examine the possibility that we may (just possibly) have not been doing something in the best way.
Nonetheless, this is how a truly open mind can be maintained.
Here's where I wish English had an equivalent word to the German "Jein" ("Ja" + "Nein" = "Jein")
We need to balance to opposing requirements
Yes of course, support and maintenance are very real problems that need to be taken seriously. Failure to take such problems seriously can lead to productive systems going down for dangerously long periods of time.
Yet at the same time, we cannot let the requirements of our legacy systems act as a ball and chain around our feet, or some sort of straitjacket that completely restricts all movement. If we do, we will never implement innovative solutions because we are too afraid that they won't be compatible with yesterdays solutions.
If Henry Ford had thought this way, then his new "motor" cars would have come with an optional hitch and bridle for a horse - in order to stay compatible with horse-drawn wagons.
I've been in software consulting for over 20 years now, and if I've learnt anything, its that:
1) Change is inevitable
2) People resist change
To be honest, I don't think the version of ABAP that runs in the current generation of NetWeaver systems will ever become a truly functional programming language. Maybe ABAP 8 will allow for such possibilities, but even then we face a barrier far larger than simply the syntax of the language, and that is that you have to construct a solution by thinking in a very different way.
Where functional programming needs to be taken seriously is in handling the concurrency problems that IoT will bring. Here is where the functional programming paradigm will be able to provide better solutions than the software built using the imperative programming paradigm.
Chris W
Christian,
I was out for a couple of weeks on vacation and got to your post from another blog post in a brazilian abap blog (http://abap101.com/2015/04/21/obscurecendo-o-abap/).
As others already stated I really don't how/if techniques like that could be really implemented in production system, but I also don't care right now. Just the fact that you took your time into creating those examples, generating some discussion about FP and blowing some people's head (like mine) is already good enough 😀 .
It would be awesome if you could do some performance comparisons between FP and 'classical' solutions.
Thank you and congrats for the article!
I would propose some simple enhancement to ABAP for functional programming:
regards,
JNN
Hi Christian,
In my comment above I already indicated that on a second look these functional examples don't seem to be all that functional after all. Which is a shame.
That's also the reason I've not commented earlier: your blog post made me feel uncomfortable, but I couldn't express exactly what it was that made feel so. Now I know.
Nevertheless I want to congratulate you on an outstanding blog post, with lots of great examples of how to incorporate these new expressions in ABAP. And thanks for stirring a lot of debate around the functional style of programming.
One of the disadvantages of a relatively closed ecosystem like the SAP community is that influences from outside take very long to make it into the SAP and SCN community. We've seen that with object oriented programming, we've seen it with agile development, we're seeing it just now with DevOps and Continuous Integration/Delivery, and we are going to see it with functional programming as well. And I probably forget some trends here. (Maybe I'd better dedicate a separate blog post to this subject 🙂 .)
Therefore: kudos to you for looking beyond the SAP world, and trying to learn from the general developer community and their best (and new) practices!
Fred
Hi Fred,
I agree with you, that in the closed ABAP ecosystem it takes time till new trends are adopted. And then there is always the requirement to be compatible to the existing code. Consequently, nothing is ever removed and the language just becomes more cluttered.
However, in the area of HCP everything seems to be much more open. Its well possible to write functional code in Javascript. Additionally, deploying a Clojure or Scala app to HCP should also be quite easy (have to try this soon 😉 ).
Christian
Really nice examples, Thanks for share
Here is an approach I made of the Fibonacci sequence.
I think it's simpler and use just the FP paradigm without the need for methods
Hi Marcelo,
nice solution. Using just a FOR loop and BASE is much cleaner then my original approach.
Christian
Great solution Bovo !
Another good way to reach this result is as I wrote below:
BR,
Pacheco.
To add a productive example: we do a lot of interfacing and sometimes you just need a hard-coded mapping from one set of values to another. This is quite elegant with COND: