[comp.lang.modula2] The WITH statement

ODX@PSUVM.BITNET (Tim Larson) (11/18/89)

(*
   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.
*)

jbaker@gmu90x.gmu.edu (jbaker) (11/20/89)

In article <89321.154018ODX@PSUVM.BITNET> ODX@PSUVM.BITNET (Tim Larson) writes:
.   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

I always thought of a WITH statement differently.  It computes the location
of the record just once, freezes it, and uses that record throughout the
WITH statement.  Thus, not only does it reduce source code size, it also
increases program efficiency.

.   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.

A warning might be a good idea - but remember, it may happen frequently that
correct code would recieve a warning.  No, forget the warning.  When
looking at a WITH statement, you should always go to the WITH to find out
which record is being referred to - and remember that any computations
were made when the WITH was entered.

John Baker
Fairfax, Virginia

ODX@PSUVM.BITNET (Tim Larson) (11/20/89)

In article <2353@gmu90x.gmu.edu>, jbaker@gmu90x.gmu.edu (jbaker) says:
>
>I always thought of a WITH statement differently.  It computes the location
>of the record just once, freezes it, and uses that record throughout the
>WITH statement.  Thus, not only does it reduce source code size, it also
>increases program efficiency.
>
This is a good point, it *should* increase efficiency, but it also may not!
A good compiler optimizes code for the programmer, but WITH broke the
optimizer in mine (JPI) and I don't believe it's the compiler's fault.  To
maintain correctness, it had to do the computation for the WITH statement,
then use that computation to reference the record.  When I wrote the same
code and removed the WITH, the code size and execution time was reduced!
The reason is that the compiler was then freed to optimize the record ref.
to registers and reduce the code size.  (Of course, this type of optimization
is specific to PCs.)  The upshot is, the optimization forced on the
programmer by remembering the subtleties of the WITH statement is overshadowed
by the potential of a good optimizing compiler, and the potential cost is
correctness!

It's interesting to note that JPI's manual, when mentioning WITH, mildly
discourages its use.

-Tim Larson
odx@psuvm.bitnet

R_Tim_Coslet@cup.portal.com (11/24/89)

>In Article: <89321.154018ODX@PSUVM.BITNET>
>	ODX@PSUVM.BITNET (Tim Larson) Wrote...
>
>      WITH A[i] DO REPEAT WrInt(f, -1); INC (i) UNTIL i > 3 END;
>
>   (see the program [deleted] following this message) which I intended to mean
:
>
>      REPEAT WrInt(A[i].f, -1); INC (i) UNTIL i > 3;
>
I think the code you REALLY wanted was...

	REPEAT WITH A[i] DO WrInt(f, -1); INC (i) END UNTIL i > 3;

>   I believe that the WITH statement as defined in Modula-2 is a bad idea.
I believe that if you use it right, there are no statements in Modula-2 that
are a "bad idea"!

It is the responsibility of the programmer to understand the tools (i.e.
statements) provided to him by the language (i.e. Modula-2) or environment
(i.e. Operating System) that he is working with. As I see it, if he then
uses those tools wrong and the program breaks... it is as much his problem
as it would be the problem of a carpenter that chooses to use screwdrivers
as chisels and the wood he is working on breaks.
In both cases I would consider the user (programmer or carpenter) of the
tool (WITH statement or screwdriver) not the supplier of the tool to be
the cause of the problem (because he "misused" the tools).

                                        R. Tim Coslet

Usenet: R_Tim_Coslet@cup.portal.com
BIX:    r.tim_coslet

ODX@PSUVM.BITNET (Tim Larson) (11/27/89)

In article <24410@cup.portal.com>, R_Tim_Coslet@cup.portal.com says:
>I believe that if you use it right, there are no statements in Modula-2 that
>are a "bad idea"!
>
>It is the responsibility of the programmer to understand the tools (i.e.
>statements) provided to him by the language (i.e. Modula-2) or environment
[...]
>In both cases I would consider the user (programmer or carpenter) of the
>tool (WITH statement or screwdriver) not the supplier of the tool to be
>the cause of the problem (because he "misused" the tools).

I agree with you that a programmer, like any craftsman, must know his tools
intimately, and use them properly.  However, any tool can be improved; after
all, Modula-2 is an improvement upon older tools, such as Pascal.  Who better
than the craftsmen to suggest improvements?  Who better than the designer to
implement the improvement?  Stone axes were once state-of-the-art, till
someone challenged the prevailing wisdom.

-Tim Larson
odx@psuvm.bitnet