nagler%olsen@unizh.UUCP (Robert Nagler) (03/26/88)
I just browsed through at a copy of "Modula-2: A Software Development Approach" by Ford and Weiner. In glancing at a random few pages, the formatting looks quite good and it seems to cover most of the features available in Modula-2. The descriptions are clear (at least the few I have read). One problem I noticed early on in the book is that the coding style is horrible and in contradiction with some of the principles put forth by the text. For example, here is a piece of code from page 353 in the chapter on "Object-Oriented Software Design": Program 17.3 Lowercase Procedure PROCEDURE lowercase ( character : CHAR (* in *) ) : CHAR; BEGIN IF ( 'A' <= character ) AND ( character <= 'Z' ) THEN RETURN CHAR( ORD( character ) + 32 ) ELSE RETURN character END END lowercase; Considering that this is in the object-oriented section, one would think that the examples would reflect good object-oriented programming style. The CHAR type in Modula-2 is an object and should be treated as such. Using the value 32 is clearly a breach of object-oriented rules and a more appropriate form of the line is: THEN RETURN CHR( ORD( character ) - ORD( 'a' ) + ORD( 'A' ) ) There are two changes. First, ORD( 'a' ) - ORD( 'A' ) is used instead of 32. Second, CHR is used instead of the type coercion CHAR. There is a subtle but critical difference between the two. When I compiled the example with CHAR, I got the following semantic error: "foo.mod", line 6: type coercions require objects of same size Skipping back to page 341 in the same chapter, there is a spelling editor/checker implementation which contains some of the worst code in the book. The program is also the primary (and largest) example. Excerpts from Program 17.1: Modular Design Listing for the Editor-Spelling Checker System FOR i := 0 TO 79 DO ... IF (currentpos = 78) OR (ch = CHR(13)) (* CHR(13) is RETURN *) ... IF (ch = CHR(27)) (* CHR(27) is ESC *) OR (linenumber > 300) ... ch := ReadKey(setofchar{'p',s','P','S'}); on := (ch = 'p') OR (ch = 'P'); ... FOR i := 0 TO 79 DO Comments like: (* CHR(13) is RETURN *) can be replaced with using a module called ASCII (supplied with many implementations) or just declaring (in fewer keystrokes if that matters): asciiCR = 15C; This is a small sample. There was is one constant declared in several pages of code, as follows: CONST statusvector = 13; The name "statusvector" in an editor/spelling checker made no sense to me, but what I found was that the statusvector is for some hardware specific code at the bottom which is: IntHdlrInit(status, statusvector (* soft key interrupt *) 15(* higher priority than keyboard so the keyboard cannot interrupt the status report*), 1000 (* stack size fro process *), StatusLine (* procedure attached to interrupt *) ); After reading through the text, you find out that this is a prototype and not a "real" implementation so that "we can test the design priniciples". There are so many examples of beginning programmer mistakes: lengthy procedures, not declaring constants, poor variable naming, etc. The word "prototype" seems to be an excuse to use a poor programming style. Teaching programmers how to write low quality code is like teaching a kid how to get dirty. If they would have left the whole example out, it would have been a big plus. The book is designed for the undergraduate programmer and as such should contain exemplary style. The hacks in this book only lead to the use of hacks by students. The book might be good in principle, but its implementation needs a lot of work. Rob Nagler olsen!nagler@uunet.uu.net
schaub@sugar.UUCP (Markus Schaub) (03/31/88)
Robert Nagler writes: I fully agree to your comments on the given fragments. There is just one thing I'd like to add. > of 32. Second, CHR is used instead of the type coercion CHAR. There > is a subtle but critical difference between the two. When I compiled If you check with Wirth's latest compiler (well I'm away from ETH for a year now, I hope it's still true) you'll see that type coercions have changed. Coercions now use VAL(CHAR,card) and VAL has to be imported from SYSTEM. The reason: All machine dependent things should be imported from SYSTEM to make porting possible. If your program uses CARDINAL(address) this might cause problems on an other computer etc. and they are hard to find. M2Amiga didn't follow this trend completely. We agree more with a draft of the BSI standard that replaces CHR/ORD etc by CHAR/INTEGER/CARDINAL and defines these as 'thinking' type conversions. If you want the old coercion in M2Amiga you have to use CAST(type,val). Heb e schoene, uff e anders Mool -- // Markus Schaub | The Modula-2 People: // M2Amiga Developer | Interface Technologies Corp. \\ // uunet!nuchat!sugar!schaub | 3336 Richmond Ave. Suite 323 \X/ (713) 523-8422 | Houston, TX 77098