Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!caip!clyde!cbatt!cbosgd!ihnp4!alberta!ubc-vision!ubc-cs!ludemann From: ludemann@ubc-cs.UUCP (Peter Ludemann) Newsgroups: net.lang Subject: Re: nested procedures. Message-ID: <337@ubc-cs.UUCP> Date: Wed, 30-Jul-86 12:46:13 EDT Article-I.D.: ubc-cs.337 Posted: Wed Jul 30 12:46:13 1986 Date-Received: Fri, 1-Aug-86 03:20:37 EDT References: <335@graffiti.UUCP> <149@opus.UUCP> <7026@boring.mcvax.UUCP> Reply-To: ludemann@ubc-cs.UUCP (Peter Ludemann) Organization: UBC Department of Computer Science, Vancouver, B.C., Canada Lines: 86 Summary: Nested procedures bad: they encourage side-effects In article <7026@boring.mcvax.UUCP> steven@mcvax.uucp (Steven Pemberton) writes: > >Let me try and give a simplified description of a case where nested >procedures are useful, i.e. functional, not just cosmetic. > > ... > >One possibility is to supply a routine in the values module that steps >through each element of a supplied sequence, calling a supplied routine. >In Pascal: > > procedure forEach(seq: value; procedure action(elem: value)); > begin > { For each element e of sequence seq, call action(e) } > end; > >Now you can code the procedure to effect the write command as follows: > > procedure doWrite(v: value); > var first: boolean; > > procedure writeElement(element: value); > begin > if not first then write('; '); > first:=false; > doWrite(element) > end; > > begin > if simple(v) then writeSimple(v) > else > begin > first:=true; > write('{'); > forEach(v, writeElement); > write('}') > end > end; This is a good example of why nested procedures should NOT exist. The procedure writeElement has a side-effect: modifying the variable "first". Because this example is small, it is easily comprehended, but a larger example could be quite incomprehensible. I've written lots of these kinds of systems using a language with no nested procedures. There is a straightforward way of handling such cases: pass the control information explicitely to the "action" procedure. This requires an extra initialisation procedure: procedure forEach(seq: value; procedure actionInit(var control: bool); procedure action(var control: bool; elem: value)); begin var control: bool; actionInit(control); { For each element e of sequence seq, call action(control, e) } end; procedure writeInit(var first: bool); begin first := true; end; procedure writeElement(var first: bool; element: value); begin if not first then write('; '); first := false; doWrite(element) end procedure doWrite(v: value); begin if simple(v) then writeSimple(v) else begin write('{'); forEach(v, writeInit, writeElement); write('}') end end; Of course, this requires knowing the type of the "control" variable (it could be a fairly large record, containing perhaps a character count, an indentation level, or whatever). I have ideas on hiding this information, if anyone is interested.