Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!mcvax!steven From: steven@mcvax.uucp (Steven Pemberton) Newsgroups: net.lang Subject: Re: nested procedures. Message-ID: <7026@boring.mcvax.UUCP> Date: Mon, 28-Jul-86 08:37:43 EDT Article-I.D.: boring.7026 Posted: Mon Jul 28 08:37:43 1986 Date-Received: Mon, 28-Jul-86 21:42:31 EDT References: <335@graffiti.UUCP> <149@opus.UUCP> Reply-To: steven@mcvax.uucp (Steven Pemberton) Organization: Centrum voor Wiskunde en Informatica, Amsterdam Lines: 88 Summary: Nested procedures offer more than just data-hiding. Apparently-To: rnews@mcvax (A long time ago,) in article <149@opus.UUCP> rcd@opus.UUCP (Dick Dunn) wrote: > The worst of it is that <> IF a > language provides other hiding mechanisms. Simple as it is, C's rule for > limiting the scope of static objects to a compilation unit is entirely > adequate for this sort of hiding. Let me try and give a simplified description of a case where nested procedures are useful, i.e. functional, not just cosmetic. You are implementing an interpreter for a programming language. Among the simple types in this language are unbounded length integers. Among the compound types are sequences of any other type: so you can have sequences of integers, but also sequences of sequences of integers, and so on. Sequences are written e.g. {1; 2; 100000}, and there is a shorthand for ranges: {1..100000}. The implementation should be able to handle ranges where the lowerbound is very far from the upperbound (eg {1..10**1000}). Among the simple commands of the language is a write command that can write values of any type. Among the compound commands is a for-loop FOR name IN sequence : commands which executes 'commands' for each element of the sequence, e.g. FOR i IN {1..1000000}: WRITE i**2 Now you want to implement this language in a good modular fashion: you want to write a separate module to implement the values of the language, so that the interpreter proper can be written without reference to how the values are implemented. This will then allow you to try different representations for values, without constantly having to rewrite the interpreter. Now, how do you arrange it so that the interpreter can step through each element of a sequence without knowing how they are represented? In particular, suppose you decide to hold ranges internally as only the lower-bound and upper-bound? 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; Similarly, you can implement the for command as follows: procedure executeFor(name, expression, commands: parseTree); var loc: location; val: value; procedure loop(element: value); begin assign(element, {to:} loc); execute(commands) end; begin loc:=locate(name); val:=evaluate(expression); forEach(val, loop) end; Nested procedures give you the option to choose this method of implementation. Steven Pemberton, CWI, Amsterdam; steven@mcvax.uucp (Sorry I took so long to follow up. I was thinking about it.)