Tuesday, May 23, 2017

My favorite CL shortcuts

using cl shortcuts rather than long hand code

If I am going to write and give examples of programming in CL I need to start by explaining some of the CL language shortcuts I use. Perhaps "shortcuts" are not the right word, maybe "shorthand". Oh well, I am sure you will work out what I mean as you read this.

I use these shortcuts extensively in my CL code as for a couple of reasons:

  1. I think it is easier for someone else to understand the code I have written.
  2. It is just quicker to write, the faster I can write code the more I can get done.

I am going to start with my favorite three.

 

Comments overflowing onto multiple lines

The number of times I have seen this kind of thing in other's CL code:

  /* Comments over more */
  /* than one line */

Unlike some other programming languages if I put a plus ( + ) at the end of the comment line the next line(s) also become comments until an end of comment characters ( */) are found.

  /* Comments +
     over +
     more +
     than +
     one +
     line */

 

If condition comparisons

I don't have to type *EQ in the condition parameter of an If or Select's When command, I can just use the mathematical symbols.

Before I start explaining how this is done I need to introduce a couple of characters: the "not" and the "or".

¬ |
Not character
(top right corner)
Or character
(vertical line or unbroken pipe)

In my experience neither of these are mapped on my TN5250 emulation software's keyboard default configuration. I had to map a key to each character so I could use them. I will explain how they are used below

For my first example I am going to show an If command with an equal test, the same syntax in used in a Select's When:

  IF COND(&VAR1 *EQ 'A') THEN(...

  IF COND(&VAR1 = 'A') THEN(...

No surprises that a "not" symbol can be used in a not equal comparison:

  IF COND(&VAR1 *NE 'B') THEN(...

  IF COND(&VAR1 ¬= 'B') THEN(...

Greater than comparison:

  IF COND(&VAR1 *GT 'A') THEN(...

  IF COND(&VAR1 > 'A') THEN(...

Greater or equal to comparison:

  IF COND(&VAR1 *GE 'B') THEN(...

  IF COND(&VAR1 >= 'B') THEN(...

Less than comparison:

  IF COND(&VAR1 *LT 'B') THEN(...

  IF COND(&VAR1 < 'B') THEN(...

Less or equal to comparison:

  IF COND(&VAR1 *LE 'A') THEN(...

  IF COND(&VAR1 <= 'A') THEN(...

Then there are two more obscure comparison, which I have to admit I did not know until researching for this post.

Not greater than (isn't this the same as less or equal to?):

  IF COND(&VAR1 *NG 'A') THEN(...

  IF COND(&VAR1 ¬> 'A') THEN(...

Not less than (isn't this the same as greater or equal to?):

  IF COND(&VAR1 *NL 'A') THEN(...

  IF COND(&VAR1 ¬< 'A') THEN(...

For logical variables, in other words indicators, I can, just as I do in RPG, compare if it is or is not:

  IF COND(&FLAG) THEN(...

  IF COND(*NOT &FLAG) THEN(...

  IF COND(¬ &FLAG) THEN(...

The third example shows using the not character, rather than using the word *NOT.

If I want to add a "and" to my if statement I can do:

  IF COND((&VAR1 = 'A') *AND (&VAR2 = 'B')) +
       THEN(...

  IF COND((&VAR1 = 'A') & (&VAR2 = 'B')) +
       THEN(...

Here I can show how the "or" character can replace the word *OR:

IF COND((&VAR1 = 'A') *OR (&VAR1 = 'B')) +
     THEN(...

IF COND((&VAR1 = 'A') | (&VAR1 = 'B')) +
     THEN(...

 

Concatenating strings

I think these shortcuts are my favorites, and most used. There are three types of concatenation in CL:

  1. Simple concatenation – simply putting two strings together
  2. Concatenation trimming the blanks off the first string
  3. Concatenation trimming the blanks, but adding one blank

This is where we find that the vertical line character ( | ) assumes a different role.

In this first example I am just going to concatenate the two variables together with a simple concatenation:

01  PGM

02  DCL VAR(&LASTNAME) TYPE(*CHAR) LEN(15) VALUE('SMITH')
03  DCL VAR(&FIRSTNAME) TYPE(*CHAR) LEN(15) VALUE('JOHN')
04  DCL VAR(&FULLNAME) TYPE(*CHAR) LEN(30)

05  CHGVAR VAR(&FULLNAME) VALUE(&FIRSTNAME *CAT &LASTNAME)

06  CHGVAR VAR(&FULLNAME) VALUE(&FIRSTNAME || &LASTNAME)

The double vertical line ( || ) used in line 6 replaces the *CAT shown on line 5. The result of these two lines is the same:

&FULLNAME = 'JOHN           SMITH          '

To remove the trailing blanks in the first name variable I would use the *TCAT in place of the *CAT, or |< in place of ||.

07  CHGVAR VAR(&FULLNAME) VALUE(&FIRSTNAME *TCAT &LASTNAME)

08  CHGVAR VAR(&FULLNAME) VALUE(&FIRSTNAME |< &LASTNAME)

The result of this is:

&FULLNAME = 'JOHNSMITH                     '

Which is not pretty.

The third type of concatenation is one that RPG does not have, which in my opinion is a shame. This time I use the *BCAT or |>.

09  CHGVAR VAR(&FULLNAME) VALUE(&FIRSTNAME *BCAT &LASTNAME)

10  CHGVAR VAR(&FULLNAME) VALUE(&FIRSTNAME |> &LASTNAME)

The result is just what I desired.

&FULLNAME = 'JOHN SMITH                    '

If I am concatenating multiple strings together I think you will find that it is easier to understand what is happening using the shortcuts rather than the long handed version.

CHGVAR VAR(&EVERYTHING) VALUE(&FIRSTNAME *BCAT +
           &LASTNAME *TCAT ', ' *CAT &ADDRESS *TCAT +
           ', ' *CAT &CITY *TCAT ', ' *CAT &STATE +
           *CAT ' ' *CAT &POSTALCODE)

CHGVAR VAR(&EVERYTHING) +
         VALUE(&FIRSTNAME |> +
               &LASTNAME |< ', ' || +
               &ADDRESS |< ', ' || +
               &CITY |< ', ' || +
               &STATE |> &POSTALCODE)

In my opinion the second statement is clearer than the first. Both of these gives the same result:

&EVERYTHING = 'JOHN SMITH, 100 MAIN ST, ANYTOWN, CA 90000-0100'

 

If you know of any other shortcuts would like to share please either add it as a comment, below, or use the Contact form, on the right.

You can learn more about this from the IBM website:

 

This article was written for IBM i 7.3, and should work for earlier releases too.

10 comments:

  1. Aren't there implication of using a "|" in some character sets?

    ReplyDelete
    Replies
    1. Could be. But I would think IBM would have chosen a character that would not have caused problems in some of the more obscure CCSIDs.

      Delete
  2. Well organized is a great idea but this only works well and benefits until someone modify the codes by hitting F4 aids which majority people do that.

    ReplyDelete
    Replies
    1. No one can stop people from doing that, whether you use these shortcuts or not.

      I have found with my programming team that they F4 when adding a new command. After that they just edit it without using F4.

      Delete
    2. Far too many people reflexively use F4. Prompting should be used only when you actually need the help, which should be only occasionally.

      I say, if you consider yourself a "professional" on this platform, then you should know the majority of the subject matter of your profession, such as the basic parts of the commands you use routinely. Nor should you need most of the common keywords on most of those commands. For example, if you don't know that a program name is the first thing after a CALL command, optionally followed by a parameter list, then you have no business claiming to be a "professional" grade programmer on this platform.

      Delete
    3. Bullcrap. That's just snobbery in action. I have been coding CL for 30 years, and I still us F4 to prompt commands. I'm capable of doing it either way, but I know eventually someone will prompt something and just leave it - so it make more sense to me to organize the CL program (with comments and rational spacing so it's readable by anyone - whether expert or novice.

      Delete
  3. Another shorthand in CL is setting a logical variable using a logical expression, similar to RPG, which is useful for working with error indicators in display files. For example, instead of coding this:

    IF COND(&somenumber = 0) THEN(CHGVAR VAR(&IN71) VALUE('1'))
    ELSE CMD(CHGVAR VAR(&IN71) VALUE('0'))

    you can do this:

    CHGVAR VAR(&IN71) VALUE(&somenumber = 0)

    ReplyDelete
  4. I recall reading an article, many years ago, by Bryan Meyers, possibly called "A CL Style Guide". I've followed many of his recommendations. I particular like the omission of certain command keywords to make the code cleaner - less "noise" when I read it. For example, rather than:
    DCL VAR(&MYVAR) TYPE(*CHAR) LEN(10)
    /* I use this */
    DCL &MYVAR *CHAR 10
    /* or */
    CHGVAR VAR(&MYVAR) VALUE(&MYVAR || &YOURVAR)
    /* this */
    CHGVAR &MYVAR (&MYVAR || &YOURVAR)
    /* one more */
    IF COND(&MYVAR *eq '*YES') CHGVAR VAR(&YOURVAR) VALUE('X')
    /* this */
    IF (&MYVAR *eq '*YES') CHGVAR &MYVAR ('X')
    Less to read and sift through to get to the point of the code.

    ReplyDelete
  5. It has always bothered me that <> was not adopted by IBM for CL. It is consistently used EVERYWHERE else (well, except for WRKQRY).

    For concatenation in CL, I prefer a similar methodology to free format RPG. Instead of using *TCAT, *BCAT, <|, |>, and so on, I use || and %trim. Your example, using my technique, would look more like

    CHGVAR VAR(&EVERYTHING) +
    VALUE(%trim(&FIRSTNAME) || ' ' || +
    %trim(&LASTNAME) || ', ' || +
    %trim(&ADDRESS) || ', ' || +
    %trim(&CITY) || ', ' || +
    %trim(&STATE) || ' ' || &POSTALCODE)

    I find it easier and more obvious to read and debug. The other advantage is that you and other developers consistently use the same syntax.

    Just my 2 cents.

    ReplyDelete
  6. Even though those shortcuts are nice, I'm always sceptical about special characters, because they may not be international.

    Birgitta

    ReplyDelete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.