Encouraging Mere Mortals
December 16, 2009 Hey, Ted
You’ve got to be kidding, right? I’ve generally thought you were trying to show better approaches for coding issues. Are you advocating falling back to bad fixed-format techniques? The only conclusion that makes sense is that you’re testing the waters to see if anyone’s paying attention. Or just trying to drum up traffic to your site.
What about a data structure that would have performed the split? Or an EVAL operation using built-in functions to convert to character format, substring it, then convert it back to the decimal fields? Both of those wouldn’t rely on the “magic smoke” multiply and divide, or falling back to fixed-format techniques that will have newer coders scratching their heads.
Whatever your real motivation is for this article, it definitely was a disappointment.
Spencer’s email came in response to Are MOVE and MOVEL Obsolete?, which appeared in the July 15, 2009, issue of Four Hundred Guru. I chose to lead with his comments for one reason only–his were the least complimentary.
Most who responded simply offered the ways they would code the examples I gave, for the most part suggesting one or both of the two techniques to which Spencer alluded. Several recommended the use of a data structure to divide the two fields. The following is representative.
D DS D AccountNumber 8 0 D Company 2 0 overlay(AccountNumber) D Customer 6 0 overlay(AccountNumber:*next)
The author of this code assumed that it was OK for Company and Customer to overlay AccountNumber, although my example showed three distinct scalar variables.
Others preferred the use of nested built-in functions–usually %UNS(%SUBST(%EDITC or something similar.
Company = %uns(%subst(%editc(AccountNumber:'X'):1:2)); Customer = %uns(%subst(%editc(AccountNumber:'X'):3:6));
There was some sentiment that MOVE and MOVEL should have been included as supported op codes in free-format calculations, but that viewpoint was definitely in the minority.
And one reader, Jon, informed me that he was not afraid.
To those who kindly responded, I addressed another, slightly different example that I had not included in the article:
There are three variables–PeriodDate, BeginDate, and EndDate. They are defined as seven digits packed decimal, with zero decimal places, and they hold dates in CYYMMDD format.
Assume PeriodDate has a valid date in it. I want to set the first five digits of BeginDate and EndDate equal to the first five digits of PeriodDate. However, I want to set the last two digits of BeginDate to 01 and the last two digits of EndDate to 31.
In fixed-format calcs, I might do something like the following:
move PeriodDate BeginDate move PeriodDate EndDate move 01 BeginDate move 31 EndDate
In case you want to use a different approach entirely, I’ll tell you that BeginDate and EndDate are used as host variables in an SQLRPGLE program.
where PayDate between :BeginDate and :EndDate
Here are a few of the responses I received.
D DS D PeriodDate 7 0 Inz(0) D Period5 5 0 Overlay(PeriodDate:1) D DS D BeginDate 7 0 Inz(0) D Begin5 5 0 Overlay(BeginDate:1) D Begin67 2 0 Overlay(BeginDate:6) D DS D EndDate 7 0 Inz(0) D End5 5 0 Overlay(EndDate:1) D End67 2 0 Overlay(EndDate:6) /Free Begin5 = Period5; End5 = Period5; Begin67 = 1; End67 = 31;
What do you think of that? Four calcs replaced by 15 lines of code–11 lines of D specs and four calcs.
d pdate s 7p 0 d bdate s 7p 0 d edate s 7p 0 /free bdate = (%dec(%subst(%editc(pdate:'X'):1:5):7:0)*100) + 01; edate = (%dec(%subst(%editc(pdate:'X'):1:5):7:0)*100) + 31;
Nested BIFs and more multiplication. Is this intuitive?
BeginDate = (%Int(PeriodDate/100)*100) + 01; EndDate = (%Int(PeriodDate/100)*100) + 31;
Now we’re back to multiplication and division, like the example from my article. The author reduced four lines of code to two, but is it easier to understand?
d periodDate s 7p 0 d endDate s 7p 0 d startDate s 7p 0 d getStartOfMonth... d pr 7s 0 d inputDate 7s 0 Value d getEndOfMonth... d pr 7s 0 d inputDate 7s 0 Value /free BeginDate = getStartOfMonth( periodDate ); End Date = getEndOfMonth( periodDate ))); /end-free p getStartOfMonth... p b d pi 7s 0 d inputDate 7s 0 Value d mapDate ds d cyymmdd 7s 0 d century 1s 0 Overlay(cyymmdd) d yearAndMonth 4s 0 Overlay(cyymmdd: *Next) d day 2s 0 Overlay(cyymmdd: *Next) /free cyymmdd = inputDate; day = 01; Return cyymmdd; /end-free p getStartOfMonth... p e p getEndOfMonth... p b d pi 7s 0 d inputDate 7s 0 Value d workDate s d /free workDate = %Date( inputDate: *CYMD) + %Months(1); workDate = workDate - %Days( %SubDt( workDate: *D )); Return %Dec( workDate: *CYMD ); /end-free p getEndOfMonth... p e
This is a very well thought-out solution, provided it is implemented as routines of a service program. However, if someone asked me how to replace the four MOVEs with free-format calcs and I showed them this code, they’d probably lose their interest in free-format code immediately.
BeginDate = PeriodDate / 100; EndDate = (BeginDate * 100) + 31; BeginDate = (BeginDate * 100) + 01;
This solution is full of math, which I don’t like. The reader would have to work through that math to figure out what was going on. But it’s short, and with a good comment, would do a fine job, as would the other solutions.
Thanks to all who responded. Judging from the way you expressed yourself, I sense that most of you enjoyed the exercise. We may have to do this again sometime.
I’d like to make a few comments and observations.
1. Almost all of the replies I received were most cordial and completely devoid of animosity.
2. I consider all the solutions that I received to be good and perfectly acceptable ones. I am not belittling anyone’s code.
3. Evidently, some programmers don’t mind writing more code to accomplish the same task. If replacing two MOVEs requires a four-line data structure and an EVAL, that’s OK with them.
4. In the same way, some programmers don’t mind replacing simple operations with more complicated ones. If replacing a MOVE requires nested functions and/or mathematical operations, that’s fine.
5. Most who responded did not address the question of the goodness or badness of MOVE and MOVEL, but simply offered the ways they would code the examples I gave. That is to say, it appears to me that they simply don’t care–as long as they have a free-format way to accomplish what needs to be done, they contentedly get on with life.
6. Some readers did imply or state that MOVE and MOVEL are undesirable, but few provided a reason why they were bad. Taken together, the reasoning appears to be the following:
7. Only one reader offered a detailed defense of the position that MOVE and MOVEL are intrinsically bad.
“The problem I have with any MOVE/MOVEL solution is that unless one is lucky enough to be able to use such obvious names as the ones you have used, you would never in a million years guess from the code what was happening–particularly if both parts were not being split out. Even with obvious names, without studying the data type and size of the fields you still don’t know exactly what is going on.”
I’m not sure I understand. To code a string of nested BIFs, one must also be familiar with the data types and field sizes of the referenced identifiers. And whether variable and field names are obvious or not has nothing to do with the relative merits of this op code versus that one, as the same names must be used in either case. But I’ll continue to give it thought.
8. Limiting oneself to an accepted set of programming language features does not transform poorly designed algorithms into good ones. Coding by the seat of one’s pants is far worse than using politically incorrect op codes.
9. The use of an editing function to convert numeric data to character type does not seem obvious or self-documenting to me.
10. I chose the multiplication and division technique in my article because it is typical of code that I have seen written in various non-business programming languages through the years, and because I considered it the worst technique. In hindsight, maybe I should have also included the data structure and nested-BIFs methods.
11. I don’t use MOVE or MOVEL in my RPG code. “Miss” and “use” are two different words with two entirely different meanings. I favor the nested BIFs technique.
12. I don’t mind a little controversy every once in a while. I hope you don’t either. I have more topics.
13. Finally, why did I write about MOVE and MOVEL? For one reason only: I wrote to encourage those who have expressed to me such sentiments as “Most of your material is too technical for me” and “I don’t have the slightest idea what you’re talking about”. These people represent a readership that I don’t want to lose. Or rather, a readership that I hope I haven’t already lost. These are people who do a dependable job writing and maintaining applications, but find it difficult to keep up with the continual enhancements to the RPG compiler.
One could argue that a person who makes his living writing source code should keep abreast of the latest developments and master them as soon as they become available. Ideally, I agree with that. But practically, I do not. People are busy, not only with work, but with life.
If you place yourself in this category, I have a special message for you: It’s OK. Keep reading. Keep studying. Keep trying. Ask questions. But whatever you do, don’t beat yourself because you still find it easier to use SUBDUR than the date/time BIFs.
As I tend to say every year at this time, I want this newsletter to be of benefit to all. The gurus and the mere mortals. The guy who cut his teeth on the System/38 and the guy who’s never seen a System/38. The YiPs and the old fossils. Those who live to work and those who work to live.
At this time of year, my family and I celebrate Christmas, in both the religious and secular senses. If you celebrate a holiday, may it be a joyous occasion. I wish you and your loved ones health and happiness in the coming year.