Home

(An updated version of the article, published in: ACM SIGPLAN Notices , Vol. 36, Num. 6, June 2001, pp 38-49)

From Pascal to Delphi to Object Pascal-2000

Abstract

The evolution of Pascal to Delphi, the powerful and elegant features of that language and RAD environment are discussed. Yet the evolution was not smooth, some inconsistencies and glitches built up. So the next version of the language named Object Pascal 2000 is suggested. It eliminates the inconsistencies, improves the language and sets the fundamentals for standardizing it. 

Introduction

Wirth's Pascal [PA], born more than two decades ago, passed through a complex evolution and is still on the scene. It was due to Borland [TP, TP55], that Pascal [PA] (renamed Turbo Pascal) had acquired many essentially new features, became popular and widely used in PC world of 80s. Starting from mainframes of the 70s, to 8 bit/64K micro computers, to the modern 32 bit Giga-Hertz/Giga-byte models, Pascal survived the unprecedented progress in hardware and software, evolving into Delphi-6 [D6], a powerful language and an unparalleled Rapid Application Development (RAD) environment. Inevitably, the language that worked fine at hardware as small as 8 bit/64K, should pass really a long and windy way to evolve in a modern RAD like Delphi-6.

On a rather bizarre scene of the modern programming languages, Delphi/Pascal is intended to be a model of a scientifically designed programming language among the others (widely used but designed less scientifically). Exactly that feature and the implied better methodology of programming in Pascal/Delphi is why this language attracts people, and why some of C++, Java or Visual Basic folks are supposed finally to switch to Delphi. While for adepts of C++ one of the most important issues is compliance to the ANSI Standard "as is", the Pascal/Delphi programmers expect the highest level of reliability and language purity per se (although there is no standard yet for the language itself).

Unfortunately, the latest development of Delphi disagrees with that high goal. The far from perfect syntax, semantics and implementation of Delphi undermine the very goal of its existence. Delphi does acquire new powerful features, but it becomes more hectic and inconsistent, evolving not in accordance with a well designed strategic plan, but rather in chaotic attempts to meet some minute goals of the changing environment (see the section 8 "Clean syntax" below). I have discussed these issues with other professionals, and learned that they share the similar opinion (enough to mention Prof. Niklaus Wirth).

Delphi requires improvements, which should follow the best principles established by Wirth's Pascal, ADA, and as far back as ALGOL-60. Thus, I took a risk of suggesting a draft for Object Pascal of the next generation, which does away with inconsistencies of the present Delphi and essentially extends its features. To clean the way for this new version, the backward compatibility issues should end sooner or later. Exactly now, when transfer to Linux and emerging 64-bit processors is on its way, it is the right moment to do that.

Delphi, being a descendant of Pascal and ALGOL-60 - the languages once widely used and respected in the scientific community, is now hardly known there. The scientists and engineers nowadays mostly adhere to different brands of C++ (and not even to C++ Builder - one in the Borland line of RAD products). To restore (to create) the respect for the new Object Pascal in the scientific community, it is necessary not only to demonstrate the advantages of the language itself, but also to develop a very efficient compiler and powerful Numeric Component Library (NCL in addition to the existing Visual Component Library VCL) in accordance with the best traditions of RAD. Essentially, such a NCL (together with the efficient native compiler) could successfully compete with the scientific packages like MatLab or Mathematica.

With that in mind, suggested here are

The Notes on Object Pascal 2000 (P2000)

Preface

The notes started as a wish-list of extensions, corrections and methodological improvements to the existing version of the language, defined in Turbo Pascal and Delphi-6 Language Guides [TP, TP55, D6]. The goal was to increase the power of Delphi-6 even more, to clean its syntax and semantics, eliminating the existing glitches and inconsistencies. These revisions seem fundamental enough to speak about a next version of the language - Object Pascal 2000. After further discussions and more improvements it would be reasonable to standardize it.

1. Standard Kernel and possible Extensions

Ideally, a high level programming language must be platform-independent (machine- and OS-independent). But given the complexity of the present day user interface and operating environments, a fully platform-independent language would be of a little help for developers. To meet their practical goals, the RAD approach and the platform-specific VCL were successfully implemented in the line of Borland/Inprise products (Delphi, C++ and Java Builders). Now in P2000 it is necessary to clearly define and distinguish the standardized and platform independent kernel of the language from the optional platform-dependent extensions. For example, the specific numeric types, zero-terminated strings, the Variant types and Interfaces of the present Delphi may be considered as the optional extensions in P2000. The VCL (and possibly other libraries like NCL - Numeric Component Library) are examples of extensions also.

2. Embedded blocks

The notion of embedded blocks appeared as early as in ALGOL-60, which introduced compound statements

begin

{Simple statements}

end

and blocks, i.e. compound statements with declarations of variables at the beginning:

begin

{Declarations}

{Simple statements}

end

Both the blocks and compound statements were allowed to be unlimitedly embedded at any place, and this way they defined the rule of scope. In Wirth's Pascal and later on in Turbo Pascal/Delphi, the blocks are allowed only in the role of declarations for procedures and functions. Thus, if we really needed a next temporary level of declarations at a certain point of the code, we should declare a procedure or function at the proper place somewhere above - in the section of declarations of the current block. P2000 should allow the more general embedded block structure (also implemented in other modern languages like C++, ADA).

3. Variables and Memory: the role and implementation of pointers

The types in a programming language may fall into the two essentially different categories: the direct (value) types vs. indirect (reference or pointer) types [GO]. The direct types always provide

- isomorphism between a variable and its memory instance according to the rule of scope. Thus, there is no need even to distinguish a variable and its instance in the memory;

- the memory for variables of these types are allocated (de-allocated) on the stack automatically: allocated in the place of variables declarations, de-allocated when leaving the scope;

- this way is the most straightforward and fastest method of memory management for an application (no garbage collection is necessary, no memory leak may occur, the sizes of the types are usually known and used at compile time to generate the most efficient code);

- therefore, it should be considered as a preferred data type.

The indirect types - pointer or hidden pointer types, on the contrary, are somehow in conflict with such fundamental principles of high level languages as (1) The rule of scope, and (2) One-to-one correspondence between a variable and its instance (its memory image).

For indirect variables the usual variable-instance isomorphism is broken so that the variables and their instances are separated and live independent lives.  Not only do we need to declare and initialize them like other variables, but we also have to take two additional actions: to create and later destroy the instances. Thus, although a pointer var p : ^T is visible and exists only in its scope, its instance p^ (some structure of type T) does not necessarily exist within this scope and does not necessarily disappear outside it (memory leak). Moreover, it may happen that several pointers

var p1, p2, p3 : ^T

point to the same instance of type T, or conversely, there may be instances of T, to which no pointer points at all (also memory leak), or a non-nil pointer may point to a no more valid instance (dangling pointer). In particular, f or hidden pointers and classes, assignments a:=b and conditions a=b do not have the usual meaning.

Nonetheless, the pointer type cannot be eliminated from a high level language. T he pointers are inevitable when a problem requires that one variable be associated with more than one instance of the same type (in different moments), or many variables be associated with one instance. For example, that happens while processing linked lists. Similarly, one variable of class type may be associated with more than one instances of different class types in a hierarchy of classes (polymorphism). Thus, although not eliminating pointers, a high level language should: (1) limit their usage to the cases where it is really necessary (linked lists, polymorphism); (2) provide certain safety measures when using them.

None of the two is followed in Delphi. On the contrary: it even promotes some exaggeratory usage of an indirect type class .

Objects in Turbo Pascal first were implemented as type object [TP55], which could be used either as a direct type, or as a pointer type, when necessary. Delphi introduced another implementation of objects called class - an indirect-only type which is essentially a hidden pointer to objectDelphi downplays "old" objects. It does not eliminate them completely, but leaves them "under-developed" not adding those new features that the classes have. Thus:

- the types object and class in P2000 should completely agree in syntax , semantics and functionality (the meaning and usage of override, property, default and index properties and so on).

Another unnecessary exposure of pointers takes place in the implementation of the Long strings and Dynamic arrays in Delphi. They are considered as hidden pointers, while in reality for the long strings and dynamic arrays the usual variable-instance isomorphism does take place because Delphi implements the automatic constructing/destructing. There remain some particularities nevertheless. One of them is that for those two types an assignment statement a:=b does not take the effect immediately in the standard meaning, following the "copy-on-write" semantics instead [D6]. Thus,

(1) the instances of the Long Strings and Dynamic arrays should be created immediately in places where a non-nil reference is assigned to them, or where their length is specified;

(2) the "pointer" nature of the long strings in P2000 may be hidden from the developer completely as an internal detail of implementation (but not completely for the dynamic arrays - see below). The long string type functionally should behave exactly as the other direct types, i.e. assignments a:=b and conditions a=b should have the usual meaning also for them. (Still, developers must be aware of the indirect nature of these two data types when they are used for internal fields in other structured types, for example in records).

(3) unlike the present "copy-on-write" implementation in Delphi-6, creation of a copy of a long string or of a dynamic array should occur not as late as in the moment when an element changes ( Str[i] :=... or a[i]:=...), but somewhere earlier (according to point (1) above) - just like the behavior expected for simple strings and static arrays.

As to the safety issue, for the Long strings and Dynamic arrays it is fully guaranteed due to automatic constructing/destructing and the Reference Count Techniques. Thus, they may be treated as the usual direct types (but avoiding operations causing multiple constructing/destructing in loops because it would require intervening of the system garbage collector in unpredictable moments).

As to the safety level for the really indirect types (pointer and class types), it is a question of a trade off between the cost and complexity of the protective features of the compiled code vs. its efficiency.

The complete safety or consistency would mean that:

(1) The compiled code automatically treats and never allows dangling pointers. If any variables u is to be freed, not only it becomes nil, but also all other variables and fields of records in the scope, as well as all instances in the heap which refer the same instance u^ become nil automatically.

(2) The code immediately reports every freed instance to the system garbage collector.

It seems impossible to implement that highest level of safety features without compromising dramatically the speed and efficiency. (But it would be highly desirable as a debugging option - at discretion of the compiler developers).

4. Dynamic Arrays: unifying and improving

The concept of array is probably the most important in any programming language. The Dynamic Arrays introduced in Delphi-4 are a great leap ahead, in particular for implementation of vectors, matrixes and other numeric algorithms. But now there exists in Delphi as many as four different types of the notion 'array' with certain syntax and semantics controversies and inconveniences related to it [GA]. Thus, we have to clean up and normalize the notion of array for P2000.

The Dynamic Array of Delphi-6 seems almost an ideal type for vector and matrix procedures. It is fast, and it allows declaring types like

TVector = array of extended;

TMatrix = array of array of extended;

TTensor = array of array of array of extended;

and then to pass parameters of these types to procedures, to easily retrieve the actual dimensions of the passed arrays (using High function) and to create the resulting array of the required dimensions. The first of the serious drawbacks of that implementation is the mandatory zero-base indexing (which together with a requirement of numeric-only range type for Dynamic Arrays were a compromise set by the team of developers for the sake of efficiency). Another drawback is an unnecessary syntax difference with the standard Pascal static array. In P2000 we must do away with that and to improve the implementation.

It is easy to admit the numeric-only range types for Dynamic Arrays, but not the mandatory zero-based indexing. The Low-bound feature of the standard Pascal arrays is so important (particularly in mathematics) that it should be conserved absolutely for Dynamic Arrays also. After all, storing the lower bound adds just one more 4-byte field to one dimension of the Dynamic Array structure:

Offset         Content

-12             32-bit lower bound {suggested additional field}
-8               32-bit reference count
-4               32-bit length
0                array elements

(True, for multi-index arrays this four additional bytes multiply by the product of the remaining dimensions, wasting some memory, but not affecting the speed).

The existing implementation of Dynamic Arrays in Delphi-6 enables non-rectangular arrays, and it is assumed as though programmers always need exactly such arrays, while in reality the usual rectangular arrays are needed even more often. The trick of the implementation of the non-rectangularity is in that varying sizes are "spread" and multiplied into each individual dimension. But if an array is actually a rectangular one, this approach wastefully stores the same dimension repeatedly. It is more economical to store its vector of dimensions just once in the structure like this:

               Low1 {suggested additional fields}
               High1 
{. . .}
               Low2 
{. . .}
               High2 
{. . .}
               Low3 
{. . .}
               High3 
{. . .}
. . . . . . . . . . . . . . . . . .
-12           Number of dimensions 
{suggested additional field}
-8             32-bit reference count
-4             32-bit full length
0             array elements

Thus, the semantics and implementation should distinguish a case when a range of just one dimension is specified (while the others are postponed to implement non-rectangularity) vs. the case when several or all of the dimensions are specified simultaneously (rectangularity). Incidentally, the system procedure SetLength should receive the actual parameters as sets in form [m..n] rather than separately m, n, for example SetLength(MyArray, [m1..n1], [m2..n2]) .

For the sake of consistency, in addition to the special syntax of Dynamic Arrays, also the traditional declaration format should be allowed - in this case with non-constant value boundaries, for example

TMatrix = array[1..M,1..N] of extended;

The compiler knows whether the identifiers M, N are constants or variables, and select the right implementation correspondingly. If at least one of them is a variable, then it is a case of the Dynamic array of rectangular type so that at the beginning of a block the compiler automatically initializes each variable v of this type with the statement

SetLength(v, [1..M], [1..N]).

If two or more dimensions of an array are set rectangular in one SetLength statement or in the declaration above, its vector of ranges should be stored just once not being wastefully spread.

The peculiarity of the Dynamic Arrays in Delphi is in that their "hidden pointer" nature cannot be hidden completely. It shows up with statements like A:=B and conditions A=B. Delphi allows those statements for dynamic array variables with incomplete set of indexes, as well as assignments of variables of structure types whose internal fields may be of any indirect type, for example:

type TMyRec = record
field1 : integer;
field2 : array of TSomething 
{dynamic array just a pointer}
end ;

TWeird = array of TMyRec;

var A, B : TWeird;

If field2 were a static array, every instance of type TMyRec would occupy a contiguous area in the memory, and assignment A:=B would copy that area. In the example above, nevertheless, although TMyRec looks like a direct type, its field2 behaves like a pointer, therefore A:=B does not copy the array itself.

With all that in mind, the standard Static and a new Dynamic arrays are unified. Now what to do in the new P2000 with other two Delphi array types (Open Arrays and Variant)?

The Variant arrays (and Variant types at all), being very inefficient, are not necessary in P2000 any more (or may be kept as extensions useful for exchange with the operating environment). As to the Open Arrays, the only desirable change here is with regard to the terminology: first, because the concept of Open Arrays actually does not belong to declarable types, and second - to avoid confusion with syntactically very similar, but essentially different Dynamic Arrays. A better choice would be the keyword list instead of array:

procedure Any(. . . ; const OpenList : list of SomeType; . . .);

procedure Any(. . . ; VariousFormalValues : list of const; . . .);

Any(. . . ,[VariousActualValues], . . .);

so that we call it Open List formal parameters and correspondingly the Open List Constructors – as the actual parameters.
 

5. Improved Semantics for Result of Functions of the Indirect Types

In the Wirth's Pascal [PA], the type of result of a function could be only a simple type. Borland gradually removed this limitation in Turbo Pascal and later in Delphi, so that the function's result type was finally allowed to be almost any valid predefined or user defined type. Nevertheless, they did not bother to specify precisely the updated semantics and the consequences the new result types imposed on the function calls, especially in expressions.

The problem appears when the type of result is a hidden pointer, in particular a class type or a Dynamic array type. The code created by the present version of the Delphi-6 compiler for this type of Result is always such, that it returns the Result as though a simple pointer (completely ignoring its "double" meaning). The question arises, who is responsible for creating and destroying the instance of the Result, and what should happen with such Results after processing an expression containing several such function calls. (When only the simple types were allowed as the Results, no such problem existed, because the code stored Results in the stack and disposed them automatically).

If a function is intended to return not just a pointer (to some data or function), but also the instance, the data itself, we have a controversial situation, when essentially a local (pointer) variable Result creates and refers to the instance, which should not be destroyed inside this block (and is often inaccessible to be destroyed outside it)!

For example, if an expression in the right hand part of an assignment statement contains only one such function call of class type, say

X := CertainFunction(A, B),

the pointer variable X still allows to destroy the instance of the Result, but in a case like the following

X := Prod(Sum(A+B), Sum(C+D))

the Results of Sum(A+B) and Sum(C+D) are not accessible at all. If these Results are of class type, we have the dangling pointers. Nevertheless, if the Results are Dynamic arrays , their memory is  released (because the reference count reaches zero), but this behavior is not clearly explained in the Manual [D6]. 

That actually means, that we should avoid functions with the Result of class types in Delphi-6 at all, and therefore we cannot use complex expressions with such functions . Instead, in such cases we have to write procedures like

procedure Sum(const A, B : TSomeClass; out C : TSomeClass );

To implement a complex expression over classes, we have to resort to step-by-step splitting it into the separate "procedural instructions" like that above.

Thus:

- An updated Delphi and Pascal 2000 must implement such a semantic and built such a code for expressions containing function calls with Results of the indirect types, that instances of the intermediate results are destroyed automatically according to the same rules, as if the results were stored in the stack.
 

6. Operator Overload (Operator Declaration)

    Turbo Pascal [TP] essentially extended features of functions, allowing the functions to have result of almost any type. Then, the overloading of procedures and functions introduced in Delphi-5 presented a new important step, but even that is not enough yet. Although programmers can declare unlimited number of new data types in Pascal/Delphi, there is not enough "syntax sugar" to allow declaring the operator signs (+, -, *, /, =, in, >, < and other special signs) for those newly declared types. This feature is traditionally called the Operator Overloading, which is a little misleading. The Operator Declaration (Re-declaration) seems to be more relevant.

  
Delphi still lags behind C++, ADA and several other dialects of Pascal [ FPA, GNU, TMT ] in that regard. (True, Delphi-6 does introduce a sort of the Operator Overloading for the Variant types, an "exotic" - and inefficient - "run time only" data types. Further on we are discussing this not yet implemented feature for the "regular" types, i.e. the types known at design and compile time.

   Similarly to the syntax of ADA, it should be possible to declare the following operands for, say, matrixes:

type TMatrix = array of array of extended;
function '*'(const A, B : TMatrix) : TMatrix; overload ;
{matrix product A*B}
function '*'(const A : TMatrix; const k : extended) : TMatrix; overload
{A*k}
function '*'(const k : extended; const A : TMatrix) : TMatrix; overload
{k*A}
function '
`'(const A: TMatrix) : TMatrix; postfix {transpose A ` }
function '!'(const n: byte) : cardinal; postfix 
{n!}
function '-'(const A: TMatrix) : TMatrix; prefix; overload ;
{-A}
function '-'(const A, B : TMatrix) : TMatrix; overload ;
{ A - B}
function '+'(const A, B : TMatrix) : TMatrix; 
{ A+B}
function '='(const A, B : TMatrix) : Boolean; 
{condition A=B }

and also

function 'in'(const a: TMyElement; const S : TMySet) : Boolean;  {condition a in S }

(new keywords postfix and prefix were added). The operator priorities are the same as for the basic types. Other special characters in the role of operators should be allowed also, for example !, ~ , `, ', , , and their priorities should be the highest. Considering the fact, that some of result types may require a lot of memory, the compiler must be smart enough to not create a temporary storage for the result if not necessary. For example, while coding the statement

X := A*B

the storage for A*B should not be created and then copied to X: instead, the memory of X should be used directly. Similarly, in a statement

X := A*B*C

the temporary storage is required for, say, A*B, but is not for the final result. Obviously, the same consideration remains valid for any function, whose result type is memory consuming.

7. Float Point Operations Optimization

The present version of Delphi compiler does not perform any optimization of the code of arithmetical operations over the float point variables [LR] (which it does for integers). It does not take any advantages of using the float point registers and architecture of a specific processor. To improve performance for numeric intensive application and to make P2000 really attractive for a scientific community, the P2000 compiler must perform the processor dependent and very efficient code optimization both for integer and float point data types. (Processor-dependent compiler vs. platform-independent programming language multiplies efforts of creating the compilers, which may be softened by the approach of developing compilers for an abstract processor, like implemented in Wirth&rsquo;s Oberon system [OB]).

In order to achieve the highest speed, several commonly used numerical types - complex numbers, polynomials, vectors and matrixes should be added to the basic types, while the corresponding operations over them like vector and matrix products, finding roots, inverting, Eigenvalues and Eigenvectors should be implemented in the Assembler language for maximal efficiency. Similar to the VCL, a vast library of visual mathematical components and mathematical graphics should be developed. Such a Numeric Component Library (NCL) could make P2000 together with its new RAD environment the most powerful and attractive media for scientific development, competitive with such presently popular tools like MatLab or Mathematica.

8. A "Richer" Text Format

So far source texts in Pascal/Delphi and in other programming languages have been viewed linearly and use a subset of the ASCII character set. Nowadays, when the Rich Text Format or HTML became ubiquitous in text editing, it would be just natural to capitalize on that in a programming language of the next generation. All the more that the source text in Pascal is essentially structural rather than a linear sequence, thus a "richer" text format may be really beneficial for expressing that internal structure. The existing Delphi environment already utilizes elements of the Rich Text: the editor displays the keywords in bold, comments in blue italic, and it can do some other coloring too. Delphi editor provides many powerful features like Code and Class Completion , helping to navigate and design the source text, but the source still remains linear. Here is a way hyper text may work.

First, the editor may implement the super and sub-indexes: the super indexes for an exponent of the Power, the sub-indexes - as an alternative for index expressions in arrays. Also, the special signs of raised and (existing in Courier New and Times New Roman), should be used for the square and cube correspondingly.

Then, instead of the full implementation of any procedure, or a block, or a compound statement, the blocks should be allowed to be represented by its caption in the format of a hyper link - a unique string commenting the purpose of this block or compound. For example:

if specified then Computing averages ;

The double-click on that link should open the window for viewing and editing the content with the caption appearing as the comment:

{Computing averages}

begin

. . . .

end

The code editor should automatically open such hyper links of embedded blocks till the desired depth (displaying the blocks with indentation), or on the contrary, "collapse" them back.

The ultimate (optional) feature of the code editor could be an implementation of the metaphor of by-block (rather than by-character) visual design based on the modified Nassi-Schneiderman Charts (See Supplement 1). 

9. Clean Syntax

This section doesn't discuss any fundamental issues, and addresses only several syntax glitches in Delphi-5, which should be eliminated in the future versions of Delphi and definitely not be brought into P2000. One of them (regarding Factors) is inherited and persists through all previous versions of Turbo Pascal and Delphi.

1. A loose definition of Factor. In the syntax definition of <factor> ([TP], page 56) there is a wrong clause:

<factor> ::= . . . | <sign><factor> | . . .

Although this wrong clause doesn't appear in section "Object Pascal Grammar" [D6] page A-3, (other disagreements with Turbo Pascal syntax [TP] are there also), this wrong implementation of Factor remains intact in both Turbo Pascal and Delphi 1-6. As a result, an expression like this

2 +-++-+-+ 1

is co nsidered syntactically correct (!), it compiles and yields 1 with an odd number of minuses or 3 otherwise (the compiler interprets '-' as multiplying by (-1), and '+'as (+1) correspondingly).

When written next to each other, not only those term operation signs contradict to the basic syntax of the Expression, accepted in Mathematics, Wirth's Pascal and several other languages: it may be also confusing. Suppose you are debugging an expression like

A - B + C

and try to isolate the middle term, misplacing {} this way: A - {B} + C. It compiles with no syntax error message and produces a result A - C !!!

2. No complete synonymity between [m,n] and [m][n]. For some reason there is no synonymity between [m,n] and [m][n] indexing formats for TStrings object. For example, each line inMemo1.Linesis a string by definition, thus its n-th character may be referred Memo1.Lines[m][n], and it works. Unfortunately, the synonymic form Memo1.Lines[m,n]doesn't, producing a syntax error "Too many actual parameters".

More than that: an assignment

Memo1.Lines[m] := 'Some string'

works, while

Memo1.Lines[m][n] := 'S' {some character}

doesn't with the message "Left side cannot be assigned"

3. Incomplete syntax for "inherited" . The syntax of inherited is defined incompletely in Delphi 1-6. According to the given examples and "The Language Guide" [D6], it is defined as a statement, normally used as a procedure call for the inherited methods. But what if a method is a function, say

function MyPredecessor(. . .) : integer;

and therefore it may be used in an expression in a body of a descendent method, say

x := 2 * inherited MyPredecessor(a) ???

Either it should be explicitly noted that, as a statement, inherited method cannot be a function, or a pair of mandatory parentheses must be always required:

x := 2 * (inherited MyPredecessor(a));

4. Undocumented omittable caret . There is an undocumented feature in Delphi allowing to omit caret while de-referencing array elements or record fields, for example p[5] instead of p^[5] or p.first instead of p^.first. Therefore, not only class type, but also pointers of these types too may become "hidden" for a while. This syntax (also accepted in Wirth's Oberon [OB]) should be documented and may be allowed also in P2000.

10. Conclusion

This draft by no means pretends for completeness, aiming such a high and ambitious goal as a next version of the clean, consistent and powerful Object Pascal. But it tries to address several important and fundamental issues of the programming language, that may be helpful both for the future versions of Delphi and for a really new next version of Object Pascal 2000.

Acknowledgments

I am very thankful to Yu. Finkel and S. Pokrovski for discussions (sometimes really hot) on different aspects of the language purity and consistency. They did help me a lot.

References

[D6] Borland. Object Pascal Language Guide. Borland Software Corp. Scotts Valley, 2001.

[FPA] Free Pascal < http://www.freepascal.org/ >

[GA] A. Gofen. A Long and Winding Way of the Dynamic Array.  Delphi Informant, n. 2, v. 6, 2000.

[GO] A. Gofen. Objects vs. Class: Fewer Pointers, Less Double Thinking.  Delphi Informant, n. 7, v. 5, 1999.

[GNU] GNU Pascal < http://www.gnu-pascal.de/gpc/h-index.html>

[OB ] ETH Oberon White Paper. <http://www.ethoberon.ethz.ch/white.html>

[PA]  K. Jensen, N. Wirth. PASCAL. User Manual and Report. Springer-Verlag, New-York, 1978.

[LR]  R. Lischner. Real Programmers Use Pascal. < http://www.oreilly.com/news/kylix_0800.html >

[TP] Turbo Pascal Reference Guide, Version 5.0. Borland International, Inc. Scotts Valley, 1989.

[TP55] Turbo Pascal 5.5. Object-Oriented Programming Guide. Borland International, Inc. Scotts Valley, 1989.

[TMT] TMT Pascal < http://www.tmt.com/ >

 
 

Supplement 1. Modified Nassi-Schneiderman Charts.

The Modified Nassi-Schneiderman Charts [MNC] were suggested once (1988) as a sophisticated code editor assisting the process of step-by-step top-down designing of a source code for different applications and programming languages (nowadays there exist many [NSE]). That code editor implemented a metaphor of visual designing and editing by means of splitting the rectangular area and zooming in deeper and deeper to the level of individual statements in a specific programming language.

The idea of the editor was based on slightly modified charts, originally known as Nassi-Schneiderman Charts [NS]. The NS Charts have several advantages over flow charts. First, unlike the flow chart, they can express structured and only structured algorithms. Second, the hierarchic structure and embedded blocks of a source code correspond ideally to the process of splitting and zooming in, and graphical displays of modern computers make such visual interface possible. Third, while an arbitrary flow chart is an arbitrary non-planar graph, a flow chart of a structured algorithm must be planar. There exists the well known isomorphism between the planar graphs and planar maps so that the MNS represents exactly such a planar map.

Unlike the original [NS], all MNC shapes are rectangles and angle-shape areas: L-shape corresponds to loops with post-condition and  G-shape –to those with pre-condition (Chart 1 ). Sequences of non-branching statements are represented by the vertical sequence of rectangles. The clauses of the case statement and if - then - else statements are represented by horizontal sequence of rectangles (Chart 1). Thus, to detail an algorithm one more step down means to split some rectangle either into a vertical sequence of smaller rectangles, or into a horizontal sequence of rectangles (for branching), or into the L- or  G- shape and one smaller rectangle (for loops). We introduce the additional convention, that the horizontal splitting corresponds to branches of a parallel process, to threads and to bodies of the same level procedure declarations (Chart 1).

The editor must work either in Frame mode or in Text mode. In the Frame mode it deals with the whole shapes, editing and navigating in all directions and zooming in and out. It takes just one key press to create a special purpose shape: F for for -loop, W - for while-loop, R for repeat -loop, C for case statement, I for if - then - else (the corresponding keywords are automatically filled in with the cursor pointing to the place of the first parameter). Inside each shape the editor works as a text editor, allowing to enter text of comments or statements in a programming language.

Obviously enough, the number of shapes multiplies quickly and their size becomes smaller and smaller. Thus, the editor enables different views with controlled level of depth and hiding of the smaller structures. Altogether it allows the structural design, editing and printing out the structural documentation.

References

[MNC] A. Gofen. A Computer System for Designing and Editing Source Code Using Modified Nassi-Schneiderman Charts. In: Proceeding of the Conference in Simferopol, USSR, 1988, pp.183-185(in Russian).

[NSE] Nassi-Schneiderman on the Web < http://www.rdrop.com/~cary/html/psd.html>

[NS] E. Weiss. Visualizing a Procedure with Nassi-Schneiderman Charts. Journal of Technical Writing and Communication. Vol. 20(3) 1990.

Chart 1. A Sample of the Modified Nassi-Schneiderman Chart