Using EQU with dimensioned arrays in the debugger

163 views
Skip to first unread message

Joe G

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

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;

DIM INVOICE.REC(20)
EQU INVOICE.DATE TO INVOICE.REC(1)
EQU INVOICE.CUSTOMER TO INVOICE.REC(2)
...

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

:: INVOICE.DATE/
Symbol not found.

You have to reference the array directly

:: INVOICE.REC(1)/
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?

Thanks

Jim Idle

unread,
Jul 18, 2022, 12:21:57 AMJul 18
to mvd...@googlegroups.com
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)
EQU II TO A(5)
II = 66
CRT II

Then:

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.

Jim

--
You received this message because you are subscribed to
the "Pick and MultiValue Databases" group.
To post, email to: mvd...@googlegroups.com
To unsubscribe, email to: mvdbms+un...@googlegroups.com
For more options, visit http://groups.google.com/group/mvdbms
---
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 mvdbms+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/mvdbms/fe6f8511-9756-478c-b712-a3aae1d28065n%40googlegroups.com.

George Gallen

unread,
Jul 18, 2022, 11:04:15 AMJul 18
to mvd...@googlegroups.com
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)

George

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

Joe G

unread,
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

unread,
Jul 18, 2022, 12:12:53 PMJul 18
to mvd...@googlegroups.com
Joe,

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

Instead of:

EQU INVOICE.DATE TO INVOICE.REC(1)

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

EQU INVOICE.DATE.AMC TO 1

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

CRT INVOICE.REC(INVOICE.DATE.AMC)
CRT INVOICE.ITEM<INVOICE.DATE.AMC>

PROS:

* 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

CONS:

* does not standardize the variable name

* expression is longer (more characters to type)

See the PickWiki page https://www.pickwiki.com/index.php/CodingStandards 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.

rex

Joe G

unread,
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:

DIM INVOICE.REC(20)
EQU INVOICE.DATE TO INVOICE.REC(1)
EQU INVOICE.CUSTOMER TO INVOICE.REC(2)

EQU INVOICE.DATE$ TO 1
EQU INVOICE.CUSTOMER$ TO 2

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

unread,
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

unread,
Jul 21, 2022, 2:35:26 AMJul 21
to mvd...@googlegroups.com

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

unread,
Jul 21, 2022, 2:39:44 AMJul 21
to mvd...@googlegroups.com
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

unread,
Jul 21, 2022, 3:45:22 AMJul 21
to mvd...@googlegroups.com

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: mvd...@googlegroups.com <mvd...@googlegroups.com> On Behalf Of Jim Idle
Sent: 21 July 2022 07:40
To: mvd...@googlegroups.com
Subject: Re: [mvdbms] Using EQU with dimensioned arrays in the debugger

 

EXTERNAL EMAIL




================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 855.577.4323
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/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

unread,
Jul 21, 2022, 3:39:47 PMJul 21
to mvd...@googlegroups.com
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:  https://www.pickwiki.com/index.php/CodingStandards

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

* COPYRIGHT (C) BANK OF HORTON - STUDENT LOAN SERVICES
*               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

unread,
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

unread,
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

unread,
Jul 21, 2022, 4:29:32 PMJul 21
to mvd...@googlegroups.com

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

James A

unread,
Jul 21, 2022, 4:44:08 PMJul 21
to mvd...@googlegroups.com

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)

 

 

INPUT.COMMON: 

 

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

 

EQU.SCREEN:

 

  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:

 

 

>FIND.BP SCREEN\$Bottom

/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>

    end

  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:

 

Text

Description automatically generated

Peter McMurray

unread,
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
002
003 * Caltex Transfer of Invoices to SAP
004 * oil
005 * 13:40:35  22 Jun 20172 pgm excalv10
006 INCLUDE A.BP A_EQU
007 A.PRASSIGN = "STANDARD\Caltex Transfer]"
008 INCLUDE A.BP A_PRINTCON
009 DIM A.FILNAM(10);MAT A.FILNAM = ''
010 A.FILNAM(1) = 'COMPANIES'
011      EQU COF TO A.FILES(1)
012 DIM COMPANY(52)
013           MAT COMPANY= ''
014 EQU SHCONAME TO COMPANY(1)
015 EQU CONAME TO COMPANY(2)
016 EQU COADD1 TO COMPANY(3)

Jim Idle

unread,
Jul 25, 2022, 2:01:20 AMJul 25
to mvd...@googlegroups.com
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.

Jim

Reply all
Reply to author
Forward
0 new messages