Skip to content

Reserved Words

Mark Sarson edited this page Sep 27, 2026 · 2 revisions

Reserved Words: When a Keyword Can Be a Label

The Language Reference's Reserved Words page lists two groups of keywords: one that "may not be used as labels for any purpose", and one that may label data but "may not be the label of any PROCEDURE statement". The compiler does not agree with either list in full.

Everything on this page was settled by compiling it, on Clarion 10 (10.0.12567) and Clarion 12 (12.0.14204), with identical results. The test project, which builds every word of both lists in every place a label can go (990 builds per version), is in the repository: test-programs/ReservedWordsTest. The extension's reserved-keyword diagnostic follows these results.


The short version

  • 44 keywords can never be a label, anywhere: not a variable, not a GROUP field, not a CLASS method, not a PROCEDURE or ROUTINE.
  • A keyword can name a parameter, but a reserved one only the last: (LONG X, LONG If) builds, (LONG If, LONG X) does not.
  • A keyword can start a statement in column 1 (OF 1, END), because it cannot be a label there.
  • A keyword can be the prefix of a colon label (Return:NotSet).
  • Everything else in the help's lists is not reserved at all: WINDOW, CLASS, QUEUE, SELF, PARENT and the rest can label anything, a PROCEDURE included; so can CODE, DATA, NULL and THROW.
  • But SELF, PARENT and NULL are system intrinsics: reusing them as a method's parameter or local (SELF, PARENT) or a procedure's name (NULL) draws a warning, and a SELF or PARENT so declared hides the real one — see below.

The 44 keywords that can never be a label

ACCEPT AND ASSERT BEGIN BREAK BY
CASE CATCH CHOOSE COMPILE CONST CYCLE
DO ELSE ELSIF END EXECUTE EXIT
FINALLY FUNCTION GOTO IF INCLUDE LOOP
MEMBER NEW NOT OF OMIT OR
OROF PRAGMA PROCEDURE PROGRAM RETURN ROUTINE
SECTION THEN TIMES TO TRY UNTIL
WHILE XOR

Each of these fails as a label in every place tested — global data, procedure-local data, a GROUP field, a CLASS property, a CLASS method, a global PROCEDURE, a ROUTINE, an executable statement's label, and a method's local data:

Loop       LONG                ! ❌ global or local variable
MyGroup    GROUP
If           LONG              ! ❌ a GROUP field too
           END
MyClass    CLASS
Return       PROCEDURE         ! ❌ a CLASS method too
           END

Note CATCH, FINALLY and TRY: they are reserved in Win32 Clarion, not only in Clarion.NET.


Where a keyword is allowed

As the name of the last parameter

Each of the 44 builds as a parameter's name when it is the only parameter or the last one, in a procedure's prototype and implementation (and, tested alone, in a method's). Followed by another parameter, it fails:

  MAP
Scale  PROCEDURE(LONG If)              ! ✅ alone
Shift  PROCEDURE(LONG X, STRING Loop)  ! ✅ last
Rotate PROCEDURE(LONG If, LONG X)      ! ❌ Expected: <ID> )
  END

The words that are not reserved (below) build as a parameter's name in any position. Legal or not, a keyword as a parameter name is best avoided.

At the start of a statement in column 1

The Language Reference says a statement without a label must not start in column one. For a statement that starts with a reserved word, the compiler accepts it anyway — the word cannot be a label, so it can only be the statement:

  CODE
  CASE X
OF 1                 ! ✅ builds
    X = 2
  END
IF X = 1             ! ✅ builds
    X = 3
END                  ! ✅ builds

OF, IF, END, LOOP, ELSE, RETURN and CODE were all tested this way. A statement that starts with an ordinary name still fails in column 1, because that name is read as a label:

X = 1                ! ❌ in column 1: X is taken for a label
  X = 1              ! ✅

So a reserved word in column 1 is only an error when it is used as a label — when a declaration follows it (If LONG, Loop PROCEDURE, End EQUATE(1)).

As the prefix of a colon-qualified label

A keyword before the colon is a prefix, not a label on its own:

Return:NotSet   EQUATE(0)      ! ✅ builds
If:Flag         LONG           ! ✅ builds
  CODE
  If:Flag = Return:NotSet      ! ✅ and can be used

Keywords that are not reserved at all

CODE, DATA, NULL and THROW

The help's first list includes them, but all four build as a label everywhere — a variable, a field, a method, a PROCEDURE:

Code       LONG                ! ✅
Data       STRING(20)          ! ✅
Null       BYTE                ! ✅
Throw      PROCEDURE           ! ✅ (ABC's own classes have a Throw method)

NULL as the name of a PROCEDURE or method builds with a warning — see SELF, PARENT and NULL are intrinsics.

The "not a PROCEDURE" list

The help's second list — APPLICATION, CLASS, DETAIL, FILE, FOOTER, FORM, GROUP, HEADER, ITEM, ITEMIZE, JOIN, MAP, MENU, MENUBAR, MODULE, OLE, OPTION, QUEUE, PARENT, RECORD, REPORT, SELF, SHEET, TAB, TOOLBAR, VIEW, WINDOW — says these may label data but not a PROCEDURE. Neither compiler enforces that: all 27 build in every place tested, a global PROCEDURE's label included.

  MAP
Window PROCEDURE               ! ✅ builds
  END

Window PROCEDURE
  CODE

The test declares such a PROCEDURE and does not call it. Calling a procedure named Window or Class may be awkward; declaring it is legal.

SELF, PARENT and NULL are intrinsics

SELF, PARENT and NULL are what the compiler calls system intrinsics. Reusing one compiles, but with a warning; for SELF and PARENT the new name then hides the intrinsic (a procedure named Null did not stop Ref &= NULL compiling — checked at compile time only):

Where Warning
SELF or PARENT as a method's parameter or local variable Redefining system intrinsic: SELF / PARENT
NULL as the name of a PROCEDURE or method Redefining system intrinsic: NULL

Everywhere else — global or local data, a GROUP field, a global PROCEDURE named Self or Parent — they build with no warning.

The hiding is real. Inside a method that declares a Self local, SELF means that local, not the object:

Shape.Fill PROCEDURE
Self     LONG                  ! ⚠️ Redefining system intrinsic: SELF
  CODE
  SELF.Draw(1)                 ! ❌ Field not found: DRAW / Unknown procedure label

Other methods of the class keep the real SELF. So the help's advice that SELF and PARENT should not name a method's locals or parameters is right in effect — "cannot" is just not what happens.


What the extension reports

The reserved keyword labels diagnostic (clarion.diagnostics.reservedKeywordLabels) reports one of the 44 words used as a label — followed by a declaration — wherever it stands, inside a GROUP or CLASS as much as outside. It does not report parameter names, statements that start with a reserved word in column 1, colon-prefixed labels, or any of the words that are not reserved.