Mapping Lisp to ABAP: It’s hard work
So I have been busy with the ABAP Lisp interpreter. The main focus now is the integration to ABAP. When I first started out with it, I had a vague idea in my head of what I wanted the interpreter to be able to do.
The problem is not so much the technical mapping of values and types; that is quite tedious work anyway. Most of the problems come about because there isn’t just one best way to do it. There are many ways. And the main problem is having to choose between them.
I initially started out writing a lot of built-in functions to manage and manipulate ABAP data, because that is obviously a prerequisite for working with function and method calls and passing parameters or accessing the results. (I’m still a looong way away from consuming classes; for now I’m just focusing on function calls). This involved writing many methods to access values according to the data type, until I struck on the idea of having a single method that will be able to get and set data with a simple syntax that will work for elementary types, structures and even function module interfaces. So for example:
(define mandt (ab-data "MANDT")) (ab-set mandt "000") (ab-get mandt)
I think this is pretty intuitive. In the first line, I create an ABAP variable of type “MANDT” and assign it to a variable called “mandt”. In the second line, I set the variable to “000”, and in the third line I retrieve the value. Here is another example:
(define client (ab-data "T000")) (ab-set client "MTEXT" "Client Name") (ab-get client "MTEXT")
This is the same as the first example, except that now, because we are dealing with a structure, the second parameter is required to be an identifier, which in this case is a field name. It beats having multiple functions to access different ABAP types.
Of course, both approaches have their merit: Having a single setter/getter pair will make programming a lot easier. Having multiple methods would cause a lot of confusion for the developer that eventually uses the language. On the other hand, being able to have a lot of smaller methods would be easier to implement and test. Now I have a few humongous methods which have to take care of a lot of detail, and that becomes messy to code. (There is probably a law in computer science which describes this trade-off, that when you try and shield complexity from the user, you end up creating quite a mess in the background, whereas when you expose them to the complexity, your code becomes cleaner and easier to maintain. True for most things, except Lisp, I suppose).
These methods are in addition to two others I had already created in earlier experiments, ab-set-value and ab-get-value, which allows setting a value by specifying a complex expression, where lists would map to structures, and nested lists to tables, and the “get” method would use the same type of mapping. I will probably keep these around, as they will be helpful for smaller structures and tables with a few entries. (Note that I am following a convention of having all functions that have to do with ABAP integration starting with “ab”. I am still in two minds about using “abap”, but typing those two extra characters over and over could make a lot of difference. I don’t know).
Function calls are another story. It turns out, when you call function modules dynamically, using the PARAMETER-TABLE syntax, the parameter table is not automatically filled with export values, or values that are changed. You have to explicitly populate the parameter table with whatever you want mapped from the function call. This presents a dilemma, as you may not always want every parameter present in each call, as the code inside often does checks depending on whether or not a parameter is present. My thinking for now is that I will by default have all parameters present, and then you will have to explicitly specify which parameters you don’t want.
The down-shot of having to make so many decisions is that the code-base becomes rather complex. While trying out this and that, you end up with a lot of things that will end up not getting used, and later on you scratch your head, wondering what you were doing there.
So, as you see, embarking on a project like this is fraught with complexity, mainly because you have to make some tough decisions between multiple possible ways of doing things. You can’t please everybody, and not everything is going to work in all cases. Probably I will make many mistakes along the way where I would like to go back and fix them, and that will probably never happen. But hey, it’s not all negative, it’s still fun.
Once I have function calls working, I would really like to tackle having a bit of a development environment, including a framework for storing and referencing (including) scripts in other scripts.