home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / comp / std / cplus / 1869 next >
Encoding:
Text File  |  1992-12-21  |  10.4 KB  |  248 lines

  1. Newsgroups: comp.std.c++
  2. Path: sparky!uunet!spool.mu.edu!umn.edu!csus.edu!netcom.com!rfg
  3. From: rfg@netcom.com (Ronald F. Guilmette)
  4. Subject: C++ already *has* nested functions SO WHAT'S THE BEEF?
  5. Message-ID: <1992Dec21.080952.15309@netcom.com>
  6. Keywords: nested functions, dumb ideas
  7. Organization: Netcom - Online Communication Services  (408 241-9760 guest) 
  8. Date: Mon, 21 Dec 1992 08:09:52 GMT
  9. Lines: 237
  10.  
  11.  
  12. I see a lot of nonsense go buy in this newsgroup (and the in the others
  13. I read) and I rarely comment on it all simply because I do not have the
  14. time, but some of the hand-wringing I've seen here recently regarding
  15. the alledged lack of a "nested function" feature in C++ causes me to 
  16. to feel a need to point out the basic fallacy on which come of these
  17. comments have been based.
  18.  
  19. You see, C++ already provides nested functions.  I believe that even the
  20. people who are bemoaning the lack of nested function in C++ are probably
  21. aware of this fact (or would be if they thought about it for a moment)
  22. and that in fact what we have here is a failure to communicate clearly.
  23.  
  24. As illustrated by the lengthy example (of legal C++ code) given at the
  25. end of this message, all that is necessary in order to nest one function
  26. within another is to declared the inner function as a static member of
  27. some class type (invented expressly for this purpose) which is itself
  28. nested within the desired containing function.
  29.  
  30. The example below clearly shows that this is an entirely viable way to
  31. achieve nested functions with C++ (as now defined).  In fact the example
  32. goes to great lengths to demonstrate that references to named entities
  33. declared locally within the function containing the "nested" function
  34. are possible (and legal) with a few minor exceptions, as long as the
  35. references in question obey the normal name scoping rules.
  36.  
  37. So what is it that people are complaining about?
  38.  
  39. Well, obviously there are several small problems with using this sort of
  40. technique for defining nested functions, but let's be clear about what
  41. we are talking about.  We *can* nest functions, so that isn't really
  42. the issue.
  43.  
  44. The problems with this technique are basically as follows:
  45.  
  46.     o    We have to "invent" an otherwise useless and unnecessary
  47.         containing struct, union, or class type in order to be
  48.         able to nest functions.
  49.  
  50.     o    Due to the (silly?) prohibition against defining a function
  51.         member of a block-local struct, union, or class type outside
  52.         of (and after) its "parent" type, and due to the (silly?)
  53.         rule that says that all functions defined *within* a class
  54.         are implicitly `inline', our nested functions are always
  55.         necessarily `inline' (when using this technique for nesting)
  56.         even if we do not want them to be.
  57.  
  58.     o    Last but not least, although nested functions can legally
  59.         reference *most* names of *most* kinds of things declared
  60.         in a containing scope (including one local to a containing
  61.         function) there is one small and mildly annoying exception
  62.         to this general rule... i.e. we cannot access `auto' and
  63.         `register' *objects* declared within a containing local
  64.         scope.  Note that we *can* however reference the tags of
  65.         enum, struct, union, and class, types, names declared in
  66.         typedef statements, names of enumerators, function names,
  67.         and names of static and extern objects which are declared
  68.         in the containing (block) scope.
  69.  
  70. I believe that it is this last item that concerns people the most.  In
  71. fact, I get the general impression that some people view these minor
  72. exceptions (to the general scoping rules) as being horrendous problems
  73. which are so utterly insurmountable that dramatic language changes are
  74. required in order to eliminate these exceptions.
  75.  
  76. It would not concern me if the kinds of changes being suggested were
  77. (in general) trivial for implementors to implement, but when I hear about
  78. all of these complicated schemes for supporting dynamic "up-level addressing"
  79. and also such things as "special" kinds of function pointers for holding
  80. pointers to nested function (and a special new syntax for declaring such
  81. things) I shrink back in horror.  Haven't the implementors already got
  82. enough to do??  Can't people figure out how to simply pass any needed
  83. `auto' variables which are local to the containing function as additional
  84. actual argument to the nested (called) function on those very rare occasions
  85. when this is actually necessary??  I mean what the devil is the problem here?
  86.  
  87. For my part, I would be satisfied if the ANSI/ISO C++ committee(s) would
  88. add "nested functions" to C++ in such a way that the first two problems
  89. on my list above could be eliminated.  But note that this could be done
  90. with only a single minor syntax change (to allow function *definitions*
  91. as well as function *declarations* within a local block) and one minor
  92. semantic change, i.e. disallowing the mention of any name of a locally
  93. declared function (except those declared `extern') in any context other
  94. than a call to the given function.  These two minor changes would solve
  95. the problems I'm concernd with, and they would be relatively easy and
  96. painless for implementors to implement.  Also, just as importantly, they
  97. would not add materially to the already horrendous complexity of the
  98. language (which is already a terrible burden for all those who would try
  99. to learn this language).
  100.  
  101. So why do people insist on attacking (and defeating) the third minor
  102. problem listed above (regardless of costs)?
  103.  
  104. Well, it appears that some people have this mental model of "nested
  105. functions" left over from the days when they programmed in Pascal, where
  106. *anything* in a containing scope could be accessed directly.  Sadly, these
  107. folks don't seem to "get" the fundamental idea which made C into the big
  108. success that it is today... i.e. that it is *good* when potentially
  109. expensive run-time actions (e.g. indirection through some number of
  110. "static link" pointers) are made *explicit* to the programmer so that he
  111. or she will be more aware of the potential effects these things may have
  112. upon run-time performance.
  113.  
  114. Obviously, I have a strong disagreement with the folks who would (for the
  115. sake of eliminating a very minor restriction which only makes a difference
  116. in rare cases anyway) "hack" the language mercilessly (and thereby cause
  117. yet another headache for implementors).
  118.  
  119. I mean c'mon folks... This endless "featurism" has got to stop somewhere!
  120.  
  121. // Ron ("Loose Cannon") Guilmette    uucp: ...uunet!lupine!segfault!rfg
  122. //
  123. //     "On the one hand I knew that programs could have a compelling
  124. //      and deep logical beauty, on the other hand I was forced to
  125. //      admit that most programs are presented in a way fit for
  126. //      mechanical execution, but even if of any beauty at all,
  127. //      totally unfit for human appreciation."
  128. //                         -- Edsger W. Dijkstra
  129.  
  130.  
  131. ===========================================================================
  132. Here's the example code showning how to "nest" functions.  This is perfectly
  133. valid C++ code.  Please try it on your favorite compiler and let me (and
  134. your vendor) know if the implementation you have doesn't compile this
  135. cleanly.  (Many don't, but then I've found that C++ implementations are,
  136. almost without exception, horrendously buggy.)
  137.  
  138. /////////////////////////////////////////////////////////////////////////
  139. void outer (int outer_arg)
  140. {
  141.   // Declare some types whose scope is just this block.
  142.  
  143.   enum        E { red, green, blue };  // The enumerator names are also local!
  144.   class       C { public: int Cmember; };
  145.   struct      S { int Smember; void S_func_member () { } };
  146.   union       U { int Umember; };
  147.   typedef int T;
  148.  
  149.   // Declare some (static-storage) objects of the above types.
  150.  
  151.   static enum        E outer_E_var;
  152.   static class       C outer_C_var;
  153.   static struct      S outer_S_var;
  154.   static union       U outer_U_var;
  155.   static             T outer_T_var;
  156.  
  157.   // Declare some plain objects whose scope is just this block.
  158.  
  159.   auto     int auto_object;
  160.   static   int static_object;
  161.   register int register_object;
  162.   extern   int extern_object;
  163.            int object;        // Really is an `auto'.
  164.  
  165.   // Declare some anon-union objects whose scope is just this block.
  166.  
  167.   auto     union { int auto_anon_Umember; };
  168.   static   union { int static_anon_Umember; };
  169.   register union { int register_anon_Umember; };
  170.   //extern   union { int extern_anon_Umember; };  // dubious (see 7.1.1)
  171.            union { int anon_Umember; };        // Really is an `auto'.
  172.  
  173.   // Declare some functions whose scope is just this block.
  174.  
  175.   extern   int extern_func ();
  176.            int        func ();    // Really is an `extern'
  177.  
  178.   // Now declare a nested function. **************************************
  179.  
  180.   struct INNER {
  181.     static void inner ()
  182.     {
  183.       // Use the types declared in the containing scope (to declare objects).
  184.  
  185.       enum      E inner_E_var;        // OK!
  186.       class     C inner_C_var;        // OK!
  187.       struct    S inner_S_var;        // OK!
  188.       union     U inner_U_var;        // OK!
  189.                 T inner_T_var;        // OK!
  190.  
  191.       // Use the enumerators declared in the containing scope.
  192.  
  193.       inner_E_var = green;        // OK!
  194.  
  195.       // Refer to members of types declared within the containing scope.
  196.  
  197.       inner_C_var.Cmember = 99;        // OK!
  198.       inner_S_var.Smember = 99;        // OK!
  199.       inner_S_var.S_func_member ();    // OK!
  200.       inner_U_var.Umember = 99;        // OK!
  201.  
  202.       outer_C_var.Cmember = 99;        // OK!
  203.       outer_S_var.Smember = 99;        // OK!
  204.       outer_S_var.S_func_member ();    // OK!
  205.       outer_U_var.Umember = 99;        // OK!
  206.  
  207.       // Refer to some plain objects declared in the containing scope.
  208.  
  209.       //outer_arg = 99;            // NO GOOD!
  210.  
  211.       //auto_object = 99;        // NO GOOD!
  212.       static_object = 99;        // OK! NO PROBLEM!
  213.       //register_object = 99;        // NO GOOD!
  214.       extern_object = 99;        // OK!
  215.       //object = 99;            // NO GOOD!
  216.  
  217.       // Refer to some anon-union objects declared in the containing scope.
  218.  
  219.       //auto_anon_Umember = 99;        // NO GOOD!
  220.       static_anon_Umember = 99;        // OK! NO PROBLEM!
  221.       //register_anon_Umember = 99;    // NO GOOD!
  222.       //extern_anon_umember = 99;    // dubious (see above)
  223.       //anon_Umember = 99;        // NO GOOD!
  224.  
  225.       // Refer to some functions declared in the containing scope.
  226.  
  227.       extern_func ();            // OK!
  228.              func ();            // OK!
  229.       
  230.     }
  231.   };
  232.  
  233.   //  Establish a shorthand alias for the nested function.
  234.  
  235. #define inner INNER::inner
  236.  
  237.   // Call the local nested function.
  238.  
  239.   inner ();
  240. }
  241. -- 
  242.  
  243. // Ron ("Loose Cannon") Guilmette
  244. // uucp: ...uunet!lupine!segfault!rfg
  245. // New new motto:  Quality control is a state of mind.
  246. //   misc.forsale.computers ad, circa 2007:
  247. //       Used Cray wrist watch for sale; 25 bucks or best offer.
  248.