Info("labels") output is bad (nope, actually it's fine)

Upon compilation in b24, a modified procedure produced a “Label does not exist” error. The labels in the procedure have worked for years and the label was definitely present and looked ok. So I used info("labels") to see if the allegedly missing label was listed. This unexpectedly produced a list of each IF, ENDIF, LOOP and ENDLOOP statement used in the procedure, as well as its labels (except for the allegedly non-existent one). Here’s a partial sample of the output:

:IF:19
:IF:2
:ENDIF:16
:IF:6
:ENDIF:17
:ENDIF:24
ReEnterNum
:ENDIF:25
:ENDIF:19
:ENDLOOP:1
:LOOP:1
:LOOP:2
:ENDLOOP:2
:IF:3

It is a list with a sequential number for each example of these statements in the procedure. I tested info("labels") on other procedures in the database, then on different database files on my new MacBook Pro, then on different databases on older MacBook Pro, all with similar results.

This is definitely not documented output of the info("labels") function.

I will keep looking for the cause of the compile error.

Using this very simple test procedure:

if now()>now()+1
    nop
endif
message info("labels")
stop

This:
    rtn
That:
    rtn
TheOther:
    rtn

I get this message returned when run:

This
:ENDIF:1
TheOther
:IF:1
That

Now if I change the if/endif statements to case/endcase I get this:

That
This
TheOther
:ENDCASE:1
:CASE:1

This was the same on both of my two older machines (High Sierra 10.13.6 & Catalina 10.15.7). It makes no difference if the info(“labels”) message is before or after if/case block.

The matching statement pairs have somehow been picked up by info(“labels”), maybe because of the use of colons?

Possibly, but the colons are necessary to indicate to Panorama that the name is that of the sub-routine label. Without the colon after the label name the procedure would not compile.

Panorama automatically generates unique labels for each if, case and loop. Each automatically generated label is unique, and begins with : so that it can’t conflict with your labels (you cannot create a label that begins with a :). Even though these labels are automatically generated, they are valid labels so they are listed by the info(“labels”) function. If you want to get rid of them you can use arrayfilter( to remove all labels beginning with a colon.

This sequence of steps is confusing me. The info("labels") returns the labels in the current procedure. But if there is a compilation error, you cannot run the current procedure, so you could not run the info("labels") function.

Perhaps you did not get a compilation error. Another source of confusion is that there is no Panorama “Label does not exist” error. But the callwithin statement does have an error “procedure PROCEDURENAME does not contain a label named LABEL”. Perhaps that’s what you mean.

If Panorama doesn’t see the label, you probably accidentally enclosed it in a comment or string literal. For example, this code appears to have a label, but it actually doesn’t. Since the /* and */ characters could be far away from the label in question, it might not be immediately obvious what is going on.

/*
myLabel:
*/

Here is another procedure where the label looks ok but is actually invisible to Panorama. This procedure will compile, but everything after /* is ignored.

/*
myLabel:

Here is an example of a string literal:

"
myLabel:
"

Again, myLabel won’t work. (Note that in both cases, info(“labels”) will correctly fail to list the label. In both of these example, the so called label is invisible to Panorama.)

I commented out the goto statement with the offending label name before running the procedure again with the new starting line displaydata info("labels") stop.

Another source of confusion is that there is no Panorama “Label does not exist”

The compile error was shown in the panel at the bottom of the procedure window as Label "xyz" does not exist

In fact I did find the cause of the missing label message soon after posting, which turned out to be an incomplete arrayselectedbuild( formula
. When that was fixed, the procedure compiled without the label error.

Even though these labels are automatically generated, they are valid labels so they are listed by the info(“labels”) function. If you want to get rid of them you can use arrayfilter( to remove all labels beginning with a colon.

This is not mentioned in the documentation. Getting a dirty great list of numbered IFs, LOOPs etc (about 80 in this case) is not anticipated when one expects a nice little list of a couple of label names.

Panorama automatically generates unique labels for each if, case and loop. Each automatically generated label is unique, and begins with : so that it can’t conflict with your labels (you cannot create a label that begins with a : ).

This is fascinating.

As you suggest, the for statement, eg, generates a LOOP label, just as an until statement generates an ENDLOOP label even though neither explicitly contains “loop”. When these automatic labels are present in procedures they are invisible to users, and I gather provide the ability to check that each opening statement has its matching closing statement and vice versa — possibly using info(“labels”), arrayfilter( and arraysearch( etc.

Invisible to users, that is, except via info(“labels”), when the wizard lets us peek behind the curtain.

No, these labels are actually used to make this statement works. For example,

loop
    ....
endloop

Is actually internally converted into something like this:

:LOOP:1:
    ...
    goto :LOOP:1
:LOOP:2:

The documentation can never mention everything. If it did, we wouldn’t need this forum! However, I have added a postscript on this documentation page mentioning this.

Unfortunately, this function was never going to be suited for the diagnostic purpose you were trying to use it for. At best, it could only tell you what Panorama had already told you via the error message, that the label didn’t exist (or was invisible to Panorama). The info(“label”) function gets the list of labels from the same source that the error message got it from.

In fact, this really isn’t a very useful function. But my tendency is for Panorama to make available information it knows about, in case someone (usually me) comes up with a use for it. But so far I can’t actually think of any real practical use for this function.