From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: ** X-Spam-Status: No, score=2.1 required=5.0 tests=BAYES_00,FILL_THIS_FORM_LOAN, INVALID_DATE autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 10cc59,9f14a3ed0f431071,start X-Google-Attributes: gid10cc59,public X-Google-Thread: 103376,4bd960829a3eda10 X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 1994-09-22 02:31:44 PST Path: bga.com!news.sprintlink.net!howland.reston.ans.net!gatech!newsfeed.pitt.edu!dsinc!netnews.upenn.edu!msuinfo!harbinger.cc.monash.edu.au!aggedor.rmit.EDU.AU!goanna.cs.rmit.oz.au!not-for-mail From: ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) Newsgroups: comp.lang.ada,comp.lang.pascal Subject: ISO Pascal Extended Date: 21 Sep 1994 16:03:13 +1000 Organization: Comp Sci, RMIT, Melbourne, Australia Message-ID: <35oib1$bgd@goanna.cs.rmit.oz.au> References: <9408127793.AA779382777@smtpgw.fnoc.navy.mil> <354iqm$1r4@felix.seas.gwu.edu> <356ev1$s8o@goanna.cs.rmit.oz.au> <35717h$gtd@felix.seas.gwu.edu> NNTP-Posting-Host: goanna.cs.rmit.oz.au NNTP-Posting-User: ok Xref: bga.com comp.lang.ada:6082 comp.lang.pascal:14315 Date: 1994-09-21T16:03:13+10:00 List-Id: I commented in comp.lang.ada that >There is a new (Pascal)standard. ISO Pascal Extended. mfeldman@seas.gwu.edu (Michael Feldman) replied: >Interesting. I had not heard of this, nor seen any books describing it. >(Or is the standard available by ftp somewhere?) Apparently the compiler >houses are not rushing to implement it either. For what it's worth, here is a brief sketch of ISO Pascal Extended. Here's my summary: (a) Any Ada 83 compiler vendor could easily support ISO Pascal Extended as well. (b) If you were already using a language _other_ than Pascal, there is no reason to prefer Pascal Extended to Ada. (c) If you were hoping for a standard that would make it easier to migrate non-trivial Pascal programs between Turbo Pascal and Unix or mainframe Pascals, tough luck. (d) If you were hoping for a standard that would fix some of the nastier problems in Pascal (no error recovery in read(), forward procedure parameters _must_ be widely separated from the corresponding blocks, numeric labels, and/or precedence botch, &c), tough luck. In short, too little, too different, too late. Some brief notes in ISO/IEC 10206: 1991, Extended Pascal. 1. Identifiers any length, not case sensitive, can contain [_A-Za-z0-9]. All names can be qualified by an prefix. New special symbols '><' (sym.diff.), '=>' (renaming), '**' (power), 'pow' (power), 'and_then' (conditional and), 'or_else' (conditional or), 'import, 'export', 'module', 'qualified' (module-related), 'bindable' (interface to external objects like files), 'otherwise' (in case stmts), 'protected', 'restricted' (type modifier), 'value' (initial value). Integers can be written as base#extendedDigits. Note to Ada lovers: no closing #, no underscores in numbers, no radix point among the extendedDigits. 2. One of the most popular and most requested extensions and easiest to provide, namely alphanumeric labels, is NOT present. 3. The sections of a block can occur more than once and in any order (except that the new 'import' section can only occur once and at the beginning). Constants can be of structured types. Types and variables can be given initial values: VAR id1,...,idn : type VALUE expr; The initial value is actually a property of the _type_ and thus all the identifiers get copies of the _same_ value evaluated _once_. I prefer this to the Ada rule (where the expr is evaluated n times). It is not only fields that can be given default initial values (as in Ada), any type identifier can be associated with an initial value. 4. Variable syntax is extended: [ .. ] is a substring, functions can return structured values, and those values can be treated as variables, so that f(x)[i] f(x)[L..U] f(x).foo f(x)^ are all legal provided f has appropriate result type. As structured constants now exist, such constants can also be indexed &c. 5. Basic types: integer : no change except for new based literals +, -, *, /, div, mod, as before. New (X pow N) raises X to integer power N, where X is integer, real, or complex. real : still not usable in portable code. The standard is VERY clear that 'real' =/= 'float'. maxreal need not be the largest representable "real" number. The text says that "The value of EPSREAL shall be the result of subtracting 1.0 from the smallest value of real-type that is greater than 1.0". It is not clear whether the subtraction is to be _mathematical_ subtraction or real-type subtraction; if the latter it is entirely possible for EPSREAL to be 0.0, which does not seem very useful. +, -, *, /, as before. New (X ** P) raises X to real power P, where X is integer (-> real), real, or complex. Boolean : no change New operators (P and_then Q), (P or_else Q) evaluate P first, then evaluate Q only if needed. This was a wonderful opportunity to do something about the Great Pascal Operator Disaster, and give these new operators wider scope than the relational operators. That opportunity was spurned; they have the same b****y stupid precedence as 'and' and 'or'. char : no change (and still no BCPL-style escapes like *T or \t). One thing to note: the language needs *no* change to deal with 16-bit characters. complex : "The complex-type shall be a simple-type." What a sense of humour, eh? Pretty good, actually, except that it is built on top of an excessively fuzzy specification of "real". There is no "raise to complex power". cmplx(X, Y) and polar(R, T) construct complex numbers. enums : no change. *STILL* no enumeration read/write, and no tools to build it with. The built-in operations succ() and pred() have been extended: succ(X, N) -> return ord(X)+N with same type as X pred(X, N) -> return ord(X)-N with same type as X This also applies to Boolean, char, and integer. Note that it isn't quite good enough. Many people wanted an inverse of ord. Given type T = (C1, ..., Cn); var X: T; then X := succ(C1, K) is almost the same as X := T(K), but it breaks horribly if you add a new enum literal before C1. ranges : CAN BE DYNAMIC. Many Pascals have something like min(T) or first_of(T); to get that you can do pred(X, ord(X)) provided X is initialised. So the inverse of ord is X := succ(pred(X, ord(X)), K); {X := T(K)} Many Pascals have something like max(T) or last_of(T); I can discover no way to do that using what Pascal Extended provides. In Ada you can ask whether a variable would fit in a subrange: if X in T then ... In many Pascals you can also ask that: if X in [first_of(T) .. last_of(T)] then ... and that will work even when the bounds of T are changed. You can _not_ do that in Pascal Extended. restricted: T = representation; restricted T = abstraction (sort of). arrays : CAN BE DYNAMIC, because ranges can be dynamic. But Pascal still doesn't believe in zero. Both var x : array[1:0] of real; (*and*) y : array[n:n-1] of real; are illegal (the first is an error that must be reported at compile time, the second an error that must be reported at run time). Ada-like array constructors now exist. Functions can return arrays. Constructors exist. They begin with a type name, then resemble a case statement body with '[' ']' for 'of' 'end'. For example, consider type A = array [1..10] of integer; case I of 1..3,5: X := 135; 6..8: X := 68; otherwise: X := 4910 end; and the array-valued expression A [ 1..3,5: 135; 6..8: 68; otherwise: 4910 ] Note especially that element values are separated by SEMICOLONS, not commas. strings : If L is a static expression yielding 1, and R is either literally L..E or a type name for L..E, then packed array [R] of char is a fixed string type. (E can be dynamic.) string(E) is a "varying" string type (0 <= length <= E). Functions can return strings. readstr(StringSource{, variable}...); writestr(StringDestination{, output_parameter}...); do the obvious things. Built in functions length (current dynamic length), index (find substring), substr, trim, and two sets of comparisons; "+" is concatenation. records : no change except that OTHERWISE is allowed in a variant part and fields can be given initial values (because types can). Trap for young players: initial values in variant parts are allowed but basically useless (except when the case constant is specified in a call to new() or a constructor). Functions can return records. There are constructors. Put the type name, then what follows looks like a record type, with '[' for 'record', ']' for 'end', and only one branch in each variant. E.g. from type R = record A, B: integer; case C: Boolean of false: (D: char); true: (E: real) end; we get expressions like R[A, B: 2; case C: true of [E: 3.0]] Note in particular that SEMICOLONS are used as separators, not commas, which wrecks "panic mode" syntax error recovery. new types : there are two new predefined record types: TimeStamp has fields DateValid, year, month, day, TimeValid, hour, minute, second and possibly others, so you cannot write TimeStamp[...]. GetTimeStamp(t) stores the local date & time in t. date(t) returns a locale-dependent string from the date bits time(t) returns a locale-dependent string from the time bits There are no built-in operations for comparing TimeStamps or for doing arithmetic on them. BindingType has fields bound : Boolean name : implementation-defined string type and possibly others. See note 10. sets : no change, except that Functions can return sets. card() was in Jensen & Wirth, but not in the standard. Now it is in the standard. S1 >< S2 is symmetric difference. There are still no proper subset/superset comparisons. Set constructors can have the type name in front, but they still use COMMAS, not semicolons. So given type S = set of [1..10]; both [5,2] and S[5,2] are allowed. files : can be given an index, file [IndexRange] of Type, which allows random access. Functions cannot return files. rewrite(f) -- as before extend(f) -- preserves old contents; new writes at end reset(f) -- as before get(f) -- as before update(f) -- replace existing record put(f) -- as before SeekRead(f, n) -- random position for reading SeekUpdate(f, n) -- random position for update SeekWrite(f, n) -- random position for writing empty(f) -- true if f empty; f must be indexed! LastPosition(f) -- index of last record in f (may not be defined if f is empty!) position(f) -- index of currend record in f (may not be defined if f is empty!) The point about the positions is that if you do type FooIndex = (A, B, C); FooType = file [FooIndex] of char; var Foo: FooType; rewrite(Foo); then at that point LastPosition(Foo) and position(Foo) would have to be succ(A, 0-1), which does not exist. SeekUpdate sets the buffer variable, SeekWrite doesn't. For file names, see note 10. pointers: no change (still can't point to ordinary variables). schemas : TYPE id( {id*,:ordinaltype}*; ) = type. Example: type vector(n: integer) = array [1..n] of real; enquiries : TYPE OF can be used as a type; this is useful with conformant arrays and with schemas. Types can have initial values associated with them. type int0 = integer value 0; int1 = integer value 1; var x: int0; y: int1; x will be initialised to 0, y to 1. 6. Procedures and functions. The single worst mistake in Pascal was that when you declare a procedure or function forward, you are *forbidden* to repeat the parameter list at the actual declaration site. It would have taken about 4 lines of text written twice to *allow* duplication of the parameter list and thus let people avoid this error prone bit of nastiness, and since a compiler must _already_ retain the parameter names and types, it would require _very_ little work in a compiler to support this extension. BUT THE WRETCHED COMMITTEE DID NOT ADD THIS EXTENSION! Assignment to the function identifier was always a rather error- prone method of returning a result; a 'return' statement as in PL/I or C is far easier to get right. The only change here is that you can now give an alias for the function result: function foo(...) = bar: T; ... within the body of foo() you can use 'bar' as a variable and you _can't_ use 'foo' that way; the final value of 'bar' is the function result. Value and VAR parameters can now be declared PROTECTED which means that the routine is not allowed to change them. There is no exact equivalent of Ada's "in" mode; PROTECTED VAR still requires a variable actual parameter, not an expression, and it is still a by-reference method, so the value _may_ change as a result of aliasing. PROTECTED {value} still implies a copy. Conformant array parameters are _still_ an optional (level 1) feature, despite the fact that the standard _demands_ a more powerful method whose underlying machine can necessarily support conformants as well. 7. A form of error handling was proposed and described in SigPlan Notices, but is NOT in the standard. There is NO form of error handling in the standard. In particular, there is no way to recover from errors in data processed by read() or readln(), which means that anyone trying to cope with real data has to roll her or his own. Speaking of errors, I _think_ the standard in effect forbids the use of IEEE 754/854 arithmetic. 8. Statements. Case statements can have 'otherwise' (it must be last) and case labels can be ranges (so basically a case label is now a set literal missing its brackets). For statements have an additional form: for Identifier in SetExpression do Statement (the order in which elements are processed is implementation dependent). No error recovery for input/output. No enumeration input/output. Strings can be read and written. 9. Modules. Years ago, UCSD Pascal introduced "units". Much of UCSD Pascal was carried over to Borland's spectactularly successful "Turbo Pascal", which today is _the_ practical Pascal system. The mechanism is simple, demonstrably implementable on small machines, useful, and the de facto standard. No single change to the Pascal standard would have been more useful than "blessing" this established practice. So the standardisers invented something new. It is necessary to distinguish between MODULES and INTERFACES. An interface is a named collection of constant,type,variable,procedure, and/or function identifiers. Modules import identifiers _from_ interfaces (not from other modules), and they export one OR MORE entire interfaces, not identifiers. Apart from the distinction between modules and interfaces, and the ability of a module to export more than one interface, the module system is pretty much like Modula-2. The extra generality is more apparent than real. Anything that can be done using Pascal Extended modules can be done using UCSD Pascal units, with one UCSD unit for each Extended module AND for each Extended interface. Almost anything: Pascal Extended allows circular dependencies, but initialisation doesn't work if you do that. This one area of the standard, more than anything else, makes me feel that the Pascal Extended committee were out of touch. 10. One widely implemented extension is reset(FileVariable, FileNameString[, ... Status]); rewrite(FileVariable, FileNameString[, ... Status]); and if you have extend, extend(FileVariable, FileNameString[, ... Status]); would make a lot of sense. The idea is that these extensions let you specify the file name as a string, and optionally get a "status" result instead of aborting if the file cannot be opened. Turbo Pascal does something different and clumsier, but has the machinery to support these if that were the standard. The standard has adopted neither the extension above (which was in use even before the first Pascal standard) nor the Turbo Pascal equivalent. Instead, there is a whole new major concept of "bindable" types and variables, and a BindingType. What you have to do is explicitly say var b: BindingType; f: bindable file of ... ; begin b := binding(f); { initialise hidden fields } b.name := FileNameString; bind(f, b); { this does not change b } b := binding(f); if b.bound then { all went well } else { the file could not be opened }; This can be abbreviated to b := binding(f); { initialise hidden fields } b.name := FileNameString; bind(f, b); { this does not change b } if binding(f).bound then { all went well } What does it mean to have a bindable variable that is not a file? It would make a very nice typed interface to memory-mapped I/O: 'bind' could open the file and map it into memory, and set the variable to point to the area of memory, 'unbind' could close the file. On the other hand, the standard doesn't _require_ bind & unbind to work with anything except files. I really do _not_ want to have to use b := binding(f); b.name := FileNameString; bind(f, b); if binding(f).bound then begin reset(f); when existing dialects would let me say reset(f, FileNameString, status); if status = IO_OK then begin ... I can program my way around this for any specific file type, but as Pascal Extended still lacks generic procedures, I'd have to do it over and over again. Note in particular that the predefined type 'text' is NOT bindable! Summary: The standard is 220 printed pages. Compared with Ada 83, it lacks nested packages, tasks, generics, *portable* floating point, any kind of exception handling, and pleasant I/O, but it does have dynamic ranges, type schemas with discriminants, record and array expressions, and strings. The new features of the standard tend not to be compatible with the dialects that already had them. There is no detectable influence from Object Pascal. -- "The complex-type shall be a simple-type." ISO 10206:1991 (Extended Pascal) Richard A. O'Keefe; http://www.cs.rmit.edu.au/~ok; RMIT Comp.Sci.