[comp.sys.amiga.tech] Can you nest subroutines in C?

wade@pnet01.cts.com (Wade Bickel) (06/26/89)

----------------------------------------------------------------------------
-- This is a programming question.  If your not interested please skip    --
--                          this posting.                                 --
----------------------------------------------------------------------------

    Recently I switched from Benchmark Modula-2 to Lattice C.  While
writing a piece of code I discovered, much to my dismay, that I could
not express nested subroutines without choking the compiler.  Perhaps
someone can enlighten me as to how to do this.

Here is a pseudo-code example, in Modula-2.  It is used to create a circular
linked list of graphics level View/ViewPort/RasInfo/BitMap/Planes structures,
which I use for Multi-Buffering the screen.  Note that "#" = "!=". :^).

    MODULE NestedSubRtnExample;

    CONST NumBuffers = 3;

    TYPE
        ScreenBuffer = RECORD
                         V  : View;     (* \
                         VP : ViewPort; (*  \  These are just inited and
                         RI : RasInfo;  (*  /    tied together.  Copper lists
                         BM : BitMap;   (* /     must also be allocated.
                         scr: ADDRESS;  (* <-- of chip mem to be allocated *)
                       END;

    VAR MB  : ARRAY[0..NumBuffers-1] OF ScreenBuffer;

   (*-----------------------------------------------------------------------
    *  InitMB(n,h,w,d):   n = number of buffers to allocate.
    *                     h,w,d = dimentions of screen buffers.
    *-----------------------------------------------------------------------*)
    PROCEDURE InitMB(n,h,w,d : CARDINAL): BOOLEAN; 
                  (* ^^^^^^^------------------------USHORTs passed by value *)
      VAR
            ...  vars declared here as local to InitMB() would be visable
            ...    InitScreenBuffer() below.

      PROCEDURE InitScreenBuffer(N: CARDINAL): BOOLEAN;
      
        BEGIN
          ...initialize graphics structures in array MB[N], allocate planes[]
          ...  chip memory. Cleaup and return NIL pointer on alloc failure.
          ...  NOTE: uses h,w, and d in initaizations
          IF (N # 0) THEN
            MB[N].Next := InitScreenBuffer(N-1);
            IF (MB[N].Next = NIL) THEN
              ...cleanup this buffers memory allocs.
              RETURN(NIL);
            END;
          END;
          RETURN(ADR(MB[N]));
        END;

      BEGIN (* InitMB body starts here *)
        IF n = 0 THEN RETURN(FALSE);
        p = InitScreenBuffer(n-1);
        IF p = NIL THEN RETURN(FALSE);
        MB[0].Next = ADR(MB[n-1]);
        RETURN(TRUE);          
      END;


    BEGIN (* MAIN BODY OF PROGRAM *)

      IF NOT(InitMB(NumBuffers,320,200,3)) THEN RETURN(FALSE);
      ...go on with the rest of program.

    END.


    The nested subroutine InitScreenBuffer() is nested inside of InitMB().
The advantage to doing this is that it avoids either the declaration of
w,h, and d (width,height and depth respectively) as globals or passing them
as parameters to InitScreenBuffer() in which case they would appear three
times on the stack (18 bytes vs 6).

    In more complex algorithms involving trees of data I have found the use
of these psuedo globals very handy.   Also, anytime a segment of code needs
a large space of temporary data which will be visable to several routines, 
nesting is an easy, memory efficient method of allocating it.  I often bottle
up my entire program in this manner to avoid declaration of any global
variables at all.  While I have not written any, it seems this should be an
easy way to create reentrant code.
    

    I hope there is a way to create nested functions in C.  In general I find
I like C.  Especially the flexability of conditionals afforded in pointer
manipulations, which is much more powerful than that allowed in Modula-2.


                                                    Thanks,


                                                            Wade.



UUCP: {nosc ucsd hplabs!hp-sdd}!crash!pnet01!wade
ARPA: crash!pnet01!wade@nosc.mil
INET: wade@pnet01.cts.com

shadow@pawl.rpi.edu (Deven T. Corzine) (06/27/89)

In article <4470@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:

>    Recently I switched from Benchmark Modula-2 to Lattice C.  While
>writing a piece of code I discovered, much to my dismay, that I could
>not express nested subroutines without choking the compiler.  Perhaps
>someone can enlighten me as to how to do this.

Sorry, you lose.  This is the one thing which keeps C from being a
strictly block-structured language -- function definitions can not
contain other function definitions.  Yet there are workarounds.

>    The nested subroutine InitScreenBuffer() is nested inside of
>InitMB().  The advantage to doing this is that it avoids either the
>declaration of w,h, and d (width,height and depth respectively) as
>globals or passing them as parameters to InitScreenBuffer() in which
>case they would appear three times on the stack (18 bytes vs 6).

One midpoint approach is to put the data values in a structure, and
pass a pointer to the structure.  This still involves passing an extra
parameter, but avoids duplicating the data unnecessarily.  Another
approach is to make a function with its "nested" functions a separate
module, with variables global to the module, but not defined external
to the module.  I can't remember offhand how to declare such; maybe
"static int x" outside of function defintions would do it.  (need to
override the otherwise assumed extern)  Anyone have K&R's book handy?
(Note that this method is NOT reentrant, but passing pointers (held in
local variables) to dynamically allocated memory IS reentrant.)

>    In more complex algorithms involving trees of data I have found
>the use of these psuedo globals very handy.  Also, anytime a segment
>of code needs a large space of temporary data which will be visable
>to several routines, nesting is an easy, memory efficient method of
>allocating it.  I often bottle up my entire program in this manner to
>avoid declaration of any global variables at all.  While I have not
>written any, it seems this should be an easy way to create reentrant
>code.

Although slightly more work, using AllocMem (or malloc) and passing
arounds pointers (to a structure if many discrete variables, like a
bunch of integers -- or maybe an array if appropriate) is equally
memory-efficient, and reentrant.

>    I hope there is a way to create nested functions in C.  In
>general I find I like C.  Especially the flexability of conditionals
>afforded in pointer manipulations, which is much more powerful than
>that allowed in Modula-2.

Yes, C is a powerful and flexible language, even if somewhat terse.
(I know that *I* like it!)

Deven
--
shadow@[128.113.10.2]   <shadow@pawl.rpi.edu> Deven T. Corzine (518) 272-5847
shadow@[128.113.10.201] <shadow@acm.rpi.edu>  2346 15th St.    Pi-Rho America
deven@rpitsmts.bitnet   <userfxb6@rpitsmts>   Troy, NY 12180-2306  <<tionen>>
"Simple things should be simple and complex things should be possible." - A.K.

sjorr@rose.waterloo.edu (Stephen Orr) (06/27/89)

In article <4470@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
>    I hope there is a way to create nested functions in C.  In general I find
>I like C.  Especially the flexability of conditionals afforded in pointer
>manipulations, which is much more powerful than that allowed in Modula-2.

	Unless someone changed the definition of C that I learnt, all 
modules in 'C' have the same visibility even main(). This does not mean you
can't get your peice of code running, it just means that the sub-module you
would place with a larger module will be visible to all modules in the program.

	If you need to declare a function (parameters etc) you can use a 'C'
prototype which is similar to pascal's forward (I don't know Modula but I
gather it has some similarities to pascal...no flames, this is just a general
blanket statement!)

	Sorry if you miss the ability to nest functions like this, it is a
more structured approach to code, but it really doesn't effect functionality.

				- sjorr

daveh@cbmvax.UUCP (Dave Haynie) (06/28/89)

in article <4470@crash.cts.com>, wade@pnet01.cts.com (Wade Bickel) says:

>     Recently I switched from Benchmark Modula-2 to Lattice C.  While
> writing a piece of code I discovered, much to my dismay, that I could
> not express nested subroutines without choking the compiler.  Perhaps
> someone can enlighten me as to how to do this.

Why did you switch?  Something Lattice C does that cannot be performed in
Modula-2, code efficiency or just for fun?  

C doesn't support nested subroutines, unlike M2 or Pascal.  You can get 
the effect of "local-global" variables, and probably the speed as well,
by building a structure that gets passed to every function in the logical
group and using registerized parameters in Lattice V5.02.  C++ give you 
this effect even more so, though if you're at all used to the speed of
Benchmark compiles, you'll probably choke on how long it'll take to go
through a Lattice C++ compilation (still, I like the language).  Also, 
there's no source level debugger for Lattice C++ yet, while I just got a
look at the new Source Level Debugger for Benchmark M2, and I like it
better overall than Manx's SDB or Lattice's CodePRobe.  TINAR, of course...

> UUCP: {nosc ucsd hplabs!hp-sdd}!crash!pnet01!wade
> ARPA: crash!pnet01!wade@nosc.mil
> INET: wade@pnet01.cts.com
-- 
Dave Haynie Commodore-Amiga (Systems Engineering) "The Crew That Never Rests"
   {uunet|pyramid|rutgers}!cbmvax!daveh      PLINK: D-DAVE H     BIX: hazy
           Be careful what you wish for -- you just might get it

FelineGrace@cup.portal.com (Dana B Bourgeois) (06/28/89)

AWRIGHT!!!  Found one I can field....

C doesn't allow nested functions.  All functions are on one 'level'.
But to avoid large amounts of argument passing there are several
techniques like putting all the arguments into a structure and passing
a pointer to it, or making global variables to hold the values before 
you call the next function.  Depends on how structured you want to make
your code.  There are techniques that allow you to have limited globals.
Sorta like having variables in an outer procedure known in an inner one.
C will allow you to create a variable that is known only by the few
functions that you want to know of it and the rest of the functions
remain ignorant of the variable's existance.(hence my term 'limited
globals')

The C gurus have technical terms for all this stuff but if you haven't
been exposed to 'scope' and 'seperate compilation' and 'static external'
then the above explanation will probably make more sense.  My beginning
C course was based around a book called "C by dissection" - A.Kelly &
I. Pohl.  Lots of examples and good explanation.  Stays away from the
more exotic stuff like bit-operators and pointer pointers.  Might be a
good book for you because they go over the storage classes.

Good luck.

Dana

kevin@cbmvax.UUCP (Kevin Klop) (06/28/89)

In article <14753@watdragon.waterloo.edu> sjorr@rose.waterloo.edu (Stephen Orr) writes:
>	Unless someone changed the definition of C that I learnt, all 
>modules in 'C' have the same visibility even main(). This does not mean you
>can't get your peice of code running, it just means that the sub-module you
>would place with a larger module will be visible to all modules in the program.
>


Actually, if you're willing to break things up into separate compilation units
(i.e. files), nested subroutines can be emulated (to alevel of 1 deep.

File : NestedRtns.c

static int FunctionInvisibleOutsideThisFile()
.
.
.

Note that the static keyword in most cases prevents any function outside the
current file from seeing the static function.

                  -- Kevin --

Kevin Klop		{uunet|rutgers|amiga}!cbmvax!kevin
Commodore-Amiga, Inc.

The number, 111-111-1111 has been changed.  The new number is:
134-253-2452-243556-678893-3567875645434-4456789432576-385972

Disclaimer: _I_ don't know what I said, much less my employer.

mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) (06/28/89)

In article <4470@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
<The advantage to doing this is that it avoids either the declaration of
<w,h, and d (width,height and depth respectively) as globals or passing them
<as parameters to InitScreenBuffer() in which case they would appear three
<times on the stack (18 bytes vs 6).

Since nobody else has mentioned it (yet), I will.

You can fake this kind of thing by putting the all the "nested"
routines in one file, and making the "pseudo-globals" statics in that
file. Of course, you can only deal with one level of nesting this way,
and you have to play games with include files and extern to make the
true globals work out, but it can be done.

As for the whole topic, I have to agree with a quote attributed to one
of the designers of Ada: "If you've got data abstraction, nesting is
for the birds."

	<mike
--
When all our dreams lay deformed and dead		Mike Meyer
We'll be two radioactive dancers			mwm@berkeley.edu
Spinning in different directions			ucbvax!mwm
And my love for you will be reduced to powder		mwm@ucbjade.BITNET

wade@pnet01.cts.com (Wade Bickel) (06/28/89)

shadow@pawl.rpi.edu (Deven T. Corzine) writes:
>One midpoint approach is to put the data values in a structure, and
>pass a pointer to the structure.  This still involves passing an extra
>parameter, but avoids duplicating the data unnecessarily.  Another

        I've considered this, but it will make what was an easy, maintainable
codeing trick into a mess.

>approach is to make a function with its "nested" functions a separate
>module, with variables global to the module, but not defined external
>to the module.  I can't remember offhand how to declare such; maybe
>"static int x" outside of function defintions would do it.  (need to
>override the otherwise assumed extern)  Anyone have K&R's book handy?
>(Note that this method is NOT reentrant, but passing pointers (held in
>local variables) to dynamically allocated memory IS reentrant.)

        Use of "static" vars in a seperate modules has been suggested by
many via E-Mail.  This solution breaks down under recursion.

>
>Although slightly more work, using AllocMem (or malloc) and passing
>arounds pointers (to a structure if many discrete variables, like a
>bunch of integers -- or maybe an array if appropriate) is equally
>memory-efficient, and reentrant.

        This seems to me a quick way to make your code un-maintainable.
Following recursive code is hard enough without crowding it with unneeded
structures and Alloc() calls.  Also, since the Alloc() may fail, it leads
to bigger code as well.

>
>Yes, C is a powerful and flexible language, even if somewhat terse.
>(I know that *I* like it!)

        So I thought as well.  I too really like the tersness of C.  However
I have now found something of major significants which I can do in M2 but not
in C.  Nested subroutines prevent spagetti code, which is very common in C.
I used to wonder as I would translate C to M2 why globals were so heavily
used, often wondering if this was a sign that the programmer was of
questionable talent, leading me to re-organize/re-write the code.  Now I see
why this is done.  Very UGLY :^<

        So far I have found nothing I could do in C that I could not do in
M2.  To me this is the test of a Language.


                                         Thanks to all who sent me mail,


                                                                Wade.
>
>Deven

UUCP: {nosc ucsd hplabs!hp-sdd}!crash!pnet01!wade
ARPA: crash!pnet01!wade@nosc.mil
INET: wade@pnet01.cts.com

panzer@grape.ucsb.edu (Panzer, John Robert) (06/29/89)

In article <14753@watdragon.waterloo.edu> sjorr@rose.waterloo.edu (Stephen Orr) writes:
>In article <4470@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
>>    I hope there is a way to create nested functions in C.  In general I find
>>I like C.  Especially the flexability of conditionals afforded in pointer
>>manipulations, which is much more powerful than that allowed in Modula-2.
>
>	Unless someone changed the definition of C that I learnt, all 
>modules in 'C' have the same visibility even main(). This does not mean you
>can't get your peice of code running, it just means that the sub-module you
>would place with a larger module will be visible to all modules in the program.

In fact, if you declare a function (or a variable external to a function)
to be static, it will be local to the source file but global to all functions
within that file.  This provides some degree of modularity, although
it does require that each module be in a separate source file.
 
==========================================================================
| John Panzer           |   UC Santa Barbara                             |
| panzer@cornu.ucsb.edu |               Department of Computer Violence  |
==========================================================================

papa@pollux.usc.edu (Marco Papa) (06/29/89)

In article <4495@crash.cts.com> wade@pnet01.cts.com (Wade Bickel)
writes: 
> So far I have found nothing I could do in C that I could not
>do in M2.  To me this is the test of a Language.

Not really a test of a language at all. Can you have "procedure pointers"
in M2 (i.e., variables that hold addresses of subroutines, and that get called
just by referencing the variable, and that of course can be assigned to)?
As I recall Pascal did not allow that.  This is one of the features of C that 
currently I could not live without.

-- Marco Papa 'Doc'
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
uucp:...!pollux!papa       BIX:papa       ARPAnet:pollux!papa@oberon.usc.edu
"There's Alpha, Beta, Gamma, Diga and Caligari!" -- Rick Unland
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

dsking@pyr.gatech.EDU ( David King) (06/29/89)

In article <18161@usc.edu> papa@pollux.usc.edu (Marco Papa) writes:
>Not really a test of a language at all. Can you have "procedure pointers"
>in M2 (i.e., variables that hold addresses of subroutines, and that get called
>just by referencing the variable, and that of course can be assigned to)?
>As I recall Pascal did not allow that.  This is one of the features of C that 
>currently I could not live without.

	Pascal did not allow procedure variables since it made the compiler
more difficult which Wirth didn't want (of course everyone in my undergrad
compilers course implemented procedure variables with no help).  Modula-2
does allow using procedure variables in the same manner as C.  I definately
could not live with out them as I use them in my IDCMP routines to implement
pseudo-object-oriented design.  

	My only complaint with Modula-2 is that there is no pre-initializing
of data.  But the cleaner initialization and termination system sort of 
makes up for it.  Since each is useful for different things I have both Lattice
and M2Sprint, but I'm weird.

	No religious wars or I'll start arguing for an OCCAM compiler :-)
		-David

>
>-- Marco Papa 'Doc'
>-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
>uucp:...!pollux!papa       BIX:papa       ARPAnet:pollux!papa@oberon.usc.edu
>"There's Alpha, Beta, Gamma, Diga and Caligari!" -- Rick Unland
>-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


-- 
 David King - 	FROM Disclaimers IMPORT Standard;
Georgia Insitute of Technology, Atlanta Georgia, 30332
uucp: ...!{akgua,allegra,amd,hplabs,ihnp4,seismo,ut-ngp}!gatech!gitpyr!dsking
ARPA: dsking@pyr.gatech.edu

mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) (06/29/89)

In article <4495@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
<        So far I have found nothing I could do in C that I could not do in
<M2.  To me this is the test of a Language.

You're not looking very hard. Please translate the following C
construct into M2:

	short main[] = {1, 2, 3} ;

On hardware that supports it, this sets up three words, puts the
values 1, 2 and 3 into them, and arranges to branch to that location
under the right conditions. Likewise, can you write M2 code that
_will_ generate an address exception? Both of these features were used
in the Unix kernel at one point in the past. 

Of course, if you don't need to do these kinds of things, then you
don't care about them. So C may not be the language of choice for the
problem at hand. And that's my test of a Language - how do the idioms
of the problem I'm solving map to it.

Finally, from elsewhere:

>> In fact, if you declare a function (or a variable external to a function)
>> to be static, it will be local to the source file but global to all functions
>> within that file. 

Not quite. C (like many other languages) reqiures forward
declarations.  Functions and variables are only visible to code that
occurs after their decleration in the file. And an external variable
declared in a function only has function scope in ANSI C. In pre-ANSI
C, the scope wasn't explicitly defined, and PCC based compilers gave
it file scope.

	<mike
--
Teddies good friend has his two o'clock feast		Mike Meyer
And he's making Teddies ex girl friend come		mwm@berkeley.edu
They mistook Teddies good trust				ucbvax!mwm
Just for proof that Teddy was dumb.			mwm@ucbjade.BITNET

wade@pnet01.cts.com (Wade Bickel) (06/29/89)

daveh@cbmvax.UUCP (Dave Haynie) writes:
>in article <4470@crash.cts.com>, wade@pnet01.cts.com (Wade Bickel) says:
>
>>     Recently I switched from Benchmark Modula-2 to Lattice C.  While
>
>Why did you switch?  Something Lattice C does that cannot be performed in
>Modula-2, code efficiency or just for fun?  
>

Hi Dave,

        I switched mainly because an associate I'm working with is convinced
C is the "only" language for the Amiga, one of us had to change, and I figured
learning C is not a bad Idea, given the lean towards UNIX.  Also I am very
interested in C++, and since I currently work on a 2500, I can handle the
compile speed.

        So far I find the two languages remarkably similar.  If you were to
mix 40% Modula-2 with 60% C you'd have a language far superior to either one.
I find that C leads to sloppy code, whereas M2 is missing some very
convienient features of C, such as pre-initialization.  However, lack of the
ability to nest routines represents the first concept which I've discovered
which cannot be translated.  C looses!

        I do not understand why C does not support Nested routines.  Perhaps
this will be added to the ANSI standard at some point in the future.  The nice
thing is, backward compatability would not be an issue.  But such things
happen slowly.  So I guess I'll just work around the deficeincy, as this is
not something I must have to work in C.  Perhaps when an optimizing M2
compiler comes out I'll switch back to M2.

>there's no source level debugger for Lattice C++ yet, while I just got a
>look at the new Source Level Debugger for Benchmark M2, and I like it
>better overall than Manx's SDB or Lattice's CodePRobe.  TINAR, of course...
>-- 
>Dave Haynie Commodore-Amiga (Systems Engineering) "The Crew That Never Rests"

        Yes, I was a tester for the Benchmark debbugger.  It is nice, and
except for not having a break on variable option I agree that it seems much
cleaner than CPR, which I use alot.  Such a shame, if I'd had it 3 weeks
earlier I'd probably still be useing Benchmark.


                                                Thanks,


                                                                Wade.


UUCP: {nosc ucsd hplabs!hp-sdd}!crash!pnet01!wade
ARPA: crash!pnet01!wade@nosc.mil
INET: wade@pnet01.cts.com

kevin@cbmvax.UUCP (Kevin Klop) (06/29/89)

In article <25874@agate.BERKELEY.EDU> mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) writes:
>>> In fact, if you declare a function (or a variable external to a function)
>>> to be static, it will be local to the source file but global to all functions
>>> within that file. 
>
>Not quite. C (like many other languages) reqiures forward
>declarations.  Functions and variables are only visible to code that
>occurs after their decleration in the file. And an external variable
>declared in a function only has function scope in ANSI C. In pre-ANSI
>C, the scope wasn't explicitly defined, and PCC based compilers gave
>it file scope.

Excuse me, I beg to differ.  If you do not declare a function before you
use it, then it is of type ``int'' with a globale scope.  Try this sometime:

main()
{
     MyFunction();
}

char MyFunction();

                      -- Kevin --

Kevin Klop		{uunet|rutgers|amiga}!cbmvax!kevin
Commodore-Amiga, Inc.

The number, 111-111-1111 has been changed.  The new number is:
134-253-2452-243556-678893-3567875645434-4456789432576-385972

Disclaimer: _I_ don't know what I said, much less my employer.

kent@swrinde.nde.swri.edu (Kent D. Polk) (06/30/89)

In article <18161@usc.edu> papa@pollux.usc.edu (Marco Papa) writes:
[...]
>Not really a test of a language at all. Can you have "procedure pointers"
>in M2 (i.e., variables that hold addresses of subroutines, and that get called
>just by referencing the variable, and that of course can be assigned to)?
>As I recall Pascal did not allow that.  This is one of the features of C that 
>currently I could not live without.

Some versions of Pascal do allow this. Hewlett Packard Pascal does for
one. It has to use a 'call' mechanism with the variable name as a
parameter. I've used this to make arrays of functions for state
machines. It is also a modular Pascal which looks surprisingly like M2
but not quite so heavily typed.  Not that this does any of us Amigans
any good though. :-(

=======================================================
       Kent Polk - Southwest Research Institute
              kent@swrinde.nde.swri.edu
-------------------------------------------------------
       "Anything worth doing is worth overdoing"
=======================================================

mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) (06/30/89)

In article <7173@cbmvax.UUCP> kevin@cbmvax.UUCP (Kevin Klop) writes:
<In article <25874@agate.BERKELEY.EDU> mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) writes:
<>Not quite. C (like many other languages) reqiures forward
<>declarations.  Functions and variables are only visible to code that
<>occurs after their decleration in the file.
<
<Excuse me, I beg to differ.  If you do not declare a function before you
<use it, then it is of type ``int'' with a globale scope.  Try this sometime:
<
<main()
<{
<     MyFunction();
<}
<
<char MyFunction();

Well, you implicitly declared the function when you used it's name in
a place that required a function invocation. And it's _still_ only
visible to things after that point in the file.

If you used MyFunction in a place where a function type wasn't
required, then you lose the decleration, and get an "undefined
variable" error.

	MyMetaFunciton(MyFunction) ;

This type of implicit decleration is also available for arguments:

main(argc, argv) char **argv;

Will implicitly declare argc as type int.

	<mike

--
When logic and proportion have fallen softly dead,	Mike Meyer
And the white knight is talking backwards,		mwm@berkeley.edu
And the red queen's off her head,			ucbvax!mwm
Remember what the dormouse said.			mwm@ucbjade.BITNET

limonce@pilot.njin.net (Tom Limoncelli) (06/30/89)

In article <4501@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:

>         I do not understand why C does not support Nested routines.  Perhaps
> this will be added to the ANSI standard at some point in the future.  The
> nice thing is, backward compatability would not be an issue.  But such things
> happen slowly.  So I guess I'll just work around the deficeincy, as this is
> not something I must have to work in C.  Perhaps when an optimizing M2
> compiler comes out I'll switch back to M2.

They are not in C because it is difficult to implement them so that
they are speed-efficient.  If you look at the code generated for a
sub-procedure, it usually has to do things through one additional
level of indirection.

I doubt that something like it will be added to ANSI C.  First of all,
the speed-demons will rant and rave, secondly others will claim that
99% of that can be done via separately compiled modules.  Most
importantly, I believe that C++ will dominate the C market by the time
another ANSI C draft is written, and since C++ gives the scoping rules
that you are requesting, it will not be needed.

Personally, I wish there was a way to get some real good control over
scope and visibility (independently of each other) in C.  I think that
C++ will meet my needs.  DEC's Vax/VMS Pascal adds extensions that let
you directly control the scope, visibility, parameter passing method,
and just about everything else I can think of; and each is
independently controlled.  Alas, it's for VMS :-)

The efficiency of all HHLs can be brought to "almost" equal if you
really have a way cool optimizer (and if you are liberal about your
definition of "almost" ;-).  The problem is that a simple C compiler
will generate much faster code than a simple Pascal compiler; hence
the stereotypes of fast-C and slow-Pascal.  With the momentum that C
has, I doubt that many companies will dedicate enough capital to
producing such a good optimizer.  (I hear crowds yelling "so stick
with C so your base is more efficient!")

Of course, you could petition your local XJ11 ANSI member :-)

>         Wade.
> UUCP: {nosc ucsd hplabs!hp-sdd}!crash!pnet01!wade
> ARPA: crash!pnet01!wade@nosc.mil
> INET: wade@pnet01.cts.com
-- 
 Tom Limoncelli -- tlimonce@drunivac.Bitnet -- limonce@pilot.njin.net
       Drew University -- Box 1060, Madison, NJ -- 201-408-5389
   Standard Disclaimer: I am not the mouth-piece of Drew University

jrc@ukc.ac.uk (John) (06/30/89)

In article <4501@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
>.. I do not understand why C does not support Nested routines.  ..

I think it's because you need to maintain a display (or something like that)
to resolve references to variables in enclosing procedures. C has a lean and
mean close to the machine philosophy, which this would run counter to.

It also causes all kinds of horrible problems if you want to have pointers to
functions - if you save a pointer to a nested function in an array, then call
it much later on from another part of your program, what should those external
variable references resolve to? Should a pointer to function in fact be a
structure containing the entire context of the function at the time the
pointer was created? All very un C-like.

There are two issues here - nested funtions and allowing references to
parameters in enclosing functions. BCPL (:-) has nested functions, but not
references to enclosing scopes (a nicer compromise, IMHO)

John Cupitt

doug@xdos.UUCP (Doug Merritt) (06/30/89)

In article <17863@swrinde.nde.swri.edu> kent@swrinde.UUCP (Kent D. Polk) writes:
>Some versions of Pascal do allow this. Hewlett Packard Pascal does for

Oh, please, let's not drag the rotting corpse of nonstandard Pascals
into this. A friend of mine in college (Bob Toxen) added essentially all
of the features of C to his version of Basic (SuperBasic). Wouldn't it
be a little wierd for me to therefore say "gee, anything you can do in
C you can do in Basic. As long as it's *that* version of Basic, of course,
widely unavailable, but you *could*"

Pascal is brain damaged. It's a toy language designed for teaching programming
that ran amok (as even Niklaus Wirth admits). The set of changes that
turn Pascal into a (standard) usable language are known as "Modula 2",
and even then it's got two major problems: you can't statically initialize
data (even assembler allows *that*), and you have to import/export
everything in sight. There are still some people who think that this is
a *feature*, but as a casual perusal of the literature will point out,
the problem is that it's such a bother that, in large projects, people
quickly start importing and exporting all kinds of things that shouldn't
be, because it's too much trouble to locate and edit out archaic imports/
exports, resulting in import/export lists half a page long. Sure, big
help in maintaining programs, ha-ha. It was an experiment in language
design that ended as a failure, not having accomplished what it intended.

This is still a relatively minor inconvenience, though, not something to
make or break a language.

The thing I hate about *C* is that it doesn't have support for variable
length list data, other than strings. This is a major nuisance when
writing e.g. lisp-flavored programs.
	Doug
-- 
Doug Merritt		{pyramid,apple}!xdos!doug
Member, Crusaders for a Better Tomorrow		Professional Wildeyed Visionary

doug@xdos.UUCP (Doug Merritt) (06/30/89)

In article <4501@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
>        I do not understand why C does not support Nested routines.  Perhaps

After going to the trouble to write an article explaining this yesterday,
I find that I neglected to post it. Here it is:

In article <4495@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
>shadow@pawl.rpi.edu (Deven T. Corzine) writes:
>>One midpoint approach is to put the data values in a structure, and
>>pass a pointer to the structure.  This still involves passing an extra
>>parameter, but avoids duplicating the data unnecessarily.  Another
>
>        I've considered this, but it will make what was an easy, maintainable
>codeing trick into a mess.

Not at all. The syntactic sugar of nested function definitions is
sometimes nice, but at other times actually *harder* to follow than
the "pass an extra parameter" approach. (Hmmm, now *which* 'foo' is being
used here?)

In any event, fully block structured languages support nested definitions
via "displays", which amount to the same thing as an extra parameter,
but maintained by the compiler, and integrated with the usual scoping
rules. The major complaint about Displays is that they are relatively
expensive to implement at run time, yet the expense is hidden by the
language.

This can be a blessing if you would've used the "extra parameter" approach
anyway, but it's a curse to the (large) extent that Displays are used
needlessly at times they aren't really needed, leading to noticeable
decrease in speed. And again, they are very frequently misused in terms
of readability.

Given the design goals of C (which I would off the cuff state as "give
high level support to all of the basic low level constructs needed for
systems programming, in a way that is easy to understand the cost, so
that C code can be very easily made efficient by the programmer"), clearly
Displays don't fit in, because they can be very easily emulated (note
that C does not support dynamic data structures like linked lists
directly either), and basically their whole purpose is to hide a construct
whose expense "should" remain exposed.

>Nested subroutines prevent spagetti code, which is very common in C.

False. Programmers create spaghetti code in all languages, and all biases
aside, Modula 2 programs are *in general* no more (nor less) readable than
C. This kind of claim is frequently made about languages, when what is
really at issue is relative familiarity or small differences in convenience.

>        So I thought as well.  I too really like the tersness of C.  However
>I have now found something of major significants which I can do in M2 but not
>in C.

Ada has features that neither C nor Modula 2 have, why not switch? :-)
Seriously, you have to make up your mind what you want. If you want
a very easily optimized systems programming language, C wins. If what
you want is high level support for abstractions in order to make you a more
efficient programmer, why settle for Modula 2?

Both C and Modula 2 are what *I* would call very low end high level
languages. By comparison, Smalltalk, FPL, Scheme, Icon, and even Ada
give much better support for higher level abstractions. Thus the whole
notion of "C versus Modula 2" is a tempest in a teapot...compared with
other languages, they're practically identical!

>I used to wonder as I would translate C to M2 why globals were so heavily
>used, often wondering if this was a sign that the programmer was of
>questionable talent, leading me to re-organize/re-write the code.  Now I see
>why this is done.  Very UGLY :^<

You were 80% right the first time; most programmers (using any language)
have questionable talent and use globals unnecessarily. But note that
the right way *in C* to handle nonrecursively referenced variables used
by several related functions as part of an encapsulation is to put those
variables (as globals) and fuctions in a file of their own, and make
everything static (aside from the external interface). This gives the
exact same underlying semantics that you would get from doing the
equivalent in Modula 2, except that in M2, you don't know whether a
display will be used or not (depends on optimization abilities of the
compiler).

>        So far I have found nothing I could do in C that I could not do in
>M2.  To me this is the test of a Language.

Then you've already lost big time, since by that measure you would be
better off using a really high level language instead of either C or
Modula 2.

By the way, my favorite fix for language deficiencies that *really*
get in the way of a project is to write a tiny language that handles
the issue at hand. This can be as trivial as a utility which, when
it's (statically initialized) data structures are edited, recompiled,
and run, produces the desired C data and functions to be included
with the actual program. (This is so easy to do, and can make such a huge
difference in convenience, that I'd say that it's a real must.)

Or for large projects, it can be as complicated as setting up a small
but full fledged language using yacc & lex (bison & flex), some symbol
table routines, and a few pages of C code. There was a discussion about
the merits of this approach in Programming Pearls (CACM) some years ago.

Digressing a bit further, people commonly create scripts/programs/makefiles
that write makefiles which are then executed. For huge projects, three
level indirection is pretty common: makefiles that create makefiles that
create makefiles which finally create a program. Or at my last job,
C programs that created C programs that created C source that was included
as part of a compiler.

The net effect is to stretch current (low) state of the commercially-available
art software development technology by creating software that expertly
assists you in building more software. Current trends aim toward formalizing
and directly supporting this process, which makes far more difference
than which language you're using in the first place.
	Doug
-- 
Doug Merritt		{pyramid,apple}!xdos!doug
Member, Crusaders for a Better Tomorrow		Professional Wildeyed Visionary

kent@swrinde.nde.swri.edu (Kent D. Polk) (07/01/89)

In article <395@xdos.UUCP> doug@xdos.UUCP (Doug Merritt) writes:
>In article <17863@swrinde.nde.swri.edu> kent@swrinde.UUCP (Kent D. Polk) writes:
>>Some versions of Pascal do allow this. Hewlett Packard Pascal does for
>
>Oh, please, let's not drag the rotting corpse of nonstandard Pascals
>into this.

For those of us who know about HP Pascal, no need to respond. I sent
Mr. Merritt a response via email explaining his mistakes &
misconceptions. Not a one of his derogatory comments applied to HP
Pascal. It also appears that Mr Merritt never learned enough of Pascal
and its capabilities to truly appreciate what it can do and why
nonstandard Pascals exist - but enough.

For those who don't know, HPPascal (9000 series) is not simply a
nonstandard Pascal, but is really different, looking remarkably like M2
with just about all of its good points and almost none of its bad
points - much better than M2 (IMHO). It is more a different language
that happens to be able to compile standard Pascal.  A language that I
wish could be available for the Amiga, but simply a wish. I am willing
to work with those languages which are available.

=======================================================
       Kent Polk - Southwest Research Institute
              kent@swrinde.nde.swri.edu
-------------------------------------------------------
       "Anything worth doing is worth overdoing"
=======================================================

doug@xdos.UUCP (Doug Merritt) (07/01/89)

In article <17894@swrinde.nde.swri.edu> kent@swrinde.UUCP (Kent D. Polk) writes:
>In article <395@xdos.UUCP> doug@xdos.UUCP (Doug Merritt) writes:
>>In article <17863@swrinde.nde.swri.edu> kent@swrinde.UUCP (Kent D. Polk) writes:
>>>Some versions of Pascal do allow this. Hewlett Packard Pascal does for
>>
>>Oh, please, let's not drag the rotting corpse of nonstandard Pascals
>>into this.
>
>For those of us who know about HP Pascal, no need to respond. I sent
>Mr. Merritt a response via email explaining his mistakes &
>misconceptions. Not a one of his derogatory comments applied to HP
>Pascal. It also appears that Mr Merritt never learned enough of Pascal
>and its capabilities to truly appreciate what it can do and why
>nonstandard Pascals exist - but enough.

What a shame that Kent didn't leave it just at email. The problem is
that Kent thought I was flaming his favorite language, HP Pascal,
whereas I was just saying that *standard* Pascal is brain damaged, and
the fact that there are nonstandard Pascal's available to some people
doesn't help the rest of the world who have to use standard Pascal.
(And *obviously* the nonstandard Pascals exist because of what standard
Pascal *can't* do.)

Standard knee jerk reaction from somebody with a favorite language.
Careful readings of my postings will reveal a strong distaste for
*all* of the languages under discussion, so I'm not playing favorites.
I started using both C and Pascal in 1976, for the record.

I don't mind comparing language features in public as long as the
discussion stays neutral, but if you're going to start reacting emotionally,
keep it 100% in email.

>For those who don't know, HPPascal (9000 series) is not simply a
>nonstandard Pascal, but is really different, looking remarkably like M2
>with just about all of its good points and almost none of its bad
>points - much better than M2 (IMHO). It is more a different language
>that happens to be able to compile standard Pascal.  A language that I
>wish could be available for the Amiga, but simply a wish. I am willing
>to work with those languages which are available.

I have no doubt but that it is an admirable language, I just don't see
why anyone without an HP machine would much care. Recall the original
subject, after all!
	Doug
-- 
Doug Merritt		{pyramid,apple}!xdos!doug
Member, Crusaders for a Better Tomorrow		Professional Wildeyed Visionary

new@udel.EDU (Darren New) (07/01/89)

In article <8608@pyr.gatech.EDU> dsking@pyr.UUCP ( David King) writes:
>Modula-2
>does allow using procedure variables in the same manner as C.  
> David King - 	FROM Disclaimers IMPORT Standard;

Am I misremembering, or don't procedures to be assigned to procedure-
pointers in M2 have to be global and parameterless?  It was that way
on the mainframe Modula-2 compiler I used, but that may not be the
way the language defines it....    -- Darren

darin@nova.laic.uucp (Darin Johnson) (07/01/89)

>        I do not understand why C does not support Nested routines.  Perhaps
>this will be added to the ANSI standard at some point in the future.

Probably the biggest thing against it is the fact that it makes compilers much
more difficult to write (especially modifying existing compilers).  Nesting
subroutines implies changing the way scoping works (which was always vague in
K&R C).  After that is done, you have to worry about getting the binding
right (which is what link, frame pointer, etc. are for).  After that's done,
you have to go back and fix it since you forgot to get the binding right
for procedure parameters that access variables from an outer frame.

Basically, trying to add this to C is not that easy.  Just adding the scoping
is only syntactic sugar.  IMHO, C fits in between assembler and Modula II,
in that you program at a high level, but your model of the world is still
low level.

Generally, there should be no problem converting back and forth between Modula
II and C.  However, I have run across a case where converting to C was
definately not straight forward.  Basically, in Modula II (actually, a similar
language) procedure A was passed as a parameter to procedure B, who called the
nested routine C.  C would recursively call B.  Whenever procedure A was
called, it needed to use the latest instance of B and C's variables.  This did
not map easily at all to using just local and global variables.  Passing stuff
around in a structures and gobs of parameters sort of worked, but nothing was
readable anymore.  Eventually, I just figured out what the code actually did,
and then rewrote it from scratch in 'C-mode'.  The code was readable, but
no where near as 'elegant' as it originally was.  Some Modula II programmers
are just as hesitant about programming in C as some C programmers are about
programming in assembly; it's all perspective.

Darin Johnson (leadsv!laic!darin@pyramid.pyramid.com)
	We now return you to your regularly scheduled program.

wade@pnet01.cts.com (Wade Bickel) (07/01/89)

papa@pollux.usc.edu (Marco Papa) writes:
>In article <4495@crash.cts.com> wade@pnet01.cts.com (Wade Bickel)
>writes: 
>> So far I have found nothing I could do in C that I could not
>>do in M2.  To me this is the test of a Language.
>
>Not really a test of a language at all. Can you have "procedure pointers"
>in M2 (i.e., variables that hold addresses of subroutines, and that get called
>just by referencing the variable, and that of course can be assigned to)?
>As I recall Pascal did not allow that.  This is one of the features of C that 
>currently I could not live without.
>

        In a word, YES.  Modula-2 is not PASCAL.  It allows pointer math and
procedure pointers, and all the other goodies of this nature not included in
PASCAL.  It also has a cleaner stucture definition system, better prototyping,
and much better (Language defined, not compiler specific) separate compilation
scheme.

        As I said in my earlier posting, lack of the ability to nest
subroutines is the first concept I've found which could be translated, in
either direction.  There are many things which I like about C, such as pre-
initialization of data, but none are conceptual issues, just technical ones.

        Please do not continue to use your PASCAL experiances to pre-evaluate
Modula-2.  I did not like PASCAL either.  M2 shares most of PASCALs syntax,
but even here it is significantly different.


                                                Thanks,

                                                        Wade.

UUCP: {nosc ucsd hplabs!hp-sdd}!crash!pnet01!wade
ARPA: crash!pnet01!wade@nosc.mil
INET: wade@pnet01.cts.com

wade@pnet01.cts.com (Wade Bickel) (07/01/89)

mwm@eris.berkeley.edu (Mike (I'll think of something yet) writes:
>In article <4495@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
><        So far I have found nothing I could do in C that I could not do in
><M2.  To me this is the test of a Language.
>
>You're not looking very hard. Please translate the following C
>construct into M2:
>
>	short main[] = {1, 2, 3} ;
>

Sure,

        main : ARRAY[0..2] OF INTEGER;

        main[0] := 1; main[1] := 2; main[3] := 3;

Pre-initialization is a nicety, not allowed in M2 because there is no way to
type the data.  This is a restriction that I understand will be/has been
lifted.  However, pre-initailization is not a conceptual tool.  It can always
be translated to a series of assignments, or a number of other methods can
be used to init data.

>On hardware that supports it, this sets up three words, puts the
>values 1, 2 and 3 into them, and arranges to branch to that location
>under the right conditions. Likewise, can you write M2 code that
>_will_ generate an address exception? Both of these features were used
>in the Unix kernel at one point in the past. 
>

        I don't see how the code you've listed arranges the branch, so perhaps
I am missing something, but since I understand the code you've listed, I think
it unlikely.

        Yes, M2 can be used to generate and deal with address exceptions.  The
new Benchmark debbugger does so.

>Of course, if you don't need to do these kinds of things, then you
>don't care about them. So C may not be the language of choice for the
>problem at hand. And that's my test of a Language - how do the idioms
>of the problem I'm solving map to it.
>
>Finally, from elsewhere:
>
>>> In fact, if you declare a function (or a variable external to a function)
>>> to be static, it will be local to the source file but global to all functions
>>> within that file. 
>
>Not quite. C (like many other languages) reqiures forward
>declarations.  Functions and variables are only visible to code that
>occurs after their decleration in the file. And an external variable
>declared in a function only has function scope in ANSI C. In pre-ANSI
>C, the scope wasn't explicitly defined, and PCC based compilers gave
>it file scope.
>

        Besides, as I have already pointed out, static variables do not cut it
as they will not generate a new level of locals on a recursive call.  The
whole point of nesting is to create an autonomous sub-environment which can
be called recursively forces such an environment to be restricted to a
single routine.

        The "declare static variables" solution that keeps cropping up does
not work.

        As I said before, what bothers me most about this is that I can see no
reason why C does not support this feature.  Perhaps Lattice or MANX will add
it, since the only hit would be that the programs written using nested sub-
routines would not be portable to other compilers.  If portability is an
issue, the coder could simply not nest any subroutines.  In the meantime I
could get back to writing shorter, neater initialization and data search
routines using nesting.  Alternatively someone could point out some good
reason why C does not support nested routines?


                                                        Thanks,


                                                                Wade.
PS:  Please, send me Email if you do not have a solution to the problem I
        posted, i.e. a lack of the ability to nest subroutines in C.  I had
        hoped it would be possible, and am quite dissapointed that it is not.
        At this point I am more interested in how to introduce it into the
        C language than arguing whether C is better or worse than M2.  How
        do I make a request to the ANSI commitee?


UUCP: {nosc ucsd hplabs!hp-sdd}!crash!pnet01!wade
ARPA: crash!pnet01!wade@nosc.mil
INET: wade@pnet01.cts.com

wade@pnet01.cts.com (Wade Bickel) (07/02/89)

To Doug Merritt:

        Modula-2 and C both exist for the Amiga.  The other "alternative"
languages you mention either do not, or are not suitable for an serious work.
Therefore I think we should constrain any discussion to these languages,
possibly adding FORTH to the list.

        I've looked at the code genrated by the M2 compilers.  The data for
vars declared as locals are referenced off the stack, much like parameters.
Not too big a hit in performance.

        I really did not intend to get into a language war.  What I expected
was to be told how to nest routines in C.  Instead I was told that it cannot
be done.

        As to your arguments about the M2 import mechanism, it is really not
such a big deal, and is certainly superior to that allowed in C.  Remember
that pre-compiled files are a non-standard part of C, whereas they are
standard in M2.  However I agree that allowing the statement

FROM Graphics           IMPORT ALL;

would be an improvement.  I believe this may be added to M2Sprints next
update, and may be added to Benchmark as well (I'll have to talk to Leon
Frenkel).

        I am switching to C so I can move to C++.  Hopefully C++ will be
a win, though I wish Eiffel were available as I'd like to check it out.


                                                        Have Fun,


                                                                Wade.

UUCP: {nosc ucsd hplabs!hp-sdd}!crash!pnet01!wade
ARPA: crash!pnet01!wade@nosc.mil
INET: wade@pnet01.cts.com

wade@pnet01.cts.com (Wade Bickel) (07/02/89)

Look everyone, I realize that writing nested routines will produce code that
is not as fast as non-nested routines.  I usually use this technique in
recursive initialization routines like the one shown.  In these situations,
which almost always occure, nested routines make for much shorter code, and
reduce the data space by allocating it on the stack.


                                                        Thanks,


                                                                Wade.

UUCP: {nosc ucsd hplabs!hp-sdd}!crash!pnet01!wade
ARPA: crash!pnet01!wade@nosc.mil
INET: wade@pnet01.cts.com

wade@pnet01.cts.com (Wade Bickel) (07/02/89)

new@udel.EDU (Darren New) writes:
>In article <8608@pyr.gatech.EDU> dsking@pyr.UUCP ( David King) writes:
>>Modula-2
>>does allow using procedure variables in the same manner as C.  
>> David King - 	FROM Disclaimers IMPORT Standard;
>
>Am I misremembering, or don't procedures to be assigned to procedure-
>pointers in M2 have to be global and parameterless?  It was that way
>on the mainframe Modula-2 compiler I used, but that may not be the
>way the language defines it....    -- Darren


        Yes and no.  The procedures must be global, but not parameterless.

                                                                Wade.

UUCP: {nosc ucsd hplabs!hp-sdd}!crash!pnet01!wade
ARPA: crash!pnet01!wade@nosc.mil
INET: wade@pnet01.cts.com

doug@xdos.UUCP (Doug Merritt) (07/02/89)

In article <4525@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
>PS:  Please, send me Email if you do not have a solution to the problem I
>        posted, i.e. a lack of the ability to nest subroutines in C.  I had
>        hoped it would be possible, and am quite dissapointed that it is not.
>        At this point I am more interested in how to introduce it into the
>        C language than arguing whether C is better or worse than M2.  How
>        do I make a request to the ANSI commitee?

You must have missed the comments I and others made to the effect that
it is extremely unlikely that this ability will ever be added to C, because
it requires the addition of an expensive mechanism which is hidden from
sight (displays). In C, expense is not to be hidden, and some people
even objected to the addition of structure assignment to the language because
it violated that philosophy!

The way to translate an M2 program that uses nested subroutines is
(as has also been pointed out) to put all the variables in question
into a structure, and pass a pointer to the structure. This is essentially
what M2 does to implement displays behind the scenes. The original structure
should be local (automatic) to the "outermost" routine for recursion to
work correctly. Somebody said that, when they tried that, the result
was unreadable. But that's not *inherent* in this technique; it's possible
to write very readable code this way. Saying foo->list is not that
much worse than just saying "list".

If recursion is not used, then simply using static variables defined
outside that routine suffices, although IMHO it often results in code
that's less readable than the "pass a pointer to a structure" approach.

The nested scoping visibility of routine and variable names cannot
be directly emulated (beyond the one level provided by static-within-a-
source-file), but that is a "syntactic sugar" issue that does not affect
functionality.

Again, I can see how people would really like this nested scoping feature,
but that doesn't mean that C is deficient because it lacks it...it conflicts
with C's design philosophy. "If it ain't broken, don't fix it." So if
you're going to use C, it would be best if you just learned to live with
its philosophy; otherwise you'll be more frustrated than necessary when
working with the language.
	Doug
-- 
Doug Merritt		{pyramid,apple}!xdos!doug
Member, Crusaders for a Better Tomorrow		Professional Wildeyed Visionary

mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) (07/03/89)

In article <4525@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
<mwm@eris.berkeley.edu (Mike (I'll think of something yet) writes:
<>You're not looking very hard. Please translate the following C
<>construct into M2:
<>
<>	short main[] = {1, 2, 3} ;
<>
<
<Sure,
<
<        main : ARRAY[0..2] OF INTEGER;
<
<        main[0] := 1; main[1] := 2; main[3] := 3;
<
<>On hardware that supports it, this sets up three words, puts the
<>values 1, 2 and 3 into them, and arranges to branch to that location
<>under the right conditions.
<
<        I don't see how the code you've listed arranges the branch, so perhaps
<I am missing something, but since I understand the code you've listed, I think
<it unlikely.

Yes, you're missing something. "main" is always the first symbol run
in any C program (well, normally, anyway - some implementations allow
you to avoid it, but all should invoke main above if the hardware
supports it). I was thinking of a specific program, and chose a bad
example. Better would be:

	int funcy[] = {1, 2, 3} ;
	.
	.
	.

	x = ((int *())funcy)() ;

And the intialization is sort of immaterial. It's the ability to call
your data that's important here.

<        Yes, M2 can be used to generate and deal with address exceptions.  The
<new Benchmark debbugger does so.

And it's written entirely in M2? Care to show the M2 to generate an
address exception? The C is simple (and once again, makes assumptions
about the hardware it's running on):

	int *y ;
	char x[2] ;

	y = (int *) &x[0] ;
	*y = 1 ;
	y = (int *) &x[1] ;
	*y = 1 ;

BTW, I also sent you mail giving the the real reason that C doesn't
have nested subroutines. Not having recieved a reply, I'm assuming the
mail isn't getting through, so I'll repeat it.

C doesn't support nested subroutines because they require code
expansion into something other than simple sequences of PDP-11 code.
You can dress it up and say "it violates C's being close to the
machine", but that's only true for certain classes of machine. The
PDP-11 is an example of same, and the first target for a C compiler.

	<mike
--
It's been a hard day's night,				Mike Meyer
And I been working like a dog.				mwm@berkeley.edu
It's been a hard day's night,				ucbvax!mwm
I should be sleeping like a log.			mwm@ucbjade.BITNET

papa@pollux.usc.edu (Marco Papa) (07/03/89)

In article <4524@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
>papa@pollux.usc.edu (Marco Papa) writes:
>>In article <4495@crash.cts.com> wade@pnet01.cts.com (Wade Bickel)
>>writes: 
>>Can you have "procedure pointers"
>>in M2 (i.e., variables that hold addresses of subroutines, and that get called
>>just by referencing the variable, and that of course can be assigned to)?

>        In a word, YES.  Modula-2 is not PASCAL.  It allows pointer math and
>procedure pointers, and all the other goodies of this nature not included in
>PASCAL.

I've been told by a third party the this is not entirely true. Can you have 
procedure pointers as fields of data structure as in:

struct xpr {
	long (*xpr_open)();
	long (*xpr_close)();
	....
}

...
struct xpr *io;

io->xpr_open = MyOpen;
io->xpr_close = MyClose;

Can you do that in M2?  I'd really like to know? Also does M2 provide
setjmp/longjmp in one of the libraries?

-- Marco Papa 'Doc'
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
uucp:...!pollux!papa       BIX:papa       ARPAnet:pollux!papa@oberon.usc.edu
"There's Alpha, Beta, Gamma, Diga and Caligari!" -- Rick Unland
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

papa@pollux.usc.edu (Marco Papa) (07/03/89)

In article <4525@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
>mwm@eris.berkeley.edu (Mike (I'll think of something yet) writes:
>>In article <4495@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
>><        So far I have found nothing I could do in C that I could not do in
>><M2.  To me this is the test of a Language.
>>
>>You're not looking very hard. Please translate the following C
>>construct into M2:
>>	short main[] = {1, 2, 3} ;
>
>Sure,
>        main : ARRAY[0..2] OF INTEGER;
>        main[0] := 1; main[1] := 2; main[3] := 3;
>
>Pre-initialization is a nicety, not allowed in M2 because there is no way to
>type the data.  This is a restriction that I understand will be/has been
>lifted.  However, pre-initailization is not a conceptual tool.  It can always
>be translated to a series of assignments, or a number of other methods can
							  ^^^^^^^^^^^^^
>be used to init data.

C'mon. SURE you say. The answer is NO, you can't do it.  And the result of this
can be devastating for a large project.  M2 like Pascal REQUIRES you to write 
CODE to initialize all your variables that need initialization.  Think for 
example of all the menus in a program: you'll need one line of code (that
dereferences a pointer or accesses a field) for EACH field in EACH of the 
Menu item. If you have ever seen a "large" PASCAL program there is ALWAYS a 
HUGE file with all the initializations.  This is enough a reason to not make 
me consider M2 for any serious programming.  I can't understand how you
can call this a 'nicety'. Lack of it is just dreadful. The fact that MAYBE/
WILLBE/HAS BEEN/IT IS POSSIBLE that some M2 compilers allow pre-initialization
is irrelevant, because those programs will be totally 'unportable'. 

And what are the "number of other methods [that] can be used to init the data"
besides pre-initialization and assignement?

>PS:  Please, send me Email if you do not have a solution to the problem I
>        posted, i.e. a lack of the ability to nest subroutines in C.  I had
>        hoped it would be possible, and am quite dissapointed that it is not.
>        At this point I am more interested in how to introduce it into the
>        C language than arguing whether C is better or worse than M2.  How
>        do I make a request to the ANSI commitee?

Forget it. The ANSI committe has JUST approved the new ANSI C standard after
YEARS of debate.  You won't see ANY major change made to it for at least the
next 5 years (when something becomes an ANSI standard, it is ever more 
difficult to change).  Also note that "nested subroutines" were proposed and 
struck down during the process of standardization. Lattice was at the forefront
of the ANSI committe.  Maybe John Toebes VIII could enlighten us about why
this feature wasn't included.

-- Marco Papa 'Doc'
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
uucp:...!pollux!papa       BIX:papa       ARPAnet:pollux!papa@oberon.usc.edu
"There's Alpha, Beta, Gamma, Diga and Caligari!" -- Rick Unland
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

kevin@cbmvax.UUCP (Kevin Klop) (07/03/89)

In article <4525@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
>        Besides, as I have already pointed out, static variables do not cut it
>as they will not generate a new level of locals on a recursive call.  The
>whole point of nesting is to create an autonomous sub-environment which can
>be called recursively forces such an environment to be restricted to a
>single routine.
>
>
>
>                                                        Thanks,
>
>
>                                                                Wade.

Wade, if you wish to declare a variable that is local to a function
for recursive calls, then:

MyRecursiveFunction()
{
	char AVariableThatIsInstantiatedEachTimeThisFunctionIsCalled;

	.
	.
	,
};

Does it.  Am I misunderstanding your question?

As to Modula-2 vs. C, I too wish to avoid that sort of discussion. :^)

                  -- Kevin --

Kevin Klop		{uunet|rutgers|amiga}!cbmvax!kevin
Commodore-Amiga, Inc.

The number, 111-111-1111 has been changed.  The new number is:
134-253-2452-243556-678893-3567875645434-4456789432576-385972

Disclaimer: _I_ don't know what I said, much less my employer.

clyde@hitech.ht.oz (Clyde Smith-Stubbs) (07/03/89)

In article <603@laic.UUCP>, darin@nova.laic.uucp (Darin Johnson) writes:
> >        I do not understand why C does not support Nested routines.  Perhaps
> >this will be added to the ANSI standard at some point in the future.

I looked into this in depth recently - there is no real problem with
managing a display to allow access to the local variables of outer
functions (except for the messiness of locating register variables) but
the problem arises since in C you can pass a pointer to a function to
an unrelated piece of code. Imagine if you passed a pointer to a a function
at block level 4 to a global function which stored it, then the level 4
function got executed after its own enclosing global function had terminated.
It could attempt to access variables outer to it which did not exist!

The only way around it I could think of was to enforce some compile-time
constraints on what you could do with pointers. I suspect that such
constraints could be devised which would reduce the problem to something
no worse than the existing C problem that arises when e.g. you return
a pointer to an automatic variable from a function (that one catches every
C programmer sooner or later).

In short, I see nested functions as practical to implement in C; there are
certain cases where nested functions can make a solution to a problem much
more elegant than is currently possible.

Clyde Smith-Stubbs, HI-TECH Software, Brisbane, QLD, Australia.

bartonr@jove.cs.pdx.edu (Robert Barton) (07/03/89)

 mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) writes:
> And it's written entirely in M2? Care to show the M2 to generate an
> address exception? The C is simple (and once again, makes assumptions
> about the hardware it's running on):
>
>    int *y ;
>    char x[2] ;
>
>    y = (int *) &x[0] ;
>    *y = 1 ;
>    y = (int *) &x[1] ;
>    *y = 1 ;


MODULE Exception;

FROM SYSTEM IMPORT ADR;

VAR
  y : POINTER TO INTEGER;
  x : ARRAY [0..1] OF CHAR;

BEGIN
  y := ADR(x[0]);
  y^ := 1;
  y := ADR(x[1]);
  y^ := 1
END Exception.

  This works fine with M2Sprint ("fine" meaning generates the exception).

(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
  P-Link := PDX*BOB    bix := robart

wade@pnet01.cts.com (Wade Bickel) (07/03/89)

papa@pollux.usc.edu (Marco Papa) writes:
>And what are the "number of other methods [that] can be used to init the data"
>besides pre-initialization and assignement?

        What about creating a data file and loading it?  Amoung other things,
this gets rid of the relocation data which ends up in you loadable file when
using pre-initialization in C.

        In any case, I think I've figured out how to achieve exactly the same
effect in C as the use of nested routines in M2.  At least with Lattice.  I'll
elaborate if it works.


                                                        Thanks,


                                                                Wade.

UUCP: {nosc ucsd hplabs!hp-sdd}!crash!pnet01!wade
ARPA: crash!pnet01!wade@nosc.mil
INET: wade@pnet01.cts.com

mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) (07/04/89)

In article <212@hitech.ht.oz> clyde@hitech.ht.oz (Clyde Smith-Stubbs) writes:
<In article <603@laic.UUCP>, darin@nova.laic.uucp (Darin Johnson) writes:
<> >        I do not understand why C does not support Nested routines.  Perhaps
<> >this will be added to the ANSI standard at some point in the future.
<
<[Description of problem of references to variables that don't exist anymore.]
<
<The only way around it I could think of was to enforce some compile-time
<constraints on what you could do with pointers.

This is the hack solution. It's much better to cause function
references to include the state of the "dynamic" variables when you
save the pointer. This gets rid of a wart (that strange restriction),
and allows for some very elegant solutions to problems.

<In short, I see nested functions as practical to implement in C; there are
<certain cases where nested functions can make a solution to a problem much
<more elegant than is currently possible.

Most (all?) of those cases are actually handled even more elegantly
with a real data abstraction rather than these scoping rules. The only
possible exceptions I know of mimicing dynamic scoping. The community
that loved dynamic scoping has largely given up on it, but kept a
mechanism around (variables that are dynamically scoped) to handle
those cases where it's really needed.

	<mike
--
I'm gonna lasso you with my rubberband lazer,		Mike Meyer
Pull you closer to me, and look right to the moon.	mwm@berkeley.edu
Ride side by side when worlds collide,			ucbvax!mwm
And slip into the Martian tide.				mwm@ucbjade.BITNET

peter@sugar.hackercorp.com (Peter da Silva) (07/04/89)

In article <4525@crash.cts.com>, wade@pnet01.cts.com (Wade Bickel) writes:
> Pre-initialization is a nicety, not allowed in M2 because there is no way to
> type the data.  This is a restriction that I understand will be/has been
> lifted.  However, pre-initailization is not a conceptual tool.  It can always
> be translated to a series of assignments, or a number of other methods can
> be used to init data.

And nested procedures can be implemented by explicitly passing the frame
pointer. In fact, you can implement nested procedures efficiently in 'C',
whereas you can't implement pre-initialisation efficiently in Modula.

And how about fall-throughs in switch statements?

>         As I said before, what bothers me most about this is that I can see no
> reason why C does not support this feature.

Because it requires that you implement displays, adding considerably to the
complexity and overhead of the generated code, for a capability that can be
implemented by hand.

Asking why C doesn't implement nested procedures is like asking why Modula
doesn't implement multiple inheritance. It's outside the scope of the
language.
-- 
Peter "Have you hugged your wolf today" da Silva      `-_-'
...texbell!sugar!peter, or peter@sugar.hackercorp.com  'U`

peter@sugar.hackercorp.com (Peter da Silva) (07/04/89)

Precompiled files (modules, whatever) are a standard part of 'C'.
-- 
Peter "Have you hugged your wolf today" da Silva      `-_-'
...texbell!sugar!peter, or peter@sugar.hackercorp.com  'U`

dsking@pyr.gatech.EDU ( David King) (07/05/89)

In article <3982@sugar.hackercorp.com> peter@sugar.hackercorp.com (Peter da Silva) writes:
>And nested procedures can be implemented by explicitly passing the frame
>pointer. In fact, you can implement nested procedures efficiently in 'C',
>whereas you can't implement pre-initialisation efficiently in Modula.
>

	Actually its not that hard (famous last words).  Of course it would 
be an extension to Modula-2 rather than the AI to find the first assignment.
I do know of some Modula-2 vendors that are planning on doing this and the 
OSI M2 committee may also be discussing this (I don't keep up with these 
committees, takes a lot of time).

>And how about fall-throughs in switch statements?

	What about them?  Yes, they are more efficient than the M2 way of 
doing it but at the price of more confusion.  Through some hackery you could
get it close to the same efficiency.  

>Asking why C doesn't implement nested procedures is like asking why Modula
>doesn't implement multiple inheritance. It's outside the scope of the
>language.

	Which is why language wars are silly.  I actually had a friend who 
tried arguing that all system hacking should/could be done in APL.  When 
pressed, he finally explained that he was talking about interfacing to
assembly. :-)

			-David
>-- 
>Peter "Have you hugged your wolf today" da Silva      `-_-'
>...texbell!sugar!peter, or peter@sugar.hackercorp.com  'U`

-- 
 David King - 	FROM Disclaimers IMPORT Standard;
Georgia Insitute of Technology, Atlanta Georgia, 30332
uucp: ...!{akgua,allegra,amd,hplabs,ihnp4,seismo,ut-ngp}!gatech!gitpyr!dsking
ARPA: dsking@pyr.gatech.edu

clyde@hitech.ht.oz (Clyde Smith-Stubbs) (07/05/89)

From article <3982@sugar.hackercorp.com>, by peter@sugar.hackercorp.com (Peter da Silva):
> 
> And nested procedures can be implemented by explicitly passing the frame
> pointer. In fact, you can implement nested procedures efficiently in 'C',
> 

What do you mean by "explicitly passing the frame pointer". The frame
pointer is not accesible to the programmer, indeed some implementations
of C have no frame pointer as such, rather they access locals by offset
from the stack pointer.

> 
>>         As I said before, what bothers me most about this is that I can see no
>> reason why C does not support this feature.
> 
> Because it requires that you implement displays, adding considerably to the
> complexity and overhead of the generated code, for a capability that can be
> implemented by hand.

Implementation of displays in C is not difficult, and properly done need
not add much overhead. Indeed, since it is something that adds no overhead
unless you use it (global functions don't use the display) it fits quite
well with that amorphous "Spirit of C". There are certain recursive
tasks that nested functions can be used to implement in a much more
transparent fashion than doing it by hand (I know, I have had to write
code that effectively maintains a manual display one level deep).

------------------------
Clyde Smith-Stubbs
HI-TECH Software, P.O. Box 103, ALDERLEY, QLD, 4051, AUSTRALIA.

ACSnet:		clyde@hitech.ht.oz
INTERNET:	clyde@hitech.ht.oz.au		PHONE:	+61 7 300 5011
UUCP:		uunet!hitech.ht.oz.au!clyde	FAX:	+61 7 300 5246

peter@sugar.hackercorp.com (Peter da Silva) (07/06/89)

In article <8674@pyr.gatech.EDU>, dsking@pyr.gatech.EDU ( David King) writes:
> 	Actually its [pre-initialistion] not that hard (famous last words).
> Of course it would 
> be an extension to Modula-2 rather than the AI to find the first assignment.
        ^^^^^^^^^^^^^^^^^^^^^

Bingo. *there's* the problem.
-- 
Peter "Have you hugged your wolf today" da Silva      `-_-'
...texbell!sugar!peter, or peter@sugar.hackercorp.com  'U`

dillon@POSTGRES.BERKELEY.EDU (Matt Dillon) (07/06/89)

:>>        I do not understand why C does not support Nested routines.  Perhaps
:>>this will be added to the ANSI standard at some point in the future.
:>Probably the biggest thing against it is the fact that it makes compilers much
:>more difficult to write (especially modifying existing compilers).
:
:No. The reason why C does not support nested functions is that it is
:a _bad_ idea. The worst piece of impenetrable rubbish I have ever tried
:to understand was written by Wirth in Algorithms + Data = Programs and
:purported to handle B-trees. It was made impossible to understand by the
:_complexity_ of the scoping considerations. C scoping is not perfect, maybe,
:but nested functions would only make it worse.
:-- 
:Softway: +61 2 698 2322	     Andrew Gollan	adjg@softway.oz
:GPO Box 305, Strawberry				{uunet,mcvax}!softway.oz!adjg
:Hills NSW 2012					Fax: +61 2 699 9174

	Well, actually, I like subroutine nesting, but only if very, very
    restricted.  It would have been to allow it in C and even relatively
    trivial to implement if you disallow access to the sub-subroutines
    function pointer and scope it so only the subroutine containing the
    sub-subroutine can call it.

	I agree that it is an incredibly _bad_ idea if you make it too
    general (like most languages do).

					-Matt

intern@lilink.UUCP (Steve Faiwisewski) (07/06/89)

In article <4536@crash.cts.com> wade@pnet01.cts.com (Wade Bickel) writes:
>..  However I agree that allowing the statement
>
>FROM Graphics           IMPORT ALL;
>
>would be an improvement.  I believe this may be added to M2Sprints next
>update, and may be added to Benchmark as well (I'll have to talk to Leon
>Frenkel).
>                                                                Wade.

Excuse me, but what's wrong with simply IMPORT Graphics; ?
That will accomplish what you're trying to do.  You WILL have to prefix
every reference to an identifier imported from Graphics with
'Graphics.', but I don't see that as a problem.  As a matter of fact
it will make the code more maintainable.

	- Steve -
-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Steve Faiwiszewski					intern@lilink.UUCP
							intern@dasys1.UUCP

applix@runx.oz (Andrew Morton) (07/06/89)

I have been occasionally LEXing and YACCing my way through a PAscal compiler
for the 68k which is compatible with and links with Hitech C objects.
The trick with nested functions/procedures is to keep a longword associated
with every function/procedure. On entry the contents on the longword is saved
on the stack and the function's frame pointer is saved there. This means that
outer functions can load the longword into an address register and refer off it.
Thus the longword always points to the locals (and args) for the current
instantiation of the function. 

On exit the old longword value is popped and restored. This is recursive & 
reentrant. It works. My firat pascal program did a

printf('Hello, world', 10)

daveh@cbmvax.UUCP (Dave Haynie) (07/07/89)

in article <18215@usc.edu>, papa@pollux.usc.edu (Marco Papa) says:

>>Pre-initialization is a nicety, not allowed in M2 because there is no way to
>>type the data.  This is a restriction that I understand will be/has been
>>lifted.  However, pre-initailization is not a conceptual tool.  It can always
>>be translated to a series of assignments, or a number of other methods can
> 							  ^^^^^^^^^^^^^
>>be used to init data.

> C'mon. SURE you say. The answer is NO, you can't do it.  And the result of this
> can be devastating for a large project.  M2 like Pascal REQUIRES you to write 
> CODE to initialize all your variables that need initialization.  Think for 
> example of all the menus in a program: you'll need one line of code (that
> dereferences a pointer or accesses a field) for EACH field in EACH of the 
> Menu item. 

Not necessarily.  In many cases, you will, but for something as repetitive and
well defined as menu-building, you'll build a set of constructor functions, 
and then build each menu entry with possibly a single function call.  I took
this approach in C++, even though I could have used static menu declarations,
and I'm currently of the opinion that at least with the present OS, static
menu declarations are bad medicine.  For example, if I want to insert a new
menu entry at any level, all I do is insert the new function call; all other
menu declarations stay the same.  And what I type is typically something
like this:

	// C++ Menus code fragment

	void Proj_Save_As(), Proj_Save(), Proj_Load();

	menu->add("Project",MENU);
	menu->add("Save As",ITEM,Proj_Save_As);
	menu->add("Save",ITEM,Proj_Save);
	menu->add("Load",ITEM,Proj_Load);

	// ...

This allows menu construction to be as dynamic as you like.  So all the sizing 
and locating of the menus is done at run time.  Which means I automatically
and painlessly adjust to the font in use, among other things.  And the menus
are completely position independent -- no need for some giant nested switch
statements.  

> If you have ever seen a "large" PASCAL program there is ALWAYS a 
> HUGE file with all the initializations.  This is enough a reason to not make 
> me consider M2 for any serious programming.  

There are certainly some very important requirements for static data allocations
that can't be handled by clever constructor functions.  For example, you may
want to include lots of image data, which would be real ugly to build one word
at a time in a constructor function, and hard to change once entered that way.
Though in reality, something like that doesn't really belong as a C static
declaration, either, since while C makes it prettier, it doesn't make it that
much prettier.  What I'd really want is a conversion utility that'd build me
an image object file directly from the IFF file.  That gets added to the
makefile, and changes in the image then happen as soon as I exit DPAINT,
not some minutes or hours later after the image is automatically or manually
converted to source code of some kind.

So some initializations are going to be between these extremes, and much more
ugly in M2 than C, though I don't think the number of these is as great as
everyone currently writing C with lots of initializations seems to think.

> Lack of it is just dreadful. 

Well, I always wonder whenever anyone tries to convince me that the lack of 
something is a feature.

> -- Marco Papa 'Doc'

-- 
Dave Haynie Commodore-Amiga (Systems Engineering) "The Crew That Never Rests"
   {uunet|pyramid|rutgers}!cbmvax!daveh      PLINK: D-DAVE H     BIX: hazy
           Be careful what you wish for -- you just might get it

peter@sugar.hackercorp.com (Peter da Silva) (07/07/89)

In article <268@hitech.ht.oz>, clyde@hitech.ht.oz (Clyde Smith-Stubbs) writes:
> From article <3982@sugar.hackercorp.com>, by peter@sugar.hackercorp.com (Peter da Silva):
> > And nested procedures can be implemented by explicitly passing the frame
> > pointer. In fact, you can implement nested procedures efficiently in 'C',

> What do you mean by "explicitly passing the frame pointer".

I mean, explicitly passing a ponter to the stack frame that contains that
particular set of variables. Maybe you call it the display pointer:

struct outer_display {
	type outer_var;
	...
};

struct middle_display {
	type middle_var;
	...
};

static inner_func(mid, out, myvars)
struct middle_display *mid;
struct outer_display *out;
type myvars;
{
	mid->middle_var = myvar;
	...
}

static middle_func(out, myvars)
struct outer_display *out;
type myvars;
{
	struct middle_display mid;
	...
	inner_func(&mid, out, out->outer_var);
	...
	out->outer_var += mid->middle_var;
	...
}

outer_func(myvars)
type myvars;
{
	struct outer_display out;
	...
	middle_func(&out, 7);
	...
}

This is an example of three levels of nested functions implemented in C by
explicitly passing the display pointers. The code generated will be
equivalent to the equivalent modula code. It's a little messier, yes, but
it *is* possible to do the job in C.

> Implementation of displays in C is not difficult, and properly done need
> not add much overhead.

I agree entirely, see above.
-- 
Peter "Have you hugged your wolf today" da Silva      `-_-'
...texbell!sugar!peter, or peter@sugar.hackercorp.com  'U`

doug@xdos.UUCP (Doug Merritt) (07/07/89)

In article <268@hitech.ht.oz> clyde@hitech.ht.oz (Clyde Smith-Stubbs) writes:
>Implementation of displays in C is not difficult, and properly done need
>not add much overhead.

The overhead that it *does* add is invisible, which is what some people
like about it, but is also why it doesn't fit C.

>Indeed, since it is something that adds no overhead
>unless you use it (global functions don't use the display) it fits quite
>well with that amorphous "Spirit of C".

Sorry to say you've gone off the deep end here. That argument could
be used to justify *anything*. Just add a new type called SEXPR which
supports garbage collected dynamic lists. After all, if you don't use
it, it doesn't cost anything at all!!!

Handy though such features may be, they are not in alignment with
C's philosophy.

>There are certain recursive
>tasks that nested functions can be used to implement in a much more
>transparent fashion than doing it by hand (I know, I have had to write
>code that effectively maintains a manual display one level deep).

Yes, and there are some things that Lisp does much more transparently
than C. Again, this is not an argument for adding features to C, it
is an argument for using a different language. Or creating (yet another)
new language, like *((fancy *) C)++.

Once again, C is *supposed* to be a "high level" (not very) systems
programming language that exposes *simple* abstractions of the (*slightly*
idealized) hardware to *direct* manipulation by the programmer, who
is expected to be grateful that there aren't thousands of hidden machine
cycles executed every time he does something that looks simple.

Many languages, including Algol, PL/1, Lisp, Snobol and even Cobol have
at least *some* transparent, expensive conveniences that would be handy
at times, and they all predate C by many years. C is not what it is because
its designers were ignorant of such mechanisms; they left them out *on purpose*.

You don't have to like C or its philosophy, but equally don't expect it
to be something that it's not.
	Doug

P.S. I think Mike Meyer was the first to point out that Displays are
a poor substitute for first class data abstraction features, anyway,
so why worry about second best? Start arguing about adding objects,
classes, inheritence, etc, and people will say "use C++/Objective C/Smalltalk"
and then you'll be on the right track.
-- 
Doug Merritt		{pyramid,apple}!xdos!doug
Member, Crusaders for a Better Tomorrow		Professional Wildeyed Visionary

peter@sugar.hackercorp.com (Peter da Silva) (07/09/89)

There have been a number of articles by various people here that attempt to
minimise the importance of static declarations in C. The point is usually
brought up that things like Intuition structures should really be built
dynamically at run-time... which is true enough. But this is also a very
minor part of the universe of things that you want to use initialised data
for. Understandable, since this is an Amiga board, but it does tend to obscure
the problem.

Here are a few things that really belong as initialised data structures that
don't belong in external files or constructors. These things are also
appropriate for portable applications, so tricks like converting a data file
to an object module are inappropriate:

	Symbol Tables.
	Automatically generated data, such as Yacc or Lex tables.
	Help messages.
	Conversion tables.
	Internal databases.

The thing to consider here is that Modula requires that a program be written
procedurally. There's no simple way to organise data in a declarative manner.

Have a look at the Little Smalltalk on Fish Disk 37 for an example of a program
that greatly benefits from initialised data.
-- 
Peter "Have you hugged your wolf today" da Silva      `-_-'
...texbell!sugar!peter, or peter@sugar.hackercorp.com  'U`

peter@sugar.hackercorp.com (Peter da Silva) (07/09/89)

In article <7223@cbmvax.UUCP>, daveh@cbmvax.UUCP (Dave Haynie) writes:
> What I'd really want is a conversion utility that'd build me
> an image object file directly from the IFF file.  That gets added to the
> makefile, and changes in the image then happen as soon as I exit DPAINT,
> not some minutes or hours later after the image is automatically or manually
> converted to source code of some kind.

How does this rule:

	foo.o: foo.ilbm
		ilbm_to_obj foo.ilbm -o foo.o

Differ from these rules:

	foo.o: foo.c

	foo.c: foo.ilbm
		ilbm_to_c foo.ilbm -o foo.c

Or even:

	foo.o: foo.ilbm
		ilbm_to_c foo.ilbm -o foo.c
		cc foo.c

Which has the advantage that it will work even if the object file format
changes... for example, switching between Manx and Aztec or porting the
program from the Amiga to, say, an AT running SV/386 and X-windows.
-- 
Peter "Have you hugged your wolf today" da Silva      `-_-'
...texbell!sugar!peter, or peter@sugar.hackercorp.com  'U`