Using EQU with dimensioned arrays in the debugger

Skip to first unread message

Joe G

Jul 17, 2022, 8:09:51 PMJul 17
to Pick and MultiValue Databases

For a many time I've used dimensioned arrays for all my file reads and writes. It can cut down the number of string operations when compared to dynamic arrays but the main reason I've done it is that it enforces field names across the system.

I'm trying to convince other developers to do it. I'm getting pushback because the Universe RAID debugger doesn't understand equates.  Take this example;


In the raid debugger  you can't see the value of INVOICE.DATE;

Symbol not found.

You have to reference the array directly

STRING: t r L=0 `'


It's always seemed strange to me that the equate feature doesn't integrate with the debugger. Equate isn't a new feature. Some of the developers seem to think there's a compiler option to include equate symbols but I haven't been able to find anything.

Anyone have any ideas or suggestions?


Jim Idle

Jul 18, 2022, 12:21:57 AMJul 18
I am not 100% sure about Universe but would think that they handle the EQU stuff using a pre-processor. That preprocessor then elides the equate values. jBASE also uses a pre-processor, but it generates a symbol table for equates that are essentially duplicate definitions of a variable.  For instance:

~/tmp ᐅ cat t.b
DIM A(10)
II = 66


jcompile -o t t.b.  # Or BASIC/CATALOG

~/tmp ᐅ ./t -Jd
Option -d seen on command line
Source taken from ./t.b
0003 II = 66
jBASE debugger->s
Source taken from ./t.b
0004  CRT II
jBASE debugger->v  
  A(1)                      : (UNASSIGNED)
  A(2)                      : (UNASSIGNED)
  A(3)                      : (UNASSIGNED)
  A(4)                      : (UNASSIGNED)
  A(5) (DUP)                : 66
  A(6)                      : (UNASSIGNED)
  A(7)                      : (UNASSIGNED)
  A(8)                      : (UNASSIGNED)
  A(9)                      : (UNASSIGNED)
  A(10)                     : (UNASSIGNED)
  II                        : 66

So, I guess nobody asked for that feature for Universe.

I am not as convinced as I used to be that this technique is that useful. When programming, it might not be obvious that the EQU is part of an array. Though I see you are using a naming convention that probably helps with that. 

Also remember that every MAT READ and WRITE then has to pull apart and put back together the array. Given how good CPUs are these days, then it’s probably irrelevant; but worth considering. And finally, there are som quirky implementation of the MAT methods that completely screw up if there are more dynamic elements than there are DIM elements. I seem to think that Universe is one of those implementations. It’s an area where there is little compatibility between implementations.

So, I don’t think you have any way to do that in Universe, unless there is indeed a compiler option to do it - but it seems like that would an option that was ON by default, if it was there.


You received this message because you are subscribed to
the "Pick and MultiValue Databases" group.
To post, email to:
To unsubscribe, email to:
For more options, visit
You received this message because you are subscribed to the Google Groups "Pick and MultiValue Databases" group.
To unsubscribe from this group and stop receiving emails from it, send an email to
To view this discussion on the web visit

George Gallen

Jul 18, 2022, 11:04:15 AMJul 18
it makes sense - EQU doesn't create any variables, there is nothing to find.

It's just a search and replace prior to compiling - so you'd have to look for invoice.rec(1) - I've not
used RAID often, so I don't know if you can get specific index locations in the variable locations (ie. (1) vs the entire matrix)


From: <> on behalf of Joe G <>
Sent: Sunday, July 17, 2022 8:09 PM
To: Pick and MultiValue Databases <>
Subject: [mvdbms] Using EQU with dimensioned arrays in the debugger

Joe G

Jul 18, 2022, 11:32:15 AMJul 18
to Pick and MultiValue Databases
I guess having a preprocessor handle the equates makes it harder to integrate. Maybe it's not a feature that's used much by the MVDB community.  I'm working on a large system developed over many decades. Each developer came up with their own field names and even record names.  Sometimes they read INVITM.  Other times it's R.INV.  Trying to find programs that update specific files and fields it difficult at best. The thing I like about using equates is that it enforces both the item and field names.  

I do use a standard variable prefix for all the fields in the equates.  Equates make the code more readable. We have lots of lines like this: R.INV<8> = R.CM<4>.  If you don't have the attribute numbers in both files memorized it doesn't tell you anything.  INV.CUST.STATUS = CM.STATUS is easier to read.  Our programs are almost always written with the attribute numbers. Even before I started using equates I would extract the attribute to a variable to make it more readable. 

Does anyone know of any utilities that maps reads/writes and updates from the source program?  I've worked on writing one but reliably pulling that information form the source code is also difficult. It would have to find all the open statements and the file variables used then find all the reads/writes/deletes using that file variable to identify the item variable names and finally find all the attribute references to those item variables.

Joe G.

Rex Gozar

Jul 18, 2022, 12:12:53 PMJul 18

Regarding equating attributes, you've described one way I've seen it done, but there is another way.

Instead of:


you would only equate the attribute number, e.g.:


That way, the same equate could be used in both dimensioned and dynamic arrays.



* both dimensioned and dynamic arrays would use the same attribute names

* allows program to have two different records from the same file; e.g., BILLTO.ITEM<CUS.CITY.AMC> and SHIPTO.ITEM<CUS.CITY.AMC>

* unique attribute name is searchable across all program files

* easier to differentiate between a scalar variable and an assignment


* does not standardize the variable name

* expression is longer (more characters to type)

See the PickWiki page for a deeper explanation.

Regarding a utility that maps reads/writes and updates from source programs, I have written my own programs to convert attribute "magic" numbers to attribute names. What you describe about finding all the OPEN statements and file variables used is pretty much what I had to do. All of our software now uses attribute names.

One very important point to remember is to have ALL your source code (programs, dictionaries, Q-pointers, etc) in a source code control system first, before making sweeping changes. I mean git, or at least cvs.


Joe G

Jul 19, 2022, 10:33:38 AMJul 19
to Pick and MultiValue Databases
Hi Rex,

That's a good idea! Great minds... My include items often have a second set of equates with a $ appended so I can use them if dealing with dynamic arrays:



You're correct on the pros and cons.

Is your mapping program available?  I'd like to give it a try. Our system would be an acid test.

Joe G.

Jeff Teter

Jul 20, 2022, 10:10:55 PMJul 20
to Pick and MultiValue Databases

Joe - good to see you posting here. Let me extend this paradigm just a bit further.

 I, too, like Rex's idea of using equated integers and using them for either dimensioned or dynamic variables. I'd suggest taking the idea even a bit further...

  1. For the equated variable name, use a standard format that uses the structure "group.subject.modifier.scope'. Using this model makes the various pieces of data easy to work with in editors providing intellisense, e.g., all entries are sorted by subject, modifier and scope, making selection simple.
    1. The 'group' is the file name (or reference) or a logical section of data
    2. The 'subject' is the topic under discussion. In Joe's example above, 'DATE' is the date of the invoice.
    3. The 'modifier' allows various uses of the subject. For instance, we might use 'INVOICE.DATE.ORDER' or 'INVOICE.DATE.SHIP'. 
    4. 'Scope' refers to various instances of the same subject and modifier. We might want to use 'INVOICE.DATE.ORDER.CLOSED' vs 'INVOICE.DATE.ORDER.STARTED'. In the particular industry that I work in, I use variables such as 'LOAN.INTEREST.PAID.YTD' or 'LOAN.INTEREST.ACCRUED.YTD'
    5. Note that the names above are the reference name but not the column name used on reports. That might be abbreviated or altered to fit the needs of reporting, etc.
  2. The team should agree on standard abbreviations. In the example above, 'YTD' refers to 'Year To Date' but I've seen in old dictionaries where  'DATE' is abbreviated as 'DAT', 'DT', 'DATE' or (someone with a German flair) 'DATUM'.
  3. Dictionaries can/should be built using the subject/modifier/scope. So, in the INVOICE file, I would have a dictionary called 'DATE.ORDER' that would correspond to the include line. 
  4. If an attribute is further broken down by values with particular purposes, the attribute is referenced as 'attribute.INFO' and the values are given more specific names. For instance, attribute 10 might be 'INVOICE.NAME.INFO' and value 1 is used to store the first name, so it would be referenced as 'INVOICE.NAME.FIRST', etc. In this case the include for INVOICE.NAME.INFO would be equated to 10 and the include for INVOICE.NAME.FIRST would be equated to 1. Then, in programs, I can have a statement line 'INVOICE.REC< INVOICE.NAME.INFO, INVOICE.NAME.FIRST > = "Jim"'.
  5. The include line can be extended with a comment to include data type, length, decimals, justification and description. This, then, gives enough information that dictionaries can be built from the include record. This makes the file self-documenting and the description can be carried from the include file to line 1 of the dictionary.

Brian Leach, in England, has suggested a structure for documenting dictionaries which is very helpful and it works for UniVerse style dictionaries as well as Pick 'S'-type and 'A'-type dictionaries. Since Pick/UniVerse flavors allow multiple dictionaries for a data file, I have extended Brian's work to include a prefix to the description that is for dictionary group. This is an integer that represents a sum of the various dictionary files in which a dictionary is to occur. For instance, the dictionary created with the file is assigned a value of 1 (In Joe's example, this would be the dictionary for the 'INVOICE' file). A dictionary file created for ODBC might be called 'ODBC.INVOICE' and would be assigned a value of 2. If a dictionary occurs in both files (with the same format, etc.), the dictionary group would be 3 (1+2).

 Using a subroutine, I can pull all of the data from dictionaries and, if necessary, export them to text files. Using any of the standard compare tools, I can then compare, by example, the INVOICE and the ODBC.INVOICE dictionaries.

 The other big advantage to using the equated values is that is someone gets a wild hair and moves a particular element, say from attribute 1 to attribute 5, the included reference to the file does not need to change, only the reference in the include file, followed by re-compiling any programs using that include file. Hopefully, though, we're not moving fields around too often!

Gerd Förthmann

Jul 21, 2022, 2:35:26 AMJul 21

Who in his right mind would want to change the attribute positions in a file?

The only time in my career that I was told to do that was by a so-called analyst who also told me that I was not allowed to use multi-values in data files because according to the school of Codd they are illegal.

That's UK government for you. Hire a Pick analyst-programmer for 35 GBP an hour and an "analyst" who doesn't know Pick at all for 50 to tell the programmer how to do his job. No wonder they can't even organize a piss-up in a brewery.

Jim Idle

Jul 21, 2022, 2:39:44 AMJul 21
Interesting that nobody has commented on the fact that jBASE actually does support what the OP asked for. I wonder now if this post made it to the group.

Martin Phillips

Jul 21, 2022, 3:45:22 AMJul 21

If we are widening the response beyond UV, it is worth adding that OpenQM has a compiler option to record equate tokens used in the program in the symbol table. They can then be used in the debugger as the OP wants.


From: <> On Behalf Of Jim Idle
Sent: 21 July 2022 07:40
Subject: Re: [mvdbms] Using EQU with dimensioned arrays in the debugger



Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 855.577.4323
Contact Customer Support:
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences -
Privacy Policy -

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.

Joe G

Jul 21, 2022, 3:39:47 PMJul 21
Hi Jeff!!!

Good to see you're here too! 

You've got some good ideas there. You should add them to the pickwiki that Rex mentioned:

After reading your post I was looking at my utilities file and checked a WRT.BACKUP subroutine.  Check out the copyright at the top;

*               108 E. 8TH STREET
*               HORTON, KS  66439
*               913/486-2113

The header was 52 lines with sections for variables changes, groups locked, inputs, outputs, etc.  The actual code was only three lines.  You were using coding standards by in April of '88!

Joe G

Jul 21, 2022, 3:42:24 PMJul 21
to Pick and MultiValue Databases
It was good to hear that someone had put it in.  It doesn't help me because moving to jBASE is out of the question in my case.  It didn't even exist when the bulk of this code was written.

Joe G

Jul 21, 2022, 3:47:05 PMJul 21
to Pick and MultiValue Databases
That's good to know but not surprising. OpenQM is a well done project! Since you're working with Rocket maybe you could put a bug in someone's ear....

 It seems like it should have been added to everything when the equate feature was added to basic.  Strange that it's still mostly not supported.

Gerd Förthmann

Jul 21, 2022, 4:29:32 PMJul 21

Most likely because not many people find it useful or see a need for it.

James A

Jul 21, 2022, 4:44:08 PMJul 21

At DocMagic we require all files to use EQU’s on dimmed arrays; the array is usually in a named common with the name of the file (there are legacy exceptions).


Naming conventions are essential to make the code clear and avoid collisions and dreaded ‘global common bugs’ (which can and do happen other ways; but that’s the downside of not having an object oriented language in general).


Here’s an example of our INPUT <screen> custom ‘Bottom Line’ options setup that shows lots of our coding conventions developed over 35 years:


  • All equates in a program named ‘EQU.<filename>’
  • Array is <file>.REC
  • Size of the ‘.REC’ array is in <file>.C (for ‘C’ounter): for loops over the entire array etc (ex: initializing it).
  • May be in <file>.COMMON; but may be in a more global COMMON.
  • All equated names start with the file name and ‘$’; remainder is mixed case
  • Append ‘S’ for Multi-Valued field (append ‘SS’ for multi-sub-valued)
  • Start the name after the ‘$’ with the C/D Group name if applicable (‘Bottom’ below)
  • Comments are <2-spaces>;*<2-spaces>; or line up when possible/convenient
  • Keep C/D Groups together; if you haven’t left enough available attributes (don’t do that next time! Always leave unused ‘gaps’ in C/D groups!), put the attribute in numerical order with a ‘see xxx’ comment’; and put a commented version in order in the group (see SCREEN$BottomHelpS below)





common /INPUT/ SCREEN.REC(98)      ;*  See EQU.SCREEN and SCREEN.C




  equate SCREEN.C to 98


  equate SCREEN$IdSeparator    to SCREEN.REC(13)  ;*  Multi-part key separator ('~','_', etc)


  equate SCREEN$AllowPartialId to SCREEN.REC(14)  ;*  'T'op, 'M'iddle, 'B'ottom, or 'N'one allowed blank (old SCR.KEY.PARTIAL)

  equate SCREEN$MiscDisplays   to SCREEN.REC(15)

  equate SCREEN$PostInputSub   to SCREEN.REC(17)


  equate SCREEN$PageHeadingS   to SCREEN.REC(18)  ;*  All we have for each Page now


  equate SCREEN$BottomHelpS    to SCREEN.REC(19)  ;*  (see below)


  equate SCREEN$BottomOptionS  to SCREEN.REC(21)  ;*  Custom bottom-line options

  equate SCREEN$BottomDescS    to SCREEN.REC(22)  ;*  and (short) descriptions

  equate SCREEN$BottomActionS  to SCREEN.REC(23)  ;*  See SCREEN '?' for Actions syntax

  equate SCREEN$BottomLogicS   to SCREEN.REC(24)  ;*  MagicLogic to turn this option on/off

  *quate SCREEN$BottomHelpS    to SCREEN.REC(19)  ;*  Full line of help text for '?' option


Since we use this is ALL CODE, it never takes more than a few seconds to find all the usages of a data point:




/u/dsisrc/RMS.BP/EQU.SCREEN:* 28.Apr.2022 james: MV-115: New field SCREEN$BottomHelpS

/u/dsisrc/RMS.BP/EQU.SCREEN:  equate SCREEN$BottomHelpS    to SCREEN.REC(19)  ;*  (see below)

/u/dsisrc/RMS.BP/EQU.SCREEN:  equate SCREEN$BottomOptionS  to SCREEN.REC(21)  ;*  Custom bottom-line options

/u/dsisrc/RMS.BP/EQU.SCREEN:  equate SCREEN$BottomDescS    to SCREEN.REC(22)  ;*  and (short) descriptions

/u/dsisrc/RMS.BP/EQU.SCREEN:  equate SCREEN$BottomActionS  to SCREEN.REC(23)  ;*  See SCREEN '?' for Actions syntax

/u/dsisrc/RMS.BP/EQU.SCREEN:  equate SCREEN$BottomLogicS   to SCREEN.REC(24)  ;*  MagicLogic to turn this option on/off

/u/dsisrc/RMS.BP/EQU.SCREEN:  *quate SCREEN$BottomHelpS    to SCREEN.REC(19)  ;*  Full line of help text for '?' option

/u/dsisrc/RMS.BP/INPUT.MAIN:* 28.Apr.2022 james: MV-115: '?' Help on bottom line options; use SCREEN$BottomHelpS

/u/dsisrc/RMS.BP/INPUT.MAIN:  NUM.BOT.OPTS = dcount(SCREEN$BottomOptionS, @VM)      ;*  Now in Commons

/u/dsisrc/RMS.BP/INPUT.MAIN:    Logic = SCREEN$BottomLogicS<1, N.B.O>

/u/dsisrc/RMS.BP/INPUT.MAIN:      OPTS<-1> = SCREEN$BottomOptionS<1, N.B.O> ; DESCS<-1> = SCREEN$BottomDescS<1, N.B.O>

/u/dsisrc/RMS.BP/INPUT.MAIN:    locate( O, SCREEN$BottomOptionS, 1; N.B.O ) then  ;*  Entered a user-defined option?

/u/dsisrc/RMS.BP/INPUT.MAIN:      BL.ACT = SCREEN$BottomActionS<1,N.B.O>    ;*  TAKE ACTIOOOOOOWN

/u/dsisrc/RMS.BP/INPUT.MAIN:  if SCREEN$BottomOptionS # '' then

/u/dsisrc/RMS.BP/INPUT.MAIN:    NUM.BOT.OPTS = dcount(SCREEN$BottomOptionS, @VM)      ;*  Now in Commons

/u/dsisrc/RMS.BP/INPUT.MAIN:      Logic = SCREEN$BottomLogicS<1, N.B.O>

/u/dsisrc/RMS.BP/INPUT.MAIN:        HelpLine = SCREEN$BottomHelpS<1, N.B.O>

/u/dsisrc/RMS.BP/INPUT.MAIN:        if HelpLine = '' then HelpLine = SCREEN$BottomDescS<1, N.B.O>

/u/dsisrc/RMS.BP/INPUT.MAIN:        BotLineHelp := @FM:' ':PrS:SCREEN$BottomOptionS<1, N.B.O>:PrX:' : ':HelpLine




And when using the values it’s crystal clear they’re from a global common:


* 20.Feb.1986 jim: First Draft

  *  Add custom options from SCREENS file:


  NUM.BOT.OPTS = dcount(SCREEN$BottomOptionS, @VM)      ;*  Now in Commons

  for N.B.O = 1 to NUM.BOT.OPTS

    Logic = SCREEN$BottomLogicS<1, N.B.O>

    if Logic # '' then

      call INPUT.CMD( Logic )  ;*  Does this need more setup, etc !?

    end else Logic = @TRUE

    if Logic then

      OPTS<-1> = SCREEN$BottomOptionS<1, N.B.O> ; DESCS<-1> = SCREEN$BottomDescS<1, N.B.O>


  next N.B.O



SCREENS screen definition:


A picture containing text

Description automatically generated



How it renders on the bottom line(s) (from the code snippet above):




‘?’ option shows ‘Help’ details:



Description automatically generated

Peter McMurray

Jul 21, 2022, 5:10:18 PMJul 21
to Pick and MultiValue Databases
I am bemused that people think this is new or missing since I have definitely used it on every program issued to clients since 1977. We defined Global dictionaries for every application and used those standard names in every program. As one person mentioned EQU has never incurred any overhead. Dimensioned arrays have always been a more efficient way of using attributes.
We have a master program and all processes are controlled by it giving complete control of all users down to field level. When SOX came along no changes were necessary. Due to absolute INPUT edit control Y2K and day 10000 problems were ruled out in 1987.
Initially we used a switch operated control program that was precisely mapped on the REALITY. I swiched this to a generated BASC program when I hit sandboxed code on the MICROSTAR. This had the advantage of getting rid of the single program that hid the workings from a developer and gave the client full independently maintainable code. It is of course still more sensible to use the generated method.
It has worked in debug on every system from Reality, R83, Unix, System 5, Unidata on a DEC farm etc.. It is 100% UNICODE compatible over all character sets with a minor change to INPUT to allow for multi 8 bit character definitions.
001 SUBROUTINE oil_tcaltexsap
003 * Caltex Transfer of Invoices to SAP
004 * oil
005 * 13:40:35  22 Jun 20172 pgm excalv10
007 A.PRASSIGN = "STANDARD\Caltex Transfer]"
011      EQU COF TO A.FILES(1)
013           MAT COMPANY= ''

Jim Idle

Jul 25, 2022, 2:01:20 AMJul 25
I think everyone knows this technique Peter - the OP was about whether the Universe debugger understands the EQUATE. I think that the conclusion is, that it doesn’t.


Reply all
Reply to author
0 new messages