Forward type declarations

Programming language questions
Post Reply
User avatar
adimetrius
Posts: 68
Joined: Sun Aug 04, 2019 1:02 pm

Forward type declarations

Post by adimetrius »

Colleagues,

The CP Language Report has it in section 4, Declaration and scope rules:
CP LR wrote:The scope of an object x extends textually from the point of its declaration to the end of the block (module, procedure, or record) to which the declaration belongs and hence to which the object is local.
Essentially, this means every identifier has to be declared before it can be referenced. The only exception to this rule is forward type declarations, which are provided for in:
CP LR wrote:3. A declaration of a type T containing references to another type T1 may occur at a point where T1 is still unknown. The declaration of T1 must follow in the same block to which T is local;
I noticed, however, that this definition of forward type declarations is way broader than that of the Oberon-2 language. Have it for comparison:
O2 LR wrote:3. A type T of the form POINTER TO T1 (see 6.4) can be declared at a point where T1 is still unknown. The declaration of T1 must follow in the same block to which T is local;
Now, Oberon's way is necessary to enable mutually referencing or recursive data structures, which is essential. It is also sufficient for that end. I just can't see what advantages are secured with the CP'sdefinition. I can't think up a case where the CP's definition of p.3 would be necessary and essential, or even significantly more convenient that Oberon-2's definition.

The following seems impossible in Oberon-2; however, it also seems of low practical importance.

TYPE R = RECORD p: PROCEDURE (a: S) END;
S = ARRAY N OF R;

So, Does anybody know why this definition was broadened? Any ideas or historical reasons?

The CP definition requires a significant (well, somewhat:) complication of the compiler's front-end (DevCPP). I am reworking the front-end for my own purposes, and I'm wondering if reverting to the Oberon way would imply any significant loss.
cfbsoftware
Posts: 55
Joined: Wed Sep 18, 2013 10:06 pm
Contact:

Re: Forward type declarations

Post by cfbsoftware »

I don't exactly know why this is so, but the document called What's New in Component Pascal (CP-New.odc) included with BlackBox summarises the language enhancements compared to Oberon-2. The general aim of these language enhancements is described as follows:
The language revision was driven by the experience with the BlackBox Component Framework, and the desire to further improve support for the specification, documentation, development, maintenance, and refactoring of component frameworks. The goal was to give a framework architect the means to better control the overall integrity of large component-based software systems.
The Miscellaneous section includes the following paragraphs related to Type declarations:
Record types can be declared as extensions of other record types by mentioning a pointer type as base type (instead of a record type). This makes the explicit naming of a record type superfluous, if the record variables are used via pointers only.

Within a scope, type names can be considered as forward-declared. This means that any type name can be used before it is declared. Old-style pointer forward declarations like T = POINTER TO TDesc are still allowed, since they are simply a special case of the new rule, but they are not necessary anymore.
User avatar
adimetrius
Posts: 68
Joined: Sun Aug 04, 2019 1:02 pm

Re: Forward type declarations

Post by adimetrius »

Thank you for the reference, I didn't know this explanation was there. Maybe, indeed, this was driven by the desire to do away with "Old-style pointer forward declarations like T = POINTER TO TDesc ".

One application of this rule that seems especially useless is forward-declarations of base types. Definitely, the following is of no practical or theoretical use, while allowing program text to become obfuscating:
TYPE Ext = RECORD (Base) END;
Base = EXTENSIBLE RECORD END;

If the desire is to get rid of T = POINTER TO TDesc; Desc = RECORD ... END;, then maybe it could be served with a more explicit and a more narrow rule:

3. A declaration of a type T containing references to another type T1 of the form POINTER TO RECORD may occur at a point where T1 is still unknown. The declaration of T1 must follow in the same block to which T is local;

or even

3. A declaration of a type T containing references to another fields of type T1 of the form POINTER TO RECORD may occur at a point where T1 is still unknown. The declaration of T1 must follow in the same block to which T is local;

This would, I think, make the laguage rules more regular, and the complier front-end (somewhat) simpler. It is not as simple as it could be ;-) And it is not just the compiler, but also textual tools that work with program text.

P.S. "Obfuscating? What do YOU know about obfuscating?" said a C programmer. :D
Post Reply