The Journey . . .    
Always Possibilities    

Avoid the Unexpected with Profile’s Early Warning System for Code Quality - PSL UCOPTS

Profile performance discussions tend to focus on speed, but equally important to the performance equation is the function of quality and its application throughout a Profile development project’s life cycle.  And while we have all heard the mantras espoused by the leading quality gurus, we should consider adding an old proverb to the quality chorus - “An ounce of prevention is worth a pound of cure.”Red Flag Profile Early Warning System UCOPTS

When applied to Profile development projects, the maxim simply means that it’s less expensive if you identify and correct issues early in your project’s development process (the ounce of prevention) than to try and fix them later (the pound of cure).  Further, it has been well documented that the costs to resolve defects that survive each phase of the development process (specification, design, development, QA, etc.) increase by an order of magnitude with each successive phase.  Fixing things later becomes exponentially more expensive!

So, how can you identify problems in your code as early as possible?  The Profile Scripting Language (PSL) provides an answer.  With PSL, you can identify and isolate issues in your code as you build it!  As PSL compiles an M program out of DATA-QWIK procedures, the PSL compiler interprets each command and evaluates it for syntax, and to a degree, logic.  If PSL identifies issues in the code, it reports them as errors or warnings.  Errors are, of course, severe and their occurrence does not allow the compilation to complete.  Warnings allow the procedure to be compiled, but also provide an alert to possible logic or performance issues that may affect the code.

How Do Warnings Work?
PSL uses a series of settings that determine which compiler conditions will cause a warning to be generated during the compilation process.  These settings are contained in the UCOPTS.ini file that resides at the top of your Profile directory.  UCOPTS contains 17 settings that control the warnings you will receive if your code contains conditions the compiler finds violate PSL rules.  UCOPTS also makes recommendations about what the settings should be based on the Profile version you are using to code.  For purposes of this blog, we will be showing work in Profile V7.x.

We won’t cover all 17 warnings in this blog, but we will discuss the scope variable warning, which can have the greatest direct impact on the quality of your work.  We would like to point out that this warning was found to be so critical, that it was changed from a warning to an error in Profile 7.5.x.

SCOPE - The Scope of a Variable Is Not Defined
In PSL, the TYPE command controls variable scope.  We should be setting the scope (the equivalent of the NEW command in M programs) at the top of the procedure and then again at the current stack level, if needed.  When the program decrements the stack via a QUIT, all non-public variables and objects created by a TYPE command at that stack level are deleted (effectively the equivalent of executing a KILL statement), and any values the variables might have had at the next highest stack level are restored.

PSL also supports “public” variable declarations.  The difference between a TYPE and a TYPE PUBLIC is the compiled M program issues a NEW command for the non-public TYPE declaration and no NEW command for the public one, thereby allowing its existing value to survive within the current stack level.

Looking at UCOPTS.ini, you will see:

 ;---- SCOPE
 ; Scope of variable is not defined
 ; Recommended settings:
 ; - Production environments for all versions: OFF
 ; - Development environments for Version 6.4: OFF
 ; - Development environments for Version 7.0 and higher: ON

The recommendation is “ON.”  When you compile your procedure, either by function @DBSPROCB or the “Test Compile” option in Workbench, you possibly may see warnings such as "%PSL-W-SCOPE:" followed by one of several warning messages:

Unscoped Variable
You did not pass the variable in as a parameter, or you did not issue a “type” variable declaration.  This is perhaps the most common warning you’ll see.

   set acn = GLTS
 %PSL-W-SCOPE: Unscoped variable: GLTS

If your code proceeds to testing containing the warning above, you have a good chance of receiving this:

 %GTM-E-UNDEF, Undefined local variable: GLTS

This one is pretty easy to fix.  Add a “type” declaration command for the variable, or add this variable to the parameter list of variables that are passed into this module.  Then, initialize your variable to a value.  A type declaration translates to the M “New” command, which ensures that a fresh copy of your variable is initialized.

And one more point for good measure.  The scope warning will help find typos.  In the example below, the variable ABC is fat-fingered:

 type String ABC = "", DEF = "", GHI
Zombies Profile Early Warning System UCOPTS
 set GHI = ACB_DEF

   set GHI = ACB_DEF
 %PSL-W-SCOPE: Unscoped variable: ACB

Undefined Variable: <X>
In some cases, PSL can identify variables that have been declared, but not set with a value:

 type String VAR

 %PSL-W-SCOPE: Undefined Variable: VAR

Variable Declared More Than Once
Within the same scope the same variable is declared more than once.

type Number SEQ2, TRC, TIM2, TAMT, TRC

   type Number SEQ2, TRC, TIM2, TAMT, TRC
 %PSL-W-SCOPE: Variable declared more than once: TRC

Typically, this error occurs because you forgot you declared the variable in one place and then declared it a second time in error.  So, you need to ask: Did I mean to use this variable again, or did I make a mistake?  A good way to avoid this issue is to perform all your declarations at the top of the procedure, function or subroutine, which allows you to manage all your variables in one place.

Ignored change of <variable> from NEW to PUBLIC
Similar to the “Variable declared more than once” warning, we’ve issued a TYPE command and in the same scope also issued a TYPE PUBLIC command.  This error can be harmless, but is it really something you meant to do?

 type public String VAR
 type String VAR

   type public String VAR
 %PSL-W-SCOPE: ignored change of VAR from NEW to PUBLIC

Return Parameter Ret <X> Not Accepted for NORET <Y>
In this case, you are telling the calling code to expect a return variable, except that the linetag being called does not specify that it’s supposed to return the variable.

   set ABC = $$ABC(.dep, ZEFD)
 %PSL-W-SCOPE: Return parameter ret dep not accepted for NORET RecordDEP dep

In this case, the function ABC looks like this:

 public ABC(RecordDEP dep, Date EFD)RR Signal Profile Early Warning System UCOPTS

To resolve this warning, either remove the "." from the call to function ABC or add "ret" to before the declaration of RecordDEP in the function ABC:

 public ABC(ret RecordDEP dep, Date EFD)

Variable X May Not Have Been Instantiated
For whatever reason, PSL cannot be certain that you instantiated an object.  This warning originates when you make an instantiation conditional, or when you perform it in a loop.

   set ttx.tjd = chist.tjd
 %PSL-W-SCOPE:  Variable chist may not have been instantiated

There is no problem with conditional instantiation, but you need to be certain that the objects you require will exist under all circumstances to avoid runtime errors.

For example, consider the following code.  (Please note that this example is written to force the Scope warning.  This is definitely not the way we’d want to write this function for optimal results.)

 START(RecordACN acn)
     type Number BAL = 0, CID = ""

  type RecordDEP dep()
  type RecordLN ln()

  type ResultSet rs ="CID", "RELCIF", "ACN = :acn.acn")
  while do {
    if acn.cls = "D" set dep(rs.getCol("CID")) = Db.getRecord("DEP", "CID = :rs.getCol(""CID"")", 1)
    else  set ln(rs.getCol("CID")) = Db.getRecord("LN", "CID = :rs.getCol(""CID"")", 1)

  for  set CID = dep(CID).order() quit:CID.isNull() do {
    set BAL = (BAL + dep(CID).bal)
  for  set CID = ln(CID).order() quit:CID.isNull() do {
    set BAL = (BAL + ln(CID).balcmp)

  return BAL

   set BAL = (BAL + dep(CID).bal)
 %PSL-W-SCOPE:  Variable dep(CID) may not have been instantiated
 At source code line: 69 in subroutine: START

   set BAL = (BAL + ln(CID).balcmp)
 %PSL-W-SCOPE:  Variable ln(CID) may not have been instantiated
 At source code line: 72 in subroutine: START

Are You Convinced to Turn It On?
Here is all you need to do:

  1.  Review the warnings section of the UCOPTS.ini file.  Change the #WARN SCOPE setting to “ON”.

  2.  While you’re in the warnings section you may want to also consider turning other warnings on to see how they affect your work.
       You can always turn them off later.

  3.  At the GTM prompt in Profile, do bootUCOPTS^UCGMCU(). This utility will recompile the directory’s copy of UCOPTS.m with the
       new settings in the .ini file.

  4.  Cycle the PBS servers in your directory.

  5.  UCOPTS will now be available during both native Profile and Workbench sessions.

Every Profile development directory that has its Scope warnings turned on in UCOPTS.ini enables an upfront quality check that will help prevent larger issues from developing later in a Profile project’s life cycle.  The early warning system also significantly reduces the threat of incurring additional resource-related costs down the line.  If ever there was an ounce of prevention, it surely can be found in UCOPTS.


Lighthouse Profile Early Warning System UCOPTS

The developers and analysts of Mozaic Group Partners are among the most expert and experienced Profile people in the world when it comes to identifying performance issues and providing brilliant solutions for Profile client institutions.  If you have questions about your system’s performance or think your team could benefit from a Profile code review session or code workshop, contact us.  We are happy to help.

If you found this article helpful, please share it with someone who might also benefit from its content.







We Are Mozaic Group Partners

We are the leading, independent, global provider of Profile banking application services. We partner with Profile institutions to develop, implement, fix, enhance and protect the investment your institution has made in its banking system. With more than 280 client engagements in 21 countries and counting, we have helped more institutions solve their Profile issues than any other services provider on the planet.

Providing A Global Reach for Profile Services

MGP Website Country Map FINAL 3 22 19