Reading the post How to loop over a queue and delete SOME entries reminded me that Clarion lacks an instruction to loop over all the values of a queue without using an index. Most languages do, even Clarion# (
FOREACH) and the Template language (
Using indexes forces you to declare index variables or, if you are lazy, to use implicit variables. I used to declare a few variables (
J LONG, etc.) in all procedures where I used queues, but this got me when by mistake I reused a variable in another routine. Using implicit variables is worst.
Now, for safety, I declare an index variable for each queue:
myQ QUEUE ... END ImyQ LONG ... LOOP ImyQ = 1 TO RECORDS(myQ) GET(myQ,ImyQ) !Some code .
But I decided to look for a “better” way, and it turns out it is possible to loop over a queue without an index in Clarion:
GET(myQ,0) LOOP GET(myQ,POINTER(myQ)+1) IF ERRORCODE() THEN BREAK. .
And adding a few trivial global procedures like these:
SET PROCEDURE(QUEUE q) CODE GET(q,0) NEXT PROCEDURE(QUEUE q)!,LONG CODE GET(q,POINTER(q)+1) RETURN ERRORCODE() PREVIOUS PROCEDURE(QUEUE q)!,LONG ptr LONG CODE ptr = POINTER(q) IF ptr GET(q,ptr-1) ELSE GET(q,RECORDS(q)) . RETURN ERRORCODE()
It is possible to write:
SET(myQ) LOOP NEXT(myQ) IF ERRORCODE() THEN BREAK. !Some code .
SET(myQ) LOOP UNTIL NEXT(myQ) !Some code . SET(myQ) LOOP UNTIL PREVIOUS(myQ) DELETE(myQ) .
Of course, there is a performance impact. I wrote a small benchmark and got these results:
LOOP I: 2.33 LOOP GET/ERRORCODE: 2.61 12.02% LOOP SET/NEXT: 2.65 13.73% LOOP DELETE I: 2.93 LOOP DELETE SET/PREVIOUS: 3.6 22.87%
Meaning that there is an increase of about 13% when using
SET/NEXT and about 22% when using
SET/PREVIOUS. But depending on what you are doing inside the loop (printing, saving to disk, etc.), the difference may be negligible.
Here’s a project with all the code: SET/NEXT/PREVIOUS for queues (github.com)