Functional programming in ABL - Forum - OpenEdge Development - Progress Community
 Forum

Functional programming in ABL

  • In functional programming languages, functions are first-class citizens.
    This means you can assign a function to a variable and pass it as parameter to another function or return it from other functions.

    In ABL there is one construct in which you can specify a method as a parameter, and that is when attaching an event handler to an event:

    myButton:Click:Subscribe(myButton_Click).

    We can (ab)use this to have some functional programming capabilities:

    CLASS FunctionalProgramming.Calculator:

    DEFINE PRIVATE EVENT Calculator VOID (a AS INTEGER, b AS INTEGER, OUTPUT Result_ AS DECIMAL).

    METHOD PRIVATE VOID Sum(a AS INTEGER, b AS INTEGER, OUTPUT Result_ AS DECIMAL):

    Result_ = a + b.

    END METHOD.

    METHOD PRIVATE VOID Multiply(a AS INTEGER, b AS INTEGER, OUTPUT Result_ AS DECIMAL):

    Result_ = a * b.

    END METHOD.

    CONSTRUCTOR Calculator():

    DEFINE VARIABLE Result_ AS DECIMAL NO-UNDO.

    Calculator:Subscribe(Sum).
    Calculator:Publish(3, 4, OUTPUT Result_).
    Calculator:Unsubscribe(Sum).
    MESSAGE Result_ VIEW-AS ALERT-BOX.

    Calculator:Subscribe(Multiply).
    Calculator:Publish(3, 4, OUTPUT Result_).
    Calculator:Unsubscribe(Multiply).
    MESSAGE Result_ VIEW-AS ALERT-BOX.

    END CONSTRUCTOR.

    END CLASS.

    The boilerplate code (Subscribe/Publish/Unsubscribe) might be able to get isolated in an include file.
    If anyone has any other creative ideas on how this pattern could be used, please share them here...

  • Thanks Lieven, no my brain is in a knot :)

  • Sorry for that!

    If Progress could somehow open up that syntax to ABL methods as well, things could get interesting...

  • I have some experience with functional programming in javascript and elixir (a language implemented on top of erlang). About two years ago I have been refactoring a large OO ABL codebase, during a whole year, where maintainance was a problem thanks a lot of problems, among which the over-enthousiast implementation of OO patterns and inheritance. I have learned to appreciate "referential transparancy", see f.e.

    "Write no classes!

    Joe Armstrong: "I think the lack of reusability comes in object-oriented languages, not in functional languages. Because the problem with object-oriented languages is they've got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle. If you have referentially transparent code, if you have pure functions-all the data comes in its input arguments and everything goes out and leaves no state behind-it's incredibly reusable. You can just reuse it here, there, and everywhere. When you want to use it in a different project, you just cut and paste this code into your new project. Programmers have been conned into using all these different programming languages and they've been conned into not using easy ways to connect programs together. The Unix pipe mechanism-A pipe B pipe C-is trivially easy to connect things together. Is that how programmers connect things together? No. They use APIs and they link them into the same memory space, which is appallingly difficult and isn't cross-language. If the language is in the same family it's OK-if they're imperative languages, that's fine. But suppose one is Prolog and the other is C. They have a completely different view of the world, how you handle memory. So you can't just link them together like that. You can't reuse things. There must be big commercial interests for whom it is very desirable that stuff won't work together."

    - Peter Seibel, Coders at Work: Reflections on the Craft of Programming"

     and github.com/.../ch03.md 

    and https://en.wikipedia.org/wiki/Composition_over_inheritance

     You can send functions around contained in objects in ABL. I have made extensive use of parameter objects that look like the following one (you could make use of interfaces of course):

    /*------------------------------------------------------------------------

       File        : SomeParameter

       Purpose     :

       Syntax      :

       Description :

       Author(s)   : Stefan

       Created     :

       Notes       :

     ----------------------------------------------------------------------*/

    using Common.Server.CommonRequest         from propath.

    using Common.Server.SomeHelper            from propath.

    using Basics.Server.DataAccess.daWhatever from propath.

    block-level on error undo, throw.

    class Somewhere.Common.SomeParameter:

     define public property CurrentRequest as CommonRequest no-undo

       get.  

       private set.      

     define public property DaX            as daWhatever no-undo

       get.  

       private set.    

     define public property Helper         as SomeHelper no-undo

       get.  

       private set.            

     constructor public SomeParameter(curRequest as CommonRequest):

       assign

         Helper            = new SomeHelper()

         CurrentRequest    = curRequest

         DaX               = new daWhatever()

         .

     end constructor.

     destructor public DebetCreditParameter():

       delete object DaX    no-error.

       delete object Helper no-error.

       error-status:error = false.

     end destructor.

    end class.

    Using this I have eliminated almost all inheritance and the use of OO patterns relying on it. The team was happy with the changes. See the recommendation I got on linkedin by the product owner: "[..] This has greatly improved the stability and maintainability of our product. The customer now experiences our product as very stable." (www.linkedin.com/in/stefanhoutzager).

    --

    Kind regards,

    Stefan Houtzager

    Houtzager ICT consultancy & development

  • Lieven, it would help if you explain your purpose. I understand progress, I can program functional myself but I do not understand what and why of your question.

    My previous mail is of course very incomplete. Hire me and I'll explain everything in detail. ;-) Small extra:

    I named "referential transparancy". An as far as possible referential transparent method should not depend on "indirect input" (a shared var so evil ;-), like an object reference obtained via constructor injection. This can be done with the parameter object as explained in my previous mail. In the example I have put (on purpose) one injected dependency. For parameter objects I do not mind much using it. My goal is making objects as much as possible stateless / push state to a lets call it statefull layer. In the end it is state (persist something in a db f.e) that you want to manipulate in your application  My goal is maintainability (see prev mail).  Read blog.ploeh.dk/.../  for more on dependency injection.

  • Lieven De Foor

    In functional programming languages, functions are first-class citizens.

    Luckily the 4GL still has functions so you can pretty much go with the functional programming paradigm if that works for you although I do not see how changing state can be avoided in a business application and I would very much like to keep the 'assign' statement part of the language - regardless of how imperative it might sound - for us mortals that don't write mathematical algorithms in 4GL :)

    Lieven De Foor

    The boilerplate code (Subscribe/Publish/Unsubscribe) might be able to get isolated in an include file.
    If anyone has any other creative ideas on how this pattern could be used, please share them here...

    No other creative idea so will probably just stick to using interfaces instead. 

  • The topic of my post was more of an eye catcher.

    You can't do functional programming in ABL.

    I've simply tried to demonstrate a way to pass a function as parameter, which is one of the pillars of functional programming.

    In ABL you would usually do this, like said using interfaces and callbacks.

    But sometimes adding an interface is not possible (3rd party code) or not wanted, and in that case the above could be useful to add some sort of callback without passing the whole object (through the interface), but only the method you want executed...

    , I did not ask any question, so it's not clear to me what your referring to. I'm also not interested in your consulting services...

  • Your question: "If anyone has any other creative ideas on how this pattern could be used, please share them here..."

    I took the question a bit broader, partly because I do not understand what it is you want and why.

    You do not reach much when you get snarky guys. Stay in your bubble if it fits your needs. ;-)

  • Stefan, I totally agree with you. I'm also totally in favor of referential transparancy. It has really changed my life.

  • That is nice to hear! At the moment I'm not developing with progress, but I'm always interested in exchanging ideas as far as I can make time.

  • You really should make time. Lots of developers here can really learn a lot from someone like you! Now back to programming. Nice day to you!

  • If you read the blog about dependency injection you will have seen the link to

    "In object-oriented architecture, we often struggle towards the ideal of the Ports and Adapters architecture, although we often call it something else: layered architecture, onion architecture, hexagonal architecture, and so on. The goal is to decouple the business logic from technical implementation details, so that we can vary each independently. This creates value because it enables us to manoeuvre nimbly, responding to changes in business or technology." (bold by me)

    You can get a bit of this value in progress. Architectural agility wins, else push the elephant: https://www.youtube.com/watch?v=GtkouFS-GSQ

  • > On Aug 11, 2019, at 9:17 AM, agent_008_nl wrote:

    >

    > "In object-oriented architecture, we often struggle ..."

    wonder if the following fashion of object orientation is worth the struggle. i've never seen any substantiation for the claims of easier maintainability, higher productivity, more reliability, easier readability, etc. lots of claims, no evidence.

    seems to me that it leads to a lot more code and figuring out what's going on amongst all the abstractions and "design patterns" and such is difficult. are the design patterns are really kludges to make up for language flaws ?

  • A bit off topic of the original post - but, I feel it necessary to point out:

    My observations as consultant/contractor seeing plenty of code is pointing in the same direction as Gus' comment:

    It seems to me, it is not so much a matter of what paradigm some application is following (procedural, object oriented, functional). What determines whether an app is technical debt or competitive advantage is directly related to how much effort the people put into making it a "good" code.

    I've worked at a (big) progress place, where they are still programming in V7/V8 style - permanently running into exactly the same issues that everybody did back then, and why OERA came about, and what OO was promised to fix... They are bad-taking progress, dreaming Java would be so much better! Well, they'll find out, if they try: if they do nonsense in Java as they do in Progress, the thing isn't even getting off the ground, not to talk about flying like an eagle!

    More recently I've worked at another big place, there they follow only rudimentary coding conventions and tried to get a handle on their flawed system by encouraging OO progress. Well, the OO code is as flawed as the (pre-)procedural one - and causing as much, or even more problems!

    To me, these two experiences are prime-examples that the paradigm does not guarantee good code!

    Before that, I was able to implement a complete application all by myself. I did everything the way I wanted - no shortcuts, no quick and dirty. I followed all the "best practices" I came up with and encountered over the year. I put a tremendous emphasis on consistency, overall architecture, and detailed implementation style. I am still maintaining this application, adding enhancements, changing existing functionality.

    It amazes me every time I have to deal with it, how quick it is to make changes, how stable the thing is, and how easy it is to find my way around it!  It was done in the procedural approach!

    I have proven to myself, that good style, clear, concise, and well formatted code, following a good overall architecture and design are the most important thing about programming, and that the paradigm (i.e. procedural, object oriented, or whatever) is totally secondary.

    As with everything, it takes time, much experiences, and plenty of bloody noses to become an expert at anything. It seems to me, switching every couple of years to a totally new approach or language can not be helpful in making you a master. It further seems, that sticking with one approach (and language) as much as possible is the best chance to ever reach master level - even though it is "just" being a master with that. But you are!

    To me, being a master application developer does not necessarily mean knowing internals of the tool you're using, or knowing all the newest fads... but to be able to build something from scratch all the way, and it working well and being easy to maintain - it being a competitive advantage for the users...

    Thomas Hutegger

    tmh@smat-consulting.com

    SMAT-Tools - Web-Apps with RollBase simpleness, ABL flexibility and power

  • Agreed Gus. Evidence based software-engineering is asked for since a long time. It is not easy to formulate the criteria to test and then the tests themselves are

    equally hard / time consuming to perform. See google on evidence based software-engineering. We are stuck with subjective opinions. "Are the design patterns are really kludges to make up for language flaws?" Yes I think so, and this not a new thought. At least Peter Norvig stated this already in 1996  "Design patterns are bug reports against your programming language.". "16 out of the 23 patterns in the Design Patterns book (which is primarily focused on C++) are simplified or eliminated (via direct language support) in Lisp or Dylan." en.wikipedia.org/.../Software_design_pattern.

     But many companies are stuck now with an OO ABL code base and have a problem maintaining it. What I propose is not a next fashion of oo (it's more weeding out some things like inheritance and depending patterns, see explanation in prev mails). Ports and adapters is natural for a functional language like haskell, not for oo abl. It is impossible to implement in oo abl. One might find some solutions for maintenance problems in it though.  Support for functional programming in ABL like making it possible to send a method/internal procedure/function reference as a parameter would be helpful.