Defining variables in a local scope.

Posted by dbeavon on 22-Nov-2019 21:41

I have been always been wary of defining and initializing variables in the local scope of a loop.

Does the following code bother anyone else?  In my opinion it seems to imply that the variable named v_Init will revert itself to "X" on every iteration ... but that implied initialization doesn't actually occur.

DEFINE VARIABLE v_Loop AS INTEGER NO-UNDO.
DO v_Loop = 1 TO 100:
   
   DEFINE VARIABLE v_Init AS CHARACTER NO-UNDO INIT "X".
   IF v_Loop = 10 THEN v_Init = STRING(v_Loop).
   
   MESSAGE v_Loop v_Init.
   PAUSE.
END.

As it turns out, once v_Init becomes "10" it never goes back to "X" again.

I suppose it is just a gotcha that ABL programmers must know about.  I suspect that this variable, v_Init has the same scope as v_Loop but we are allowed to define it in the loop as a matter of convenience.  However, the convenience comes at a price of not being totally certain how the code will actually execute.

Thanks, David

All Replies

Posted by Thomas Mercer-Hursh on 22-Nov-2019 21:57

Not only is it not going to get initialized, it shouldn't because it is pointless to define it every time.  If there was a need to initialize it ... which is not indicated by the code above ... then merely including a v_Init = "X". in the loop would get the job done unambiguously and without anything like the overhead of the define.

Posted by onnodehaan on 22-Nov-2019 22:01

I always define variabels and buffers right after input/output parameters.

Also hate to see them scattered around the routine

Posted by Thomas Mercer-Hursh on 22-Nov-2019 22:08

It is good to define them local to the block in which they are used to limit their scope ... just not like this!

Posted by dbeavon on 22-Nov-2019 22:27

>> ... define them local...

Yes, it is helpful to define variables in proximity to where they are used.  I hate it where I'm looking at an ABL program on line 5,000 in a triple-nested loop and someone starts using a variable that is defined waaaay at the top ... so I have to stop what I'm doing scroll up to the beginning of the file. (although tooltips in the IDE help to some extent).

I think the problem is that ABL gives you the *false* impression that variables can actually be scoped and initialized in the loop.   Whether that makes sense to do (in terms of performance) is another topic.   Limiting the scope of variables is more about avoiding bugs and improving the readability of the code. 

In C#, for example, my variables are scoped as you would expect and  it would be possible (theoretically) to reuse variable names in the same method (if they are declared in the scope of a different loop).

            for (int i = 0; i < 100; i++)
            {
                string v_Init = "X";
                if(i == 10) { v_Init = i.ToString(); }

                System.Diagnostics.Debug.WriteLine("Message : " + v_Init);
            }

            for (int i = 0; i < 100; i++)
            {
                int v_Init = 1;

                System.Diagnostics.Debug.WriteLine($"Message {v_Init}");
            }

You can see above that the loop variable (i) can be declared and initialized twice.  So can the "v_Init" which is local to every iteration of those loops.

Posted by onnodehaan on 22-Nov-2019 22:31

I feel that if you have a routine of 5000 lines you should break it up in smaller pieces.

When I have to scroll more than a screen, I'm usually inclined to break stuff up into smaller funtions/procedures. So scrolling to the top is almost never necassary.

To me a variable that is only used in a small piece of code in a big routine, indicates that that piece of code should be made into a function/procedure.

Posted by Patrick Tingen on 23-Nov-2019 14:31

I like my variables' scope to be as small as possible and I define them at the beginning of where the scope starts. Defining them in the middle of the scope, like in the example above, might give new programmers the idea that the variable is scoped to the loop, which it isn't. I think you should program to get the least number of WTF's in your code and defining variables halfway the code does not help IMO.

If you have code blocks that are 5000 lines of code, then they are about 4900 lines too long. Recently I modified some of these monsters to become more manageable, and I found that taking small parts out of the code and moving them to their own internal procedure / function / external procedure greatly helps in keeping the code clear. It also greatly reduces the need for variables, because often you don't need anything more than the output parameters of your procedure.

This week I split up a large save-routine. It did a lot of checks to see whether the record could be saved. I moved all checks to individual procedures, even when they were only 5-10 lines of code. This keeps it clear and simple.

This thread is closed