Commentaries on the Revised Report The following commentaries are issued by the Sub-committee on ALGOL 68 Support, a standing sub-committee of IFIP WG 2.1. They deal with problems which have been raised in connection with the Revised Report on the Algorithmic Language ALGOL 68, and mostly take the form of advice to implementers as to what action they should take in connsction with those problems. These commentaries are not to be construed as modifications to the text of the Revised Report. Note that commentaries are not being published on trivial misprints. Those concerned about such misprints (and especially those preparing new printings of the Report) should apply to the Editor of the ALGOL Bulletin for the latest list of agreed Errata. {{The first two commentaries below have already been published in AB42.3.1. They are reprinted here for the sake of completeness.}} {{Commentaries 1 through 30 have already been published (see AB42.3.1 and AB 43.3.1). The two new commentaries published here were accepted by the Support Sub-committee at its meeting in April 1979.}} 1) Interruption of loops. Although the semantics of 3.5.2 suggest that a count of the number of iterations of a loop should be kept even when the for-part and the intervals of a loop-clause are EMPTY, it is clearly unnecessary for an implementation actually to implement the count in this case, and it would therefore be unreasonable for an implementation to interrupt (2.1.4.3.h) the elaboration simply because such a count had overflowed. Thus, the elaboration of WHILE TRUE DO SKIP OD would be expected to continue beyond maxint iterations and would not be terminated unless some other action of the operator or operating system intervened. On the other hand, if a for-part or a FROBYT-part is present in a loop-clause an iteration count must be kept and will be subject to the arithmetic limitations of the hardware. If this count should overflow, therefore, it is reasonable for the implementation to interrupt the elaboration under the provisions of 2.1.4.3.h. For example, in: FOR i FROM maxint-3 TO maxint DO print(i) OD the implementation may attempt to compute the quantity (maxint+1) (as is indeed suggested by 3.5.2.Step 4), and it will then be quite justified in interrupting. 2) Plus operator on strings. The + operator for STRINGs declared in 10.2.3.10.i works with strings whose descriptors are exactly flat (2.1.3.4.c), e.g.: LOC [1:0] CHAR + "abc" # yields "abc" # but has undefined semantics if a descriptor is "super flat", e.g.: LOC [1:-1] CHAR + "abc" # should have yielded "abc" also # This is an error in the Report, and implementations should accept all such STRINGs and yield the same result as if LOC [1:0] CHAR had been provided. 3) Scope of heap variables. There is an error in 5.2.3.2.a of the Report. The intention of this section was to ensure that the scope of the heap should be the same as that of the outer level of the particular-program so that, for example, the following would be well defined: BEGIN MODE PCHAIN = STRUCT(PROC(INT)VOID p, INT i, REF PCHAIN next); LOC REF PCHAIN pstart := NIL; LOC INT j := 0; PROC p = (INT a)VOID: j +:= a; # the scope of p is determined by its use of the variable j # ... pstart := HEAP PCHAIN := (p, 1, pstart); ... END In fact, the first environ created during the elaboration of the particular-program contains 4 other environs (including the primal one) nested within itself {2.2.2.a and 10.1.1}. Therefore, to achieve the intended effect, the first requirement of Case B of 5.2.3.2.a should have been (i) the primal environ {2.2.2.a} is the environ of the environ of the environ of the environ of E1 (sic). {{The following group of commentaries is concerned with the Transput section of the Report. The items numbered 4 through 16 describe admitted errors in the Report. Items 17 through 21 are concerned with errors in or amplifications of the pragmatics. Items 22 through 30 contain interpretations of doubtful points or suggestions for sub- or superlanguage features.}} 4) Syntactic errors in the standard-prelude. There are a few cases in the standard-prelude of syntactically incorrect ALGOL 68 (as augmented by 10.1.3). They are as follows: a) 10.2.3.3.n+1 (INT r =" should have been "(L INT r =" b) 10.3.1.3.cc."on line end"."Example"+3 "PROC(REF FILE file) BOOL:" should have been "(REF FILE file) BOOL:". c) 10.3.2.1.d+8 "fixed (SIGN" should have been "fixed (K SIGN". d) 10.3.2.1.j+12 "L real width" should have been "L real width". 10.3.2.1.j+23 "string to L int" should have been "string to int" 10.3.2.1.j+26,+28 "L max real" should have been "L max real". e) 10.3.2.1.n+2 "'1.0' and of '1.0 +" should have been "'L 1.0' and of 'L 1.0 +" f) 10.3.3.2.a."OP !"+9 10.3.3.2.b+17 10.3.5.2.b+13 The series commencing on these lines were intended to yield the values (CHARs) of their conditional-clauses, whilst ensuring that "read mood" remained set. They should therefore have been of the form: CHAR cc = IF ... THEN ELSE ... FI; set read mood (f); cc g) 10.3.5.1.a."edit L compl"-6 "OR NOT sign2 AND exp < 0" should have been omitted. 5) Standconv and FILE. Although the Report defines the mode of "standconv" (10.3.1.2.d) to be PROC(CHANNEL)PROC(REF BOOK)CONV, and the mode FILE (10.3.1.3.a) to be a very specific structure (albeit with hidden field-selectors), so that the user may in theory (but without practical use) write standconv (standin channel) (SKIP) and FILE f := (SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP) , implementers should feel under no obligation to implement "standconv" and FILE with these particular modes (provided, of course, that "standconv" has one CHANNEL parameter) nor to accept phrases such as the above which rely upon them. (See also the footnote on page 262 of the Revised Informal Introduction.) 6) Establish. The procedure "establish" (10.3.1.4.b) attempts to check the validity of its parameters "p", "l" and "c". There is an error in the Report whereby, given maxpos OF chan = (10, 50, 100), it accepts for (p, l, c) such clearly unsuitable values as (5, 25, 200) and (5, -100, 0). In lines 10.3.1.4.b+8,+9 the operator BEYOND should have been an operator EXCEEDS, defined as PRIO ? EXCEEDS = 5, OP EXCEEDS = (POS a, b) BOOL: p OF a > p OF b OR l OF a > l OF b OR c OF a > c OF b; 7) Associate. There is a bounds error in "associate" (10.3.1.4.e) if the descriptor of the formal-parameter "sss" is flat {2.1.3.4.c} {there are zero pages} or, otherwise, if the descriptor of "sss[1]" is flat (the pages have zero lines). It is nevertheless intended that such values of "sss" be accepted (the rest of the transput routines still having well-defined meanings in such cases). Note also that the lower bounds of all descriptors involved in "sss" are required to be 1, a fact not made clear in 10.3.1.4.ee. 8) Reset. There should have been a "DOWN bfileprotect; UP gremlins" before the final FI of 10.3.1.6.j. This then ensures that the semantics of "reset" resemble closely those of "close" followed immediately by re-"open". In particular, it makes it clear that implementations may always entrust complete lines of books to their operating systems as they are produced and that alterations made to those lines by the operating system (e.g. padding with blanks to some multiple of the word length, or moving the logical end - which might have been at the end of some line containing text - to the start of the following line) are not in violation of the Report 9) Whole, fixed and float. It was intended that the procedures "whole", "fixed" and "float" (10.3.2.1), when provided with combinations of "width", "after" and "exp" parameters under which no number could possibly be converted (e.g. "whole(x, +1)" and "float(x, 8, 4, 3)") should call "undefined" before possibly returning "errorchar"s. There is an error in "whole" whereby "undefined" is not called in the case of "whole(1, +1)" (nor in the case of "float(1, +7, 3, +1)"). Line 10.3.2.1.b+1l should have been IF length = 0 THEN undefined; ABS width * errorchar ELIF char in string (errorchar, LOC INT, s) Contrariwise, "fixed(-.123, -4, 3)" does call "undefined" even though "fixed(+.123, -4, 3)" returns, quite correctly, ".123". The test "length > after" in 10.3.2.1.c+4 should not have depended on the sign of "x". Likewise, "float(1\100, +6, 1, +2)" calls "undefined", even though "float(1\-4, +6, 1, +2)" returns, quite correctly, "+.1\-3". If the failure of the tests on "before" and "after" at the beginning of "float" were to call "undefined" only on the initial call of "float", and were to return "errorchar"s from within its recursive calls, then this example would return "errorchar"s without calling "undefined" first. This is more reasonable, and implementations should behave accordingly. If "width" = 0, it is intended that the shortest possible string containing the correct result should be returned (except in "float" where the "width" parameter should never be zero). Following this intention, if a string of "errorchar"s is to be returned a string of length 1 would be appropriate, rather than the empty string at present prescribed. The only cases affected are those such as "fixed(x, 0, -3)" and "float(x, 0, -3, 3)", both of which will have first called "undefined". In "fixed", line 10.3.2.1.c+8, use is made of integer arithmetic in the form of "L 10 ^ length". This might overflow with large values of "y". Such was not the intention, and real arithmetic, in the form of "L 10.0 ^ length", should have been used. In "fixed", line 10.3.2.1.c+14, the test "y < L 1.0" is intended to yield TRUE if there are no significant digits before the decimal point. Due to the rounding in the preceding call of "subfixed" (as in "fixed(0.996, -5, 2)") it may yield TRUE erroneously. The test should have been y + L .5 * L .1 Î after < L 1.0 In "float", if "before" = 0 and "width" < 0 and "v" > 0, " " should be yielded before the decimal point. There is an error whereby "0" is yielded in this position. One possible cure is to replace the assignation commencing in 10.3.2.1.d+7 by s := (x < L 0.0 | "-" |: width > 0 | "+" | " ") + fixed (y, -(ABS width - ABS exp - 2), after) + "\" + whole (p, exp); For examples of the use of these procedures see Commentary 18, and for a discussion of accuracy and the properties of real arithmetic as used in them see Commentary 25. 10) Putting of strings "put("")" at end of page has no effect (i.e. no event is provoked). It should have been ensured that the current line was "good", so that the empty string could have been considered to have been written upon it. Therefore, before the loop-clause on line 10.3.3.1.a+39, "(NOT get good page (f, FALSE) | undefined)" should have been present, and likewise "(NOT get good page (f, TRUE) | undefined)" before the loop-clause on line 10.3.3.2.a+77. 11) Put char. There is an error in "put char" (10.3.3.1.b) whereby the "char error mended" routine called in line 10.3.3.1.b+33 may, by performing a read operation, set the read mood. There should therefore have been a call "set write mood (f)" before the call "check pos (f)" in line b+36. 12) Get next picture. If a collection is replicated zero times, as in "$ l n(0) (3d, 3d) l $", its pictures should not be selected [10.3.4.1.1.gg} although the insertions immediately preceding and following it should be performed. The procedure "get next picture" (10.3.5.b), as presently formulated, erroneously selects the pictures of the collection once. Also, in line 10.3.5.b+22 of "get next picture" there is a test to ensure that "undefined" is called if the staticizing of the insertion or the elaboration of the replicator should cause a different format to be associated with the file (for there is no sensible continuation in such a case). The same test should have been made again after line 10.3.5.b+23, in case the getting or putting of the insertion should have associated a new format. Likewise, to ensure uniformity of treatment of format-patterns and collections, a similar test ought to have been made after lines 10.3.5.j+4 and 10.3.5.j+5 of "do fpattern". 13) Do fpattern. The assignation "cp OF aleph[forp] := 0" in 10.3.5.j+12 will cause an unintended index overflow in a subsequent call of "get next picture". It should have been "cp OF aleph[forp] := 1" {cf. 10.3.5.b+9}. 14) Putf. In 10.3.5.1.a,"edit L compl"-4, the expression "t[ :b] + point + t[b+2: ]" assembles an incorrect string causing, for example, "printf(($ 4d.d $, 13.2))" to print "013.2." instead of "0013.2" and "printf(($ 5d.d $, 13.2))" to be undefined {note that "subfixed" suppresses all nonsignificant leading zeroes}. The expression should have been "(a = 0 | t + point | t)". 15) Edit string. The declaration "CHAR sj = s[j]" in line 10.3.5.1.b+11 results in a bounds error in cases such as "printf(($ 3z+n(0)d $, 0))". {"$ 3z+ $" would also have caused the problem had it been syntactically legal. "edit string" is asked to edit "+000" with, effectively, the sequence of markers "u,u,u,+". The first "u" is matched against the "+" causing "again" to be set to TRUE and "j" to be incremented so as to point one character further along the string than expected. This is still true when the "+" marker is reached, hence the bounds error.} A sufficient, but not too elegant, solution is to make that declaration CHAR sj = (j <= UPB s | s[j] | "0") 16) Indit string. In "indit string" (10.3.5.?.b), in the case when the marker is "a" or "b" with a replicator of value zero, as in "readf(($ n(0)a $, s))", "no sign" is never set to TRUE, so that the example erroneously assigns "+" to "s". A satisfactory cure would be to replace 10.3.5.2.b+21 by S := (marker OF sf[l] = "b" OR marker OF sf[1] = "a" | "" | "+"); and to remove the declaration of "no sign" and all statements of which it is a constituent Also, the flag "space found" should have been reset to FALSE after an "e" marker or an "i" marker (lines 10.3.5.2.b."marker="e""+2 and "marker="i""+2) so as to prevent, for example, "readf(($ 3z-d e z-d $, x))" from erroneously accepting "µ1234\123". 17) Oversimplified pragmatics. The Report contains examples of pragmatic remarks which, whilst they indicate the intention of the formal definition so far as most practical situations are concerned, nevertheless, if examined legalistically, do not tell the exact truth. It should be emphasized that the pragmatics were never intended to be an alternative definition of the language. However, it has been thought useful to document some of these cases. a) 10.3.1.3.dd.last sentence A conversion key may also be the "standconv" of some channel, as in make conv( standout, standconv( stand in channel)) b) 10.3.3,second sentence A PROC(REF FILE)VOID routine provided by the user may also be a data-list element. c) 10.3.3.2.aa,bb,cc,dd In all of these, the phrase "the book is searched from the current position" would he more accurate. d) 10.3.3.2.hh Before any characters are read, "newpage" will be called if necessary. 18) Examples of whole, fixed and float. The examples of the use of "whole", "fixed" and "float" in 10.3.2.1 do not illustrate all of the possibilities of those procedures. Here is a more complete set of examples: print (whole (i, -4)) which might print "µµµ0", "µµ99", "µ999", "9999", "µµ-9", "µ-99", "-999" or, if i were greater than 9999 or less than -999, "****", where "*" is the yield of errorchar; print (whole (i, +4)) which might print "µµ+0", "µ+99", "+999", "µµ-9", "µ-99", "-999" or, if i were greater than 999 or less than -999 , "****"; print (whole (i, 0)) which might print "0", "99", "999", "9999" "99999" "-9", "-99", "-999", "-9999" or "-99999"; print (whole (2.3, 0)) which prints "2"; print (whole (2.7, 0)) which prints "3"; print (whole (i, -1)) which might print "9"; print (whole (i, +1)) which must always call undefined (then possibly returning "*"), since there exists no value of i which could be converted in a width of +1; print (fixed (x, -6, 3)) which might print "µ0.272", "µ2.718", "27.183", "271.83" (in which one place after the decimal point has been sacrificed in order to fit the number in), "2718.3" (2 places sacrificed), "µ27183" (all places sacrificed), "-0.272", "-2.718", "-27.18" (1 place sacrificed), "-271.8", "µ-2718" or, if x were greater than 999999 or less than -99999, "******"; print (fixed (x, +6, 3)) which might print "+0.272", "+2.718", "+27.18", "+271.8", "µ+2718", "-0.272", "-2.718", "-27.18", "-271.8" or "µ-2718; print (fixed (x, -4, 3)) which might print ".272"; print (fixed (x, +5, 3)) which might print "+.272" or "-.272"; print (fixed (x, 0, 3)) which might print ".272", "2.718", "27.183", "271.828", "-.272", "-2.718", "-27.183" or "-271.828"; print (fixed (x, n, 0)) which must always print the same as print (whole (x, n)); print (fixed (i, -6, 3)) which might print "µ0.000", "99.000", "999.00", "-9.000", "-99.00" or "-999.0"; print (fixed (x, -6, 6)) print (fixed (x, +6, 5)), print (fixed (x, -6, -5)) all of which must always call undefined (then possibly returning "******") since there exists no value of x which could be so converted or, in the last case, since the after parameter of fixed may not be negative; print (float (x, +9, 3, +2)) which might print "+2.718\-1", "-2.718\+0", "+2.72\+11" (in which one place after the decimal point has been sacrificed in order to fit the exponent in), "+2.7\+111" (2 places sacrificed), "+27\+1111" (3 places sacrificed), "+3\+11111" (4 places sacrificed) or, if ABS x were greater than 9.5\99999, "*"*******"; print (float (x, -9, 3, -2)) which might print "µ2.718\-1", "-2.718\µ0", "µ2.718\11", "µ2.72\11l", "µ2.7\11ll", "µ27\11111", "µ3\111111" or, if ABS x were greater than 9.5\999999, "*********". print (float (x, +9, 4, +2)) which might print "+.2718\+0" or "-.2718\+1"; print (float (x, +9, 0, +2)) which might print "+27182\-5" or "-27182\-4"; print (float (0.0, +9, 2, +2)) which prints "µ+0.00\+0"; print (float (x, m, n, 0)) which must always print the same as print (float (x, m, n-1, -1)) if n>0, or the same as print (float (x, m, n, -1)) if n=0; print (float (x, 0, m, n)), print (float (x, +7, 3, +2)), print (float (x, 4, 0, +2)), print (float (x, 9, -3, 2)) all of which must always call undefined. 19) Complementarity of put and get. Generally speaking, if a value of some mode A is successfully output using "put" at a given position (p, l, c) in the book, it may be reinput into a REF A name by a call of "get" at that same position. Moreover, the current position after the "get" will be the same as it was after the original "put". The principal exceptions to this are listed below. It is assumed that the same CONV is in use on both occasions and that no event routines have been provided. It is also assumed that the error reported in Commentary 10 above has been corrected. a) If a string that is put includes characters in the "term" field of the file, the reinput string will be truncated to just before the first such character. b) If a string that is put does not completely fill the line, and if the file is not compressible or another string is subsequently put on the same line, the reinput string will extend to the end of the line (or to an earlier terminating character). As a special case of this, putting an empty string will not result in reinputting an empty string unless the line had already overflowed (10.3.1.5), or "newline" was immediately called (the file being compressible) or a terminating character was immediately put. c) If a string that is put is split over the end of a line (the default action when no "line end" routine is provided), the reinput string will be truncated to the line end. As a special case of this, if a non-empty string is put when the line has overflowed, an empty string will always be reinput d) If the mapping performed by the CONV is not the same in both directions, then differences may arise. For example, it is quite possible that "A" and "a" both map into the external character "A", which would presumably be reinput as "A". e) If, when putting, the current position is before the logical end of file (which with a sequential access book can only happen if the logical end is within the current line, but with a random access book can happen anywhere), the characters already present between the current position and the logical end can affect what is read back. For example, supposing that "int width" = 6: put (f, (newline, " 456 ")); set char number (f, 1); put (f, 123) will result in the printed line "µµµ+123456µ" with obvious disastrous consequences upon a subsequent "get (f, i)" A related problem arises if there is insufficient room for an arithmetic value on the remainder of the current line. Suppose that the length of a line is 10 characters, that "int width" = 6 as before, and that "real width + exp width + 4" > 6: put (f, (newline, "µµµ", 123456)); set char number (f, 4); put (f, 2.718281828) The 2.71828, in some form such as +2.718281828\µ+0, will be put on the next line so that a subsequent "get (f, x)", at the position of the original "put", will obtain the real number 123456.0 20) Putting of numbers. In the pragmatic remarks 10.3.3.1.aa, bb, cc, after "the current line", it would be helpful to insert "(or one less than this when at the start of the line)". 21) General patterns. The pragmatic remark 10.3.4.10.1.bb is incomplete. It was intended to read: bb) A value ... whose pattern Q ...: ° P is staticized; ° the insertion of Q is performed; ° (any parameters ...) ... using get; ° the insertion of P is performed,} 22) CONVs. The CONV feature of the transput is one of the less satisfactory features of the Report. It does not interface well with conversion features that are likely to be provided by the hardware or operating system (which would be better invoked by JCL commands or features in "idf" strings, anyway). Its correct implementation is difficult to do efficiently. Noting that the Report nowhere obliges an implementer to provide any CONVs beyond one "standconv" for each CHANNEL (and these are likely to be null operations, or at least very straightforward, in most systems), we wish to recommend that implementers should not in general provide additional CONVs unless they have pressing problems with their local character codes. In any event, if any additional CONV is provided, at least the digits and the other characters required for the transput of arithmetic and BITS values should always be convertible. 23) Physical file end When (on output) the physical end of the book is reached, the event routine corresponding to "on physical file end" is supposed to be called as soon as the user attempts to put any character on the line (just beyond the physical end) that isn't there. If the physical limits of the book are known to the run-time system in advance (e.g. they are simply the "p", "l" and "c" parameters of "establish"), this raises no problem. In practice, however, the limit usually becomes known only when the operating system refuses to accept the contents of the buffer, which will not occur until, having put characters on the line with apparent success, the user calls, for example, "newline" Although this situation is not recognised by the Report, it is nevertheless recommended that the physical-file-end event routine should thereupon be called. In terms of the transput model of the Report, it should be as if some system-task had suddenly reduced the size of the text of the book just as the body of "newline" (or "newpage") was entered, causing "physical file ended (file)" {10.3.1.5.h} to return TRUE. Users should be warned that any characters written to the buffer up to that point may have been lost. They can test whether this has happened by seeing whether "char number (file)" {10.3.1.5.a} returns an integer greater than 1 (note that in all present circumstances where the physical-file-end event is called the char number will be found to be 1, indicating an empty line). 24) Reidf. The procedure "reidf" can only be called when the book to be renamed has already been opened via some file. However, not all operating systems are able to perform their renaming function on an opened book. For implementers faced with such systems, one of the following courses of action is recommended: a) Do not provide the "reidf" facility at all (the Report nowhere requires that "reidf possible" should ever return TRUE); b) "reidf" causes no immediate action, but the revised "idf" is remembered and the book is renamed when the file is eventually "close"d (or "lock"ed) It is to be noted that, where "reidf" is provided, the set of strings acceptable as its "idf" parameter may be only a subset of the "idf"s acceptable to "open" and/or "establish", especially if the latter are permitted to contain information concerning the disposal of, or the access rights to, the book 25) L int width, etc The environment enquiries "L int width", "L real width" and "L exp width" (10.3.2.1.m, n, o) are primarily provided in order to fix the numbers of digits to be allowed for when numbers are output with "put". In the case of REAL (and hence also COMPL) numbers, a sensible choice of "L real width" will depend upon how accurately the implementation actually performs its conversions in "put". "L exp width" should reflect the manner in which "L max real" is actually converted. A numerical analyst would expect, in an ideal world, that conversions would produce sufficient digits to ensure that different real numbers are always converted to different strings. In actual implementations this may not be practicable. In any case the value of "L real width" should reflect what is actually done in "put". The Report does not seek to define the accuracy of the conversions performed by "fixed" and "float" (10.3.2.1.c, d) (and hence by "put" and "putf") and by "string to L real" (10.3.2.1.j). Here, as elsewhere where operations are performed upon real numbers {2.1.3.1.e}, implementations should adhere to the best practices of numerical analysis. It is best, therefore, not to regard the texts of these procedures as defining the strings or values which would have been obtained had the real-number operations therein actually been performed according to the limitations of the particular implementation, but rather to consider the strings or values which would have resulted if real numbers and operations in the sense of mathematics had been used, and then to consider how close to these ideal results it is reasonable for the implementation to get. In particular, no question of arithmetic overflow should arise (so that it is defined that all values up to and including "L max real" may be converted) Although, with this interpretation, the precise definitions of these environment enquiries become of less importance, it should be noted that there are some specific errors in "L int width" and "L real width": a) In the present definition of "L int width", "maxint = 100" implies "int width = 2". Also, real arithmetic is used which is undesirable where an exact result should be obtained. Line 10.3.2.1.m+4 should therefore have been WHILE L 10 ^ (c-1) <= L max int % L 10 DO c +:= 1 OD b) The comment in 10.3.2.1.n should have been: "... different strings are produced by conversion of 'x * L 1.0' and of 'x * (L 1.0 + L small real)', for all admissible, non-zero x, ...". 26) INTYPE. Due to an oversight in the definition of INTYPE (10.3.2.2.d), it is not possible to write LOC STRUCT (BOOL b, STRING s) x; read (x) although the given straightening algorithm handles this case correctly (as will all likely implementations); moreover "print (x)" is allowed. Implementers are therefore recommended to allow, in addition to the 'MOOD's from which INTYPE is presently united, modes which (whilst still subject to the other restrictions given) contain 'flexible row of character' (but not other 'flexible' modes). 27) Default action of event routines. It is generally the case that, in each situation where an event routine is called, a default action is provided (possibly a call of "undefined") and is taken if the routine returns FALSE (even if it has actually mended the situation). There are, however, three exceptions to this, brought about when the position is not "good" {10.3.1.6.dd}: viz. when a string is being input with "get", or any value is being input with "getf", or any value is being output with "putf". In these cases, the default action (to terminate the input in the first case, and to call "undefined" in the others) is only taken if the position remains "bad", and the value returned by the event routine makes no difference, except insofar as it may prevent any further attempts to fix the situation (see "check pos" {10.3.3.2.c}). To obtain a more consistent treatment of event routines, implementers are recommended always to take the default action when an event routine returns FALSE. This means that in "get", lines 10.3.3.2.a."(REF STRING ss)"+2:+3 are to be interpreted as if they had been written: WHILE IF NOT check pos (f) In "edit string", line 10.3.5.1.b+3 is to be interpreted as if it had been (NOT supp | (check pos (f) | put char (f, c) | undefined)); with similar changes to be made in 10.3.3.1.c-4 ("put char"), 10.3.5.g+10 ("put insertion") and 10.3.5.i+14 ("aligmment"), and in "indit string", line 10.3.5.2.b."OP !"+4 is to be interpreted as if it had been IF CHAR k; (check pos (f) | get char (f, k) | undefined); with similar changes to be made in 10.3.5.h+11 ("get insertion") and 10.3.5.i+10 ("aligmment"). To accomodate all these changes, "check pos" (10.3.3.2.c) has to be rewritten as follows: PROC ? check pos = (REF FILE f) BOOL: BEGIN BOOL reading = read mood OF f, BOOL ended := TRUE; WHILE IF get good page (f, reading) THEN (line ended (f) | (line mended OF f)(f) | ended := FALSE) ELSE FALSE FI set mood (f, reading); NOT ended END ; 28) Last insertion of a collection. Normally, when a picture is encountered during formatted transput, it is "staticized", i.e. its dynamic replicators are all elaborated (collaterally) before transput using that picture commences. Moreover, if the transput is terminated by a jump at this stage, any subsequent transput will start with the next following picture. Clearly, it is not appropriate to staticize the whole of a collection-list at one time, and it is therefore prescribed that its pictures be staticized one by one as they are required for transput Finally, at the end of the collection-list, there may be a final insertion to be performed when the collection-list has been repeated as required by its replicator. The Report defines that the replicator of this final insertion be elaborated collaterally with the staticizing of the last picture on its last time round; i.e. before any possible side effects of the transput using that picture. This is not what a user might expect nor is it easy to implement, and implementers should therefore feel free to elaborate it after the transput of the final picture (but before returning from "putf" or "getf", of course). If the transput should terminate at this point, the collection-list should be deemed to have been completed and future transput should start with the next complete picture or collection-list. The final insertion of a format-pattern should be treated similarly. 29) G patterns. In formatted output a g-pattern can be used to obtain the effect of "put" and, if it is provided with parameters, of "whole", "fixed" and "float" also. Thus "printf (($g(6.3)$, x))" is exactly equivalent to "print (fixed (x, 6, 3))". On input, a g-pattern can give the effect of "get" but, since "whole", "fixed" and "float" cannot be used with "get", there is no meaning for any parameters, and none should therefore be present. In fact, the Report gives an entirely false impression of input/output compatibility by permitting parametrized g-patterns on input, but directing that their parameters be ignored. It would therefore be better to regard such parametrized g-patterns on input as not being "input compatible" {10.3.4.1.1.ii} with their data-list values and to call the "on value error" event (with default action "undefined" if it returned false) whenever one was encountered. 30) Binary transput An implementer of the binary transput defined by the Report is not, in general, able to output stored values in the form in which they are stored internally (which may include packing, storing of fields in different orders and inclusion of extra fields such as garbage-collector templates). This is because of the requirement to be able subsequently to reinput their component fields or elements either singly, or stowed in other ways. For example, the following is well defined: putbin (standback, (STRUCT (REAL a, [] BOOL b) (2.0, (TRUE, TRUE, TRUE)), STRUCT (CHAR c, INT d) ("c", 1))); reset( stand back); getbin( standback, (LOC STRUCT (REAL a, BOOL b1), LOC STRUCT ([1:2] BOOL b2, CHAR c), LOC INT)) There exists a sublanguage in which output values of some mode may only be reinput into variables of that same mode. Clearly, this sublanguage is easier (and more efficient) to implement, whilst detracting little from the power of the language (and even increasing its safety), and it is therefore commended to implementers. The sublanguage is defined by the following modified forms of the procedures in 10.3.6: PROC ? to bin = (REF FILE f, OUTTYPE x) [] CHAR: C present text C ; PROC ? from bin = (REF FILE f, OUTTYPE y, [] CHAR c) OUTTYPE: C present text C ; PROC put bin = (REF FILE f, [] OUTTYPE ot) VOID: IF opened OF f THEN set bin mood (f); set write mood (f); FOR k TO UPB ot DO [] CHAR bin = to bin (f, ot[k]); FOR i TO UPB bin DO OD OD ELSE undefined FI ; PROC get bin = (REF FILE f, [] INTYPE it) VOID: IF opened OF f THEN set bin mood (f); set read mood (f); FOR k TO UPB it DO OUTTYPE y = C the value referred to by the yield of ot[k] C; [1:UPB (to bin (f, y))] CHAR bin; FOR i TO UPB bin DO OD; C the name yielded by ot[k] C := from bin (f, y, bin) OD ELSE undefined FI ; 31) Overwriting of existing books and control of the write mood. The Report provides that, where both "put" and "get" are "possible", an existing book with sequential access may be read up to some arbitrary point and overwritten with new information from there onwards. If a given implementation can only overwrite from the beginning of a line, or even from the start of the book, it should be arranged that "put possible" (which is a procedure) only returns TRUE when the current position is at a place from which overwriting may commence. However, even if "get" is not "possible" (but "put" is), the Report permits such an arbitrary point to be reached by suitable calls of "space", "newline" and "newpage". However, these calls can only be implemented by reading the book from the beginning, counting characters and line and page terminators, and this is impossible by hypothesis. It is indeed strange that even "put(f, newline)" causes the book to be read in order to skip a line. It is even stranger that there is no way in which the first line of an existing book can be overwritten with an empty line. These difficulties all stem from the fact that it is the putting of an actual character which causes the logical end of the file to be retracted to the current position {10.3.3.1.b}. Implementers are therefore advised to test in "set write mood" (10.3.1.4.j) for the case where the logical file end is beyond the current line in a sequential access book, and to retract the logical file end there rather than in "put char". Moreover, it should now be the case that all calls of "put" and "putf", even "put(f, ())", should set the write mood and bring about this effect. To this end, implementors should always call "set write mood" at the start of "put" (10.3.3.1.a) and of "putf" (10.3.5.1.a) {just after the tests for "opened" which are currently provided}. Very few programs will be changed in meaning as a result of this and, moreover, the precise effect defined by the Report can always be obtained by writing "get(f, newline)" (in situations where "get" is "possible" , of course). 32) On the scope of the particular-program. According to the letter of the Revised Report the first environ created during the elaboration of the ENCLOSED-clause of the particular-program is newer in scope than the environ of the user-task in which it is contained. This would imply that the heap scope (see also Commentary 3) is newer than the scope of the variables (in particular "stand in", "stand out" and "stand back") declared in the particular-prelude. As a consequence, the elaboration of, e.g., the call "open(stand in, "", stand in channel)" in the particular-prelude would result in scope violation and thus be undefined. This is, however, not the intention. In effect, the environ in question should be considered nonlocal, so that the scopes concerned are the same. Also, the meaning of the following particular-program should be well defined: BEGIN on logical file end(stand in, (REF FILE f)BOOL: GOTO lfe); DO STRING s; read((s, newline)); print((s, newline)) OD; lfe: print( "1**eof***") END