Article View: comp.lang.modula2
Article #400The WITH statement
From: Tim Larson
Date: Fri, 17 Nov 1989 20:40
Date: Fri, 17 Nov 1989 20:40
86 lines
3179 bytes
3179 bytes
(*
Good grief! I was away from my debugger yesterday and I stared at a
piece of code for almost an hour before I discovered the culprit - a
WITH statement! I don't believe I have ever used the statement in the
offensive way I wrote it, but, on the other hand, I never knew I
couldn't until now. The code in question is too large to post here,
but it was essentially equivalent to:
WITH A[i] DO REPEAT WrInt(f, -1); INC (i) UNTIL i > 3 END;
(see the program following this message) which I intended to mean:
REPEAT WrInt(A[i].f, -1); INC (i) UNTIL i > 3;
I believe that the WITH statement as defined in Modula-2 is a bad idea.
Informally, we often think of the WITH statement as a way of reducing
the size of the source code, and that we may simply replace the field
names within the WITH block by the name in the WITH designator. This
is simply not true. What is really happening is that the designator is
bound once when the WITH statement is encountered and the field names
are then treated as fields of this static object.
In the test code given below, the mistake is quite obvious. This is
not always the case, however, and it IS the responsibility of the
language designer to provide semantics that correspond in an obvious
way with the syntax. The WITH designator is not required to be a static
object and yet it is treated as if it were static. This is a mistake!
In any case, since Modula-2 is a good language in so many respects, and
assuming that the semantics will not now be changed, the compiler should
be made to produce a warning at the least, or perhaps even an error
message if the designator's value changes in the body of a WITH block.
There is a test program below that illustrates the comments above. Any
comments about this?
*)
MODULE TestWITH;
FROM IO IMPORT WrInt, WrLn;
TYPE
R = RECORD f: INTEGER END;
VAR
A: ARRAY [0..3] OF R;
p: POINTER TO R;
i: INTEGER;
BEGIN (* Note that the desired output is 1234. *)
A[0].f := 0; A[1].f := 1; A[2].f := 2; A[3].f := 3;
(* The following two blocks are essentially equivalent in the way they
execute. *)
i := 0;
WITH A[i] DO REPEAT
WrInt (f, -1);
INC (i)
UNTIL i > 3 END;
WrLn;
i := 0;
p := ADR(A[i]);
REPEAT
WrInt (p:.f, -1);
INC (i)
UNTIL i > 3;
WrLn;
(* The informal way of thinking of WITH leads one to believe that the first
block is equivalent to the following block (which represents the code
that was intended). *)
i := 0;
REPEAT
WrInt (A[i].f, -1);
INC (i)
UNTIL i > 3;
WrLn;
END TestWITH.
(*
-Tim Larson
odx@psuvm.bitnet
Naturally, these opinions, for what they are worth, are just mine.
*)
Technical Details
Message-ID:
<89321.154018ODX@PSUVM.BITNET>Path:
arc1-ca.pugleaf.net!utzoo!attcan!uunet!aplcen!samsung!brutus.cs.uiuc.edu!psuvax1!psuvm!odxShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!aplcen!samsung!brutus.cs.uiuc.edu!psuvax1!psuvm!odx From: ODX@PSUVM.BITNET (Tim Larson) Newsgroups: comp.lang.modula2 Subject: The WITH statement Message-ID: <89321.154018ODX@PSUVM.BITNET> Date: 17 Nov 89 20:40:18 GMT Organization: Penn State University Lines: 86