Topic: nested functions


Author: David Bruce <dib@dera.gov.uk>
Date: 1999/12/11
Raw View
wmm@fastdial.net wrote:

> As I recall the discussion, there were three main arguments against
> allowing nested functions:
>
> 1) Runtime overhead.  The function calling sequence has to be
> modified to maintain a display pointer or the like.  Considering
> all the howls that went up when multiple inheritance was added to
> the language and virtual function calls became slightly more
> expensive, there wasn't a lot of enthusiasm for adding this overhead.

...

> 3) C data compatibility.  A function pointer in C is a simple object,
> just the address of the code of the function.  A pointer to a nested
> function is more complex, requiring a pointer to the automatic
> storage area.

FWIW, there *are* alternative approaches -- though you might not necessarily
like them any better :-)

For example, one from the Scheme community (due to Bill Rozas, IIRC)
actually gives nested functions simple code addresses, by creating for each
new `closure' a little stub in code space (which then does the
display/whatever stuff behind the scenes).  (Obviously, this assumes that
you can create these stubs at runtime.)  This adds no cost to non-nested
functions, for which one pays an indirection overhead on calling nested
functions (and some cost to their creation).


--

    David Bruce
________________________________________________________________________
post: DERA Malvern, St Andrews Road, Malvern, WORCS WR14 3PS, ENGLAND
mailto:dib@dera.gov.uk ** phone: +44 1684 895112 ** fax: +44 1684 894389
[The views expressed above are entirely those of the writer and do not represent the views, policy or understanding of any other person or official body.]




[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <david@tribble.com>
Date: 1999/06/25
Raw View
John Potter wrote:
>
> David R Tribble <dtribble@technologist.com> wrote:
>: I disagree; I don't think it makes much sense to call or pass a
>: pointer to a local function to functions outside its scope (i.e,
>: outside its enclosing function).  It's analogous to passing pointers
>: to local structures to other functions outside the function
>: containing the structure declaration.
>
> Disallow passing address of a local int too?  A structure is a
> complete type a function is just a prototype.  Pointer to function
> with a given prototype does not need the name.  A structure is a
> type and has a name.  Two structure types with the same layout
> have different types.  Two functions with the same prototype have
> the same pointer type.

Passing a pointer to a local int to another function requires the
second function to use the well-defined type 'int*'.  Passing a
pointer to a locally defined struct type requires the second function
to use a parm of type - what?  If the local struct is not a derived
type, then it is a completely unique type which is unknown outside of
its parent function (which can't be forward-declared).

A pointer to a local function is not the same as a pointer to a
nonmember function, because it entails context information (at the
very least, the compiler needs to know how many levels it has in its
display frame).  This is analogous to a pointer to a locally defined
struct, i.e., like saying that a pointer to a local function is a
completely unique type which is unknown outside of its parent
function.

Supposedly, this difference is solved using pointers to trampolines
as pointers to local functions.  But I'm not convinced that
trampolines can be implemented in all C++ implementations.

>: P.S.  I personally don't see any need for nested functions. Still,
>: they make for an interesting discussion in language design.
>
> Me either.  Real nested functions have been around a long time in
> several languages.  I don't think that your watered down versions
> will provide anything of interest.  They could not be used as
> call-backs with context which was the original poster's desire.

At this point, I'm not sure fully-unwatered versions of local
functions will provide much of interest either.

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/06/26
Raw View
David R Tribble <david@tribble.com> writes:

>I'm not convinced that trampolines can be implemented in all C++
>implementations.

Which part of my explanation did you find unconvincing?

If you were to say that implementing trampolines might be complex
or difficult, then I won't argue with you.  Implementing trampolines
is a non-trivial task, and whether or not the benefits are sufficient
to justify the additional implementation complexity is certainly debatable.

But if you say that it can't be done, then I must refer you to my
previous explanation of how it can be done, and ask you which part
of it you did not believe or did not understand.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/06/23
Raw View
James.Kanze@dresdner-bank.com writes:

>ark@research.att.com (Andrew Koenig) wrote:
>> <gbush@my-deja.com> wrote:
>>
>> > C++ unlike other languages doesn't support nested functions.
>> > [...] I wonder, is there at least one good reason why it is so?
>>
>> Yes -- the reason is that someone proposed it to the committee,
>> the committee talked about it, took a vote, and the proposal lost.
>
>Was this a formal proposal?  When during the standardization process?

Yes, there was a formal proposal, from John Skaller and I.  It was
relatively early on -- in 1993, between May and October; a few months
before the first CD was due.  John Skaller went to one of the comittee
meetings, where it was discussed, and he reported the following to me
in email afterwards (I'm pretty sure he wouldn't mind me quoting this):

 |         Nested functions were discussed, there was some support,
 |  for example from Dag Bruck (who showed how its useful
 |  with concurreny). Unfortunately, too many C programmers
 |  who just dont appreciate the utility of functional decomposition.
 |  The proposal was not rejected outright though. Its still on
 |  the active list.  However, the WP is to be released
 |  to SC22 in a few months :-(

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/06/23
Raw View
James.Kanze@dresdner-bank.com wrote:
>
> In article <7jrv0r$dfq$1@engnews1.eng.sun.com>,
>   clamage@eng.sun.com (Steve Clamage) wrote:
>
> > C++ has enough different scope control mechanisms you don't need
> > local functions the way you need them in, say, Pascal. The
> > primary reason to have local functions in C++ would be to
> > implement closures. If you just want to share state among
> > cooperating functions, use a class. The code will be simpler
> > and easier to maintain.
>
> Just a question of vocabulary, but what is a closure, exactly.  I've
> always thought that, in layman's terms, it extended the life of the
> local context beyond the return from the function.  I think that this is
> how it works in lisp (but my lisp experience is limited to customizing
> emacs, so I'm not sure).  And of course, Borland has invented a totally
> different meaning.

Yes, that's a big problem. Maybe we should always qualify the
word "closure", like "functional closure" and "BC++ closure".
However, I prefer the term "bound member pointer" for the last
one. (BTW, those "BC++ closures"/bound member pointers could be
implemented as usual function pointers with the same trampoline
technique as suggested for pointers to local functions - just that
the trampoline would add the class pointer instead of the local
function context).

> What you are describing would seem to be closure as
> I understand it, but without the extended lifetime.  Or are you
> suggesting that Pascal extended the lifetime of the function context
> beyond the return from the function if the address of the function was
> taken.  (The Pascal I used didn't, but there are so many variations of
> Pascal, it's hard to know what is standard, and what is fantasy on the
> part of the implementer.)

Just for your information: Standard Pascal doesn't allow to
take the address of a function at all, nor does it let you
return (or otherwise store) a reference to a function.
All it allows is passing functions as parameters "by reference".
So the question of surviving contexts doesn't arise at all here.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/06/23
Raw View
James.Kanze@dresdner-bank.com writes:

>clamage@eng.sun.com (Steve Clamage) wrote:
>
>> C++ has enough different scope control mechanisms you don't need
>> local functions the way you need them in, say, Pascal. The
>> primary reason to have local functions in C++ would be to
>> implement closures. If you just want to share state among
>> cooperating functions, use a class. The code will be simpler
>> and easier to maintain.
>
>Just a question of vocabulary, but what is a closure, exactly.

A closure consists of two things: a piece of code containing free
variables (or simply the name or address of such a piece of code),
plus an environment which specifies the bindings for those variables.
I think the name comes from the idea is that a closure
"closes" over the free variables.

>I've
>always thought that, in layman's terms, it extended the life of the
>local context beyond the return from the function.

If you're trying to be precise about things, in the terminology that I'm
familiar with, that would be referred to as a "closure with unlimited extent".

(On the other hand, a quick altavista search found no hits at all for
the term "closure with unlimited extent", so perhaps the terminology
that I'm familiar with is not as commonly used as I thought ;-)

>I think that this is
>how it works in lisp (but my lisp experience is limited to customizing
>emacs, so I'm not sure).

Yes.  Lisp has closures with unlimited extent.  And since it doesn't have
any other kind of closures, the lisp community tends to just call them
"closures".

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/06/23
Raw View
David R Tribble <dtribble@technologist.com> writes:

>No one's addressed the problem of what happens when a local function
>is invoked through a pointer after its outer function's scope has
>ended.  Is this simply undefined behavior?  Is an exception thrown?

It's simply undefined behaviour, just the same as when a local variable
is accessed through a pointer after its containing function's scope has
ended.

>Okay, so I'm alone in my opinion that, just as local functions are
>only visible (i.e., callable) from other local functions within the
>same outer function, pointers to local functions should be restricted
>to being passed/invoked within the scope of their outer function.
...
>My restriction avoids this whole problem.
>
>It also makes the implementation of local function pointers much
>simpler

These points are both true.  However, your design would also make
local functions much less useful.

>My guess is that nested functions would be no more harder to
>implement than exception handling.
>
>Oh, and by the way, how do nested functions complicate exception
>handling?  No one's discussed that either.

They don't.

If you allow gotos from a nested function into its containing
function, as GNU C does (the effect is similar to a longjmp
in that it unwinds the stack) then there might be some additional
complications.  But there is no need to allow that for C++.

>What is hard is adding yet another kind of function pointer, which
>allows the compiler to properly invoke a pointed-to local function
>so that its invocation frame is properly constructed.  I'm led to
>the conclusion that the compiler needs to know it's a local
>function pointer, distinct from a "normal" function pointer, so that
>this can occur; this implies a new syntax for distinguishing between
>the two kinds of pointers.  (I already suggested the syntax
>'({}::* fp)()' in another post.)  Such a pointer must contain extra
>information such as the number of nesting levels needed by the
>pointed-to function's display; perhaps such a pointer points to
>a static "display descriptor" which contains such information,
>much like an object's _vtbl pointer points to a static "class
>descriptor table".

This seems like quite a bit of additional complexity, both for the
implementation and for the programmer.  The alternative approach of
using trampolines is a much more elegant approach, at least as far as
the programmer is concerned, and much more useful.  It probably adds
a comparable amount of complexity to the implementation.  The drawback
is that it requires modifications to the back-end rather than just to
the front-end.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: source@netcom.com (David Harmon)
Date: 1999/06/23
Raw View
On 16 Jun 99 03:58:16 GMT in comp.std.c++, James.Kanze@dresdner-bank.com
wrote:

>> I'm afraid that would have to be disallowed too.  The type of &g would
>> be something resembling int(main::*)(int) and nothing outside of main
>> would know enough about it to use it.  foo(g) would be a type
>mismatch.
>
>But then you've eliminated the main reason for wanting local functions.

After reading some of your other articles, I think you may be right,
subject to some question over "main reason."  I don't think it
eliminates the main reason I wanted them, but I may be thinking too
narrowly.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/06/23
Raw View
David R Tribble wrote:
>
> Fergus Henderson wrote:
> >
> > "Dave Abrahams" <abrahams@mediaone.net> writes:
> >
> > >fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
> > >
> > >> In addition, on implementations with appropriate virtual memory
> > >> support, you can create an unbounded size trampoline stack
> > >
> > >Even virtual memory is bounded,
> >
> > Sorry, you are of course correct -- "unbounded" was not quite the
> > right word, I should have said "bounded only by the size of the
> > virtual memory".
> >
> > But I think your point is irrelevant to the consideration of whether
> > or not nested functions should be or should have been included in the
> > C or C++ standards.  Any program's memory use will be limited by the
> > size of virtual memory -- the separate trampoline stack that might be
> > needed (on systems which don't allow creating code at runtime) should
> > not make things any worse in that respect.
>
> It would probably complicate code generation for embedded systems,
> which typically have very constrained memory resources.  OTOH,
> implementors could simply refuse to add nested functions to EC++.

Or they could limit them to non-recursive outer functions. Then you
don't need a stack; one static variable per function with nested
functions (set by the outer function on entry/exit) would
suffice.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/23
Raw View
In article <7k3fr2$7el@abyss.West.Sun.COM>,
  stanley@West.Sun.COM (Stanley Friesen [Contractor]) wrote:
> In article <7k0b01$nod$1@panix.com>,
> Greg Comeau <comeau@comeaucomputing.com> wrote:
> >scope is a syntactic thing.  It doesn't apply to a running program
> >in the same sense.

> True - but there is this little rule that variables of automatic
> *duration* are destroyed on exit from their scope.

On *final* exit from their scope.

> >  So, when you say the local vars do not exist when you leave the
> >scope, they will if the local function calls a different function,
> >perhaps passing or having pointers to the local vars.

> But if the destructors have been called on them, and the sotrage
> reused for some other set of automatic variables (as is allowed upon
> leaving a function), then those pointers generate undefined behavior,
> as they are pointers to variables after their destructors are called.

I'm pretty sure what Greg is talking about is nested function calls.
Consider the following:

    void
    f( int* pi )
    {
        ++ (*pi) ;
    }

    void
    g()
    {
        int                 x = 0 ;
        f( &x ) ;
        cout << x << '\n' ;
    }

You pass the address of a local variable to another function (eventually
in another compilation unit).  If C/C++ had nested functions, I would
expect to be able to do exactly the same thing with the address of the
nested function.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orientie objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <dtribble@technologist.com>
Date: 1999/06/23
Raw View
Steve Clamage wrote:
> Maybe you could explain how local functions that could not be
> called from outside the enclosing function scope would be a
> useful addition to C++. What programming problems can be solved
> more easily? It seems to me that a class with member functions
> solves all the same problems, and does a better job of it.

It would be useful for adding local (i.e., externally hidden)
functions to a class that have full access to all the class's
members (by having access to their outer function's 'this' pointer)
without the need for adding their declarations to the class
declaration.  Sort of like being able to define static functions
in a source file that act like member functions (by having access
to all the members of the class) without needing to be declared in
the class declaration (and are thus hidden to casual readers of
the class's header file).  This would make it easier to hide the
private implementation details of a class without revealing the
names of of its private member functions in its declaration.

Granted, this isn't a big win, and we usually aren't saving any
effort in the long run by avoiding the extra member function
declarations.

I think the effort of adding local functions to C++ outweighs
their benefits.  Since I began programming in C/C++ in 1982, I
have had the need for something resembling nested functions
perhaps two or three times, and I was always able to find a
reasonable existing alternative.

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/23
Raw View
In article <37fc8bd2.644752685@nntp.ix.netcom.com>,
  source@netcom.com (David Harmon) wrote:
>
> On 10 Jun 99 16:20:58 GMT in comp.std.c++, ark@research.att.com
> (Andrew Koenig) wrote:
>
> >> Why do local functions have to have the same calling sequence as
non-local
> >> functions?
> >
> >Because otherwise, you can't define a variable
> >(of type pointer to function) that can potentially
> >contain the address of a local function or a non-local
> >function.
>
> Just like you can't define a variable that can hold both a pointer
> to a member function or a pointer to a non-member function.  A local
> function is actually more like a member function than a non-member
> function, but instead of 'this' it gets a pointer to an implicit
> local context object (AKA display.)

In that case, why not just make it a pointer to member of a class
deriving from __local_scope.

The difference, in both cases, is that the function to which it is
passed as a parameter must know that it is dealing with a local
function/a pointer to member function, and handle it separately.  For a
pointer to member function, this is a requirement anyway, because the
pointer to member function is *not* bound to an instance of the class.
The caller must provide the instance.  A pointer to a local function, on
the other hand, is bound, and can be used exactly like a pointer to any
other function.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orientie objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/06/23
Raw View
"G.B." <gb@web1.ucar.edu> wrote:

: void f3() {
:   void f4(){};
:   p_global(); // run-time error; the local context is different

Undefined behavior covers that.

:   f1::f2(); // compile-time error; same considerations as above

Agree.  No different from f1::x = 5.  You can't look inside of the
function scope.

: > BTW are functions nested within member functions member functions?

: Do we gain anything by making them member functions? I think it would be
: superfluous; local function already has an access to "this" pointer through
: its parent member function.

Everything has access to the "this" pointer via &object.  What are the
rights?  Nestesed class members may not access non-public members of
the enclosing class.  Derived class members may not access private
members of the base class.

: Though it may make sense for pointer
: manipulation since the pointer to member function has a different type, so
: maybe a new keyword can be added to specify member local function.

No new keyword required.  The local function is either a member and
we use pointer to member or it is not and we use normal function
pointer.

All I see is a desire to use Pascal idioms in C++ without the details
of how this will fit into the language.  What are the gains and costs?

John
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/23
Raw View
In article <slrn7lu1vu.ic4.sbnaran@localhost.localdomain>,
  sbnaran@uiuc.edu wrote:
> On 09 Jun 99 20:00:41 GMT, Stanley Friesen
>
> >Actually, I have found little good use for local classes either.
>
> You can use them in template functions.  One alternative is putting
the
> class at namespace scope, but this does not provide strong locality of
> reference.  Another alternative is to use various function objects
from
> <functional>, but the resulting code may be bulky looking.
>
> You can use local classes for fancy iterators.  Eg,
>    void f() { struct I { ... }; for (I i(1,11); i.ok(0); ++i) ; }

In my code, I've used local classes intensively in two cases:

1.  As the return value of a factory method; each distinct factory
    method returns a different derived class.  Obviously, I don't need
    nested classes for this, but in the past, it has been a convenient
    way to avoid a proliferation of class names in which no one was
    interested.  (Today, the unnamed namespace is an alternative.)

2.  For a callback.  In this case, the class often either declares a
    member variable which is used publicly elsewhere in the function, or
    contains references initialized to local variables or parameters.
    Declaring the class outside of the function is awkward.

Of course, in case 2, the class would almost always derive from
__local_context, if __local_context existed.  In many cases,
__local_context would eliminate the need of a constructor, leaving just
the one virtual function which is overridden.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orientie objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/24
Raw View
In article <7k8ori$ra6$1@nnrp1.deja.com>,
  gbush@my-deja.com wrote:
> In article <7k5ssr$pll$1@nnrp1.deja.com>,
>   James.Kanze@dresdner-bank.com wrote:
> >
> > It's important to note that I have *not* done the work necessary to
> > present a formal proposal, and that these are mostly just ideas off
the
> > top of my head.  However, my basic idea is that __local_context
would be
> > defined as containing non-const references to all visible local
> > variables and parameters, with the same name as the variable, and
> > initialized to refer to the variable.  I'm not sure whether these
> > members should be protected or public -- I think I rather favor
> > protected.  And of course, this just defines the semantic; most
> > compilers will be able to implement the actual accesses directly,
> > without the intervening reference.

> Though I like the idea of local context, it doesn't seem very clear
how
> it should be defined. Why const references are not to be included in
> __local_context?

Good point.  The class should contain non-const references to non-const
visible objects, and const references to const visible objects.

Note that the use of references is only to explain the semantics.  I do
not expect the compiler to actually implement it this way.  (Or better
said, I expect that in this particular case, the references take zero
memory.)

> Then you may need to have more than one local context if you have more
> than one local class. For example,
> void f()
> {
>   int i1;
>   // __local_context1 includes i1
>   struct S1: __local_context1 {} s1;
>   int i2;
>   // __local_context2 includes i1, s1, i2
>   struct S2: __local_context2 {} s2;
>   // and what kind of __local_context
>   // the following class inherited
>   struct S3: S1 {}; // ???
> }
> It's certainly not a good idea to have multiple __local_context
classes.
> Therefore there should be one __local_context class but it's contents,
> so to speak, is changing depending where it is used. So it's not
really
> a class in C++ definition, but some kind of pseudo-class.

Each use of __local_context defines a new (nameless) class.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orientie objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/06/23
Raw View
David R Tribble <dtribble@technologist.com> wrote:

: John Potter wrote:

: [reformatted for clarity]:

I can't read it any more.  Doesn't fit on screen. :)

: I disagree; I don't think it makes much sense to call or pass a
: pointer to a local function to functions outside its scope (i.e,
: outside its enclosing function).  It's analogous to passing pointers
: to local structures to other functions outside the function containing
: the structure declaration.

Disallow passing address of a local int too?  A structure is a
complete type a function is just a prototype.  Pointer to function
with a given prototype does not need the name.  A structure is a
type and has a name.  Two structure types with the same layout
have different types.  Two functions with the same prototype have
the same pointer type.

: > BTW are functions nested within member functions member functions?

: Good question.  If so, should they be declared somewhere in the class
: declaration?

Hum.  The fog is getting thicker.  No, it would be inconsistent to
declare something inside of something else.  That would be like a
forward declaration of a nested class or member function.  Another
thread is running on that subject.

: P.S.  I personally don't see any need for nested functions.  Still,
: they make for an interesting discussion in language design.

Me either.  Real nested functions have been around a long time in
several languages.  I don't think that your watered down versions
will provide anything of interest.  They could not be used as
call-backs with context which was the original poster's desire.

John
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1999/06/23
Raw View
Stanley Friesen [Contractor] wrote:
>
> In article <7k0b01$nod$1@panix.com>,
> Greg Comeau <comeau@comeaucomputing.com> wrote:
> >scope is a syntactic thing.  It doesn't apply to a running program
> >in the same sense.
>
> True - but there is this little rule that variables of automatic *duration*
> are destroyed on exit from their scope.

Not on exit from their scope, but on exit from the block they are
defined in. You can have one without the other by executing a
subroutine; the block hasn't exited yet, but while the subroutine is
executing, the variable isn't in scope.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Lisa Lippincott <lisa_lippincott@advisories.com>
Date: 1999/06/23
Raw View
James Kanze <James.Kanze@dresdner-bank.com> asks:

> Just a question of vocabulary, but what is a closure, exactly.  I've
> always thought that, in layman's terms, it extended the life of the
> local context beyond the return from the function.  I think that this is
> how it works in lisp (but my lisp experience is limited to customizing
> emacs, so I'm not sure).  And of course, Borland has invented a totally
> different meaning.  What you are describing would seem to be closure as
> I understand it, but without the extended lifetime.

There's a common meaning to all of these uses of "closure": a closure
is a new function created by fixing some of the parameters to an
existing function.  Thus the one-parameter function "add three" is a
closure of the two-parameter function "add."

The confusion you express comes from interpreting "closure" in radically
different environments.  Lisp's rules of scope (functions may access
objects defined in their callers) and lifetime (if it's accessible, it's
alive) give Lisp's closures properties which seem bizzare from a C++
point of view.

                                             --Lisa Lippincott
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: gbush@my-deja.com
Date: 1999/06/23
Raw View
In article <7k5ssr$pll$1@nnrp1.deja.com>,
  James.Kanze@dresdner-bank.com wrote:
>
> It's important to note that I have *not* done the work necessary to
> present a formal proposal, and that these are mostly just ideas off
the
> top of my head.  However, my basic idea is that __local_context would
be
> defined as containing non-const references to all visible local
> variables and parameters, with the same name as the variable, and
> initialized to refer to the variable.  I'm not sure whether these
> members should be protected or public -- I think I rather favor
> protected.  And of course, this just defines the semantic; most
> compilers will be able to implement the actual accesses directly,
> without the intervening reference.
>
Though I like the idea of local context, it doesn't seem very clear how
it should be defined. Why const references are not to be included in
__local_context?
Then you may need to have more than one local context if you have more
than one local class. For example,
void f()
{
  int i1;
  // __local_context1 includes i1
  struct S1: __local_context1 {} s1;
  int i2;
  // __local_context2 includes i1, s1, i2
  struct S2: __local_context2 {} s2;
  // and what kind of __local_context
  // the following class inherited
  struct S3: S1 {}; // ???
}
It's certainly not a good idea to have multiple __local_context classes.
Therefore there should be one __local_context class but it's contents,
so to speak, is changing depending where it is used. So it's not really
a class in C++ definition, but some kind of pseudo-class.
Gene.

Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Lisa Lippincott <lisa_lippincott@advisories.com>
Date: 1999/06/18
Raw View
Fergus Henderson <fjh@cs.mu.OZ.AU> wrote:

> It's not necessary to create trampolines "on the fly".  You can
> allocate a stack of trampolines statically (at link time, for example),
> and allocate trampolines from this stack as needed.  They can be
> deallocated when the containing scope is exited.
>
> You don't need to be able to write to code space, because
> you can keep the data parts and the code parts of the trampoline
> stack in separate parallel arrays.

I don't see how the number of trampolines needed can be bounded
at link time.  Consider a recursive function:

typedef int(*IntFunction)();
std::vector<IntFunction> localFunctions;
typedef std::vector<IntFunction>::const_iterator iterator;

int UseManyTrampolines( int n )
  {
   if ( n > 0 )
     {
      int GetN() { return n; }
      localFunctions.push_back( &GetN );
      return UseManyTrampolines( n - 1 );
     }
    else
     {
      int sum = 0;
      for ( iterator toCall = localFunctions.begin();
            toCall != localFunctions.end();
            toCall++ )
          sum += (**toCall)();
      return sum;
     }
  }

                                                   --Lisa Lippincott
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/06/18
Raw View
Lisa Lippincott <lisa_lippincott@advisories.com> writes:

>Fergus Henderson <fjh@cs.mu.OZ.AU> wrote:
>
>> It's not necessary to create trampolines "on the fly".  You can
>> allocate a stack of trampolines statically (at link time, for example),
>> and allocate trampolines from this stack as needed.  They can be
>> deallocated when the containing scope is exited.
>>
>> You don't need to be able to write to code space, because
>> you can keep the data parts and the code parts of the trampoline
>> stack in separate parallel arrays.
>
>I don't see how the number of trampolines needed can be bounded
>at link time.  Consider a recursive function:

The number of trampolines can't be bounded at link time, in general,
but neither can the normal call stack usage.  Many many C implementations
have had a fixed-size stack.  So the situation here is no worse.
In both cases, the implementation can easily provide some method for the
programmer to select what size stack they need.

Of course, for the vast majority of implementations it's possible to
create code at run-time.  The growing importance of JIT compilers and
dynamic linking suggest that this is likely to remain true in the future.
So most implementations won't need to use fixed-size stacks.

In addition, on implementations with appropriate virtual memory support,
you can create an unbounded size trampoline stack without creating any
new code at runtime, by mapping the same code page into multiple places
in the address space.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Dave Abrahams" <abrahams@mediaone.net>
Date: 1999/06/18
Raw View
In article <7kcjai$l9u$1@mulga.cs.mu.OZ.AU> , fjh@cs.mu.OZ.AU (Fergus
Henderson) wrote:

> In addition, on implementations with appropriate virtual memory support,
> you can create an unbounded size trampoline stack

Even virtual memory is bounded, and people bump up against these bounds in
real life. Often the effective size of the VM space is in fact bounded by
the amount of real memory underlying it ;)

I do wish we all (especially OS designers) could keep that in mind!

-Dave


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "G.B." <gb@home.nospam.net>
Date: 1999/06/18
Raw View
Dimitrios Souflis <dsouflis@altera.gr> wrote in message
news:7kb2kk$hg5$1@medousa.forthnet.gr...
> You are implying that only *one* invocation of a local function can be
> active
> at any one time. This can only be verified with a global analysis, it's
> really
> an akward rule for a language supporting separate compilation.
You are right about that. When I thought about that implementation I didn't
take into account possible recursive calls. But common implementation of a
trampoline for local function works perfectly well with recursive calls. So
the point still stands - it's not difficult to implement local functions in
one way or another.
Gene.



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James.Kanze@dresdner-bank.com
Date: 1999/06/18
Raw View
In article <7kbdbl$65m@abyss.West.Sun.COM>,
  stanley@West.Sun.COM (Stanley Friesen [Contractor]) wrote:

    [...]
> >A bit more to type, but it allows the user (someFunc) to maintain
state
> >(not used in this example).  Of course, this also requires an
extension
> >in order to work.  (Without the extension, the nested class is
> >significantly more complicated.)
>
> How is maintaining an explixit reference to the required auto variable
> significantly more complex?

Without the extension, the local class requires a constructor and a data
member -- doing it correctly also requires both public and private
sections.  With the extension, the local class is a single function.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orientie objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <dtribble@technologist.com>
Date: 1999/06/19
Raw View
James.Kanze@dresdner-bank.com wrote:
>
> David R Tribble <dtribble@technologist.com> wrote:
> > I disagree; I don't think it makes much sense to call or pass a
> > pointer to a local function to functions outside its scope (i.e,
> > outside its enclosing function).  It's analogous to passing pointers
> > to local structures to other functions outside the function
> > containing the structure declaration.
>
> In short, something which is both legal and moderately frequent.

Not in my code it's not.  I sometimes pass around pointers to opaque
types (generally as polymorphic pointers or simply 'void*' pointers),
but I have never had cause to return a pointer to a local struct.
Perhaps I'm just not that experienced in object-oriented programming
paradigms...

-- David R. Tribble, dtribble@technologist.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/06/20
Raw View
"Dave Abrahams" <abrahams@mediaone.net> writes:

>fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
>
>> In addition, on implementations with appropriate virtual memory support,
>> you can create an unbounded size trampoline stack
>
>Even virtual memory is bounded,

Sorry, you are of course correct -- "unbounded" was not quite the right word,
I should have said "bounded only by the size of the virtual memory".

But I think your point is irrelevant to the consideration of whether
or not nested functions should be or should have been included in the
C or C++ standards.  Any program's memory use will be limited by the
size of virtual memory -- the separate trampoline stack that might be
needed (on systems which don't allow creating code at runtime) should
not make things any worse in that respect.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <dtribble@technologist.com>
Date: 1999/06/21
Raw View
Fergus Henderson wrote:
>
> "Dave Abrahams" <abrahams@mediaone.net> writes:
>
> >fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
> >
> >> In addition, on implementations with appropriate virtual memory
> >> support, you can create an unbounded size trampoline stack
> >
> >Even virtual memory is bounded,
>
> Sorry, you are of course correct -- "unbounded" was not quite the
> right word, I should have said "bounded only by the size of the
> virtual memory".
>
> But I think your point is irrelevant to the consideration of whether
> or not nested functions should be or should have been included in the
> C or C++ standards.  Any program's memory use will be limited by the
> size of virtual memory -- the separate trampoline stack that might be
> needed (on systems which don't allow creating code at runtime) should
> not make things any worse in that respect.

It would probably complicate code generation for embedded systems,
which typically have very constrained memory resources.  OTOH,
implementors could simply refuse to add nested functions to EC++.

-- David R. Tribble, dtribble@technologist.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/06/16
Raw View
David R Tribble <dtribble@technologist.com> wrote:

: No one's addressed the problem of what happens when a local function
: is invoked through a pointer after its outer function's scope has
: ended.  Is this simply undefined behavior?  Is an exception thrown?

No problem.  If the function accesses its outer function's context
that is undefined behavior just like returning a reference to local
context.  Exceptions?  Since it is undefined behavior, anything could
happen :)

: My restriction avoids this whole problem.

By making local functions useless.  Baby and bathwater?

: It also makes the implementation of local function pointers much
: simpler

No, it complicates the issue by creating an unneeded new type.  A
local function pointer is just a function pointer.  See below.

: My guess is that nested functions would be no more harder to
: implement than exception handling.

Good point.  Likely easier, lots of history to use.

: Oh, and by the way, how do nested functions complicate exception
: handling?  No one's discussed that either.

They are just functions, no change.

: A nested function requires a slightly more complex invocation frame,
: called a "display" (see chap.7 of the Red Dragon compiler book),
: which allows it to access its outer function's local variables (to
: any arbitrary nesting level) in addition to its own local variables.

Now the clincher.  Normal functions are nested to level zero.  They
have access to the global context as well as their own.  All
functions are nested functions.

Now you have the context.  Is the cost of the display for all
functions justified by the gains of the feature?  There have been
statements that the cost can be reduced to almost nothing and
possibly nothing when not used.

There are likely some unasked and/or unanswered questions, but the
type of pointer to local function is not one of them for anyone
else.  Those who want them have uses for them and normal function
pointers are a requirement for those uses.

John
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Jerry Leichter <jerrold.leichter@smarts.com>
Date: 1999/06/16
Raw View
| Just a question of vocabulary, but what is a closure, exactly.  I've
| always thought that, in layman's terms, it extended the life of the
| local context beyond the return from the function....

Not quite.

Let's, for simplicity, ignore statements and consider a language that
has only expressions.  One could imagine changing C++ to allow this - in
fact, GCC already has a form for "wrapping" an expression around any
statement - ({ ... }) or something like that.

If you look at an expression *in isolation* and list all the variables
that occur within it, you find that they fall into one of two classes.
Some of the variables are "bound" - that is, they are declared within
the expression itself, so are in effect simply placeholders.  In fact,
in a language without side-effects (like variable assignment) you could
eliminate the bound variables entirely by just replacing each by its
value.  In a language *with* side-effects, you generally imagine that,
in evaluating the expression, you first create a stack frame with a slot
for each such bound variable; and then when you're done with the
evaluation you discard the stack frame.

The remaining variables in the expression are "free".  To determine
their referents, you have to look at the environment in which the
expression is used.  In a language with static (or lexical) scopes, like
C++, "is used" means "lexically appears":  The rule is that you look at
surrounding, nested scopes out to the encompassing class (if any) and
then finally out to global variables.  Note that lexical scopes aren't
really "static", since variables that are bound by a function call are
bound to *an instance* of the call - otherwise, recursion wouldn't work.
(In FORTRAN, the binding really *can be* static:  A function has exactly
one set of local variables, shared by all recursive instances - so
recursion *does not* work, and indeed is illegal - though I gather
recent FORTRAN standards - and certainly many FORTRAN implementations -
have allowed it for years.)

(I remarked in an earlier message that LISP's prior to Scheme didn't do
this.  In fact, they used *dynamic binding*:  If a function definition
had free variables, their values were bound *at the point of call*.)

Anyhow:  The *closure* of an expression at a given point in the program
is the expression plus bindings for all its free variables, as
determined at that point.  That's the logical definition:  It's all the
information needed to evaluate the expression in any allowed context.
Nothing is stated about how that information is organized.  If you
simply pass local functions implemented the traditional way "downward",
the necessary information is (a) a pointer to the stack frame in which
each the function was declared; (b) a backpointer in each stack frame to
the previous one; (c) for each free variable in the function's
expression, a stack frame indication - typically a count for how many
stack frames back the binding occurs - and a frame number.

Now, it's true that the term "closure" isn't often used in this context,
because people didn't historically think of the information that way.
Where it gets interesting is where the closure "escapes" - i.e., where
the expression/local function is somehow made available outside the
(nested) scope in which it was originally declared.  To support that,
you have to actually "capture" the information somehow - typically by
moving the stack frame into the heap.  It's only at the point you do
that that it becomes obvious that there really is such a thing as a
"closure" that exists as a separate entity.
       -- Jerry
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/06/16
Raw View
James.Kanze@dresdner-bank.com wrote:

: The most essential use of nested functions requires precisely that they
: access local variables:

:     double
:     integrate( double (*pf)( double ) )
:     {
:         //  ...
:     }

:     double
:     someFunc( double a )
:     {
:         double localFunc( double x ) { return a * x ; }
:         return integrate( &localFunc ) ;
:     }

: That's with Pascal-like local functions.  Show me a program that does
: this in C++, and I'll show you a program which is significantly longer
: and more complex.

Assuming that you purposely picked an example which was trivial to
modify, I will do it and give you a chance to restate your case.
I moved one line and added a few characters to three lines.  This
does not qualify as significantly longer.  I will give you more
complex (noting absence of significantly here).  The added visible
coupling shows in integrate while it was invisible in the original.

    double
    integrate( double (*pf)( double ), double& c )
    {
        //  ...
    }

        double localFunc( double x, double& a ) { return a * x ; }
    double
    someFunc( double a )
    {
        return integrate( &localFunc, a ) ;
    }

I can write off that complexity as a standard idiom.  Of course the
real increase in length and complexity comes when the context to be
transfered is non-trivial.  Templates can help with that.

I also agree that the functor idiom is an alternative for C++.  I
don't see the need for the extension you presented.  It is convient
to use it locally, but I can manage with it global.

All of these alternatives become much more difficult when the nesting
level increases.  That could be a good thing and maybe the best
argument against nested functions.

All I have seen is nice but not convincing.  I look forward to an
answer from Steve to your question elswhere on closures.

John
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/16
Raw View
In article <3mP93.15224$uk.221592@newscene.newscene.com>,
  jpotter@falcon.lhup.edu (John Potter) wrote:
> James.Kanze@dresdner-bank.com wrote:
>
> : The most essential use of nested functions requires precisely that
they
> : access local variables:
>
> :     double
> :     integrate( double (*pf)( double ) )
> :     {
> :         //  ...
> :     }
>
> :     double
> :     someFunc( double a )
> :     {
> :         double localFunc( double x ) { return a * x ; }
> :         return integrate( &localFunc ) ;
> :     }
>
> : That's with Pascal-like local functions.  Show me a program that
does
> : this in C++, and I'll show you a program which is significantly
longer
> : and more complex.
>
> Assuming that you purposely picked an example which was trivial to
> modify, I will do it and give you a chance to restate your case.
> I moved one line and added a few characters to three lines.  This
> does not qualify as significantly longer.  I will give you more
> complex (noting absence of significantly here).  The added visible
> coupling shows in integrate while it was invisible in the original.
>
>     double
>     integrate( double (*pf)( double ), double& c )
>     {
>         //  ...
>     }
>
>         double localFunc( double x, double& a ) { return a * x ; }
>     double
>     someFunc( double a )
>     {
>         return integrate( &localFunc, a ) ;
>     }
>
> I can write off that complexity as a standard idiom.  Of course the
> real increase in length and complexity comes when the context to be
> transfered is non-trivial.  Templates can help with that.

You missed the point.  The function integrate is used in many different
locations; the additional parameter is of varying types, etc.  Of
course, I could make integrate a template function, but if the code is
anything but trivial, this leads to unreasonable code bloat.

And of course, for all I know, integrate could be in a third party
library, to which I don't have the sources.  (IMHO, in such cases, in
C++, a functor should be used.  In C, an additional void* parameter
should be provided, precisely for passing such context.  But in
practice, at least in the few libraries I've seen, this has not been the
case.)

> I also agree that the functor idiom is an alternative for C++.  I
> don't see the need for the extension you presented.  It is convient
> to use it locally, but I can manage with it global.
>
> All of these alternatives become much more difficult when the nesting
> level increases.  That could be a good thing and maybe the best
> argument against nested functions.

I totally agree that it is a feature which can be misused.  I've seen
what people are doing with inner classes in Java -- it's like the early
days of operator overloading in C++, before the word got out that
operator overloading was only good if the overloaded operators did
something similar to what the built-in operator did.

But since when is the argument that something can be misused been a
valid argument for C++?

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <dtribble@technologist.com>
Date: 1999/06/17
Raw View
Christopher Eltschka wrote:
>
> David R Tribble wrote:
>
> [...]
>
> > >> P.S.  I personally don't see any need for nested functions.
> > >
> > > I do. (It's true no single language feature is have-it-or-die,
> > > though.)
> >
> > Please provide a convincing example; no one's done that yet.
>
> One from real life:
>
> extern "C"
>  void fortran_integration_routine_(double(*)(double&),
>                                    int const& start, int& end,
>                                    double const& prec,
>                                    double& result);
>
> double calc_something(double param1, double param2)
> {
>   // I wish I had this
>   double foo(double& pd)
>   {
>     return param1 + pd*param2;
>       // of course, the real function was more complex
>   }
>   double result;
>   fortran_integration_routine_(&foo, 1, 3, 1e-10, result);
>   return result;
> }
>
> Of course, the real function was much more complex (and the
> integral was two-dimensional, so the integration was called
> recursively).

Ignoring for the moment the problems of integration with FORTRAN
subroutines, why not use a functor that stores the 'pd' parm as part
of its state?:

    double calc_something(double param1, double param2)
    {
        struct Functor
        {
            double      p1;
            double      p2;

                        Functor(double a, double b):
                            p1(a), p2(b)
                        { }

            double      operator ()(double pd)
                        { return p1 + pd*p2; }
        };

        result = integration_routine(
                     Functor(param1, param2), 1, 3, 1e-10);
        return result;
    }

Hooking this into FORTRAN adds another dimension to the problem,
of course.  But I don't think we should resort to adding nested
functions to C++ just to solve that particular problem.

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/06/17
Raw View
James.Kanze@dresdner-bank.com wrote:

: In article <3mP93.15224$uk.221592@newscene.newscene.com>,
:   jpotter@falcon.lhup.edu (John Potter) wrote:

: > I can write off that complexity as a standard idiom.  Of course the
: > real increase in length and complexity comes when the context to be
: > transfered is non-trivial.  Templates can help with that.

: You missed the point.  The function integrate is used in many different
: locations; the additional parameter is of varying types, etc.  Of
: course, I could make integrate a template function, but if the code is
: anything but trivial, this leads to unreasonable code bloat.

The function integrate accepts only one type of function pointer.  I
doubt that there would be many types of additional parameter.  In fact,
a double** would likely cover almost all cases.  That would add one
line to the outer function to declare and initialize the C array of
double* and add some ugly [] and * to the inner function.  Adding
arrays of references to the language would solve that problem. :)

: And of course, for all I know, integrate could be in a third party
: library, to which I don't have the sources.  (IMHO, in such cases, in
: C++, a functor should be used.  In C, an additional void* parameter
: should be provided, precisely for passing such context.

Yes, that's what I meant by standard idiom.

: But in
: practice, at least in the few libraries I've seen, this has not been the
: case.)

That statement excludes the standard library, I assume, from the earlier
use of third party.

"My great libraries are broken, let's fix the language."  I'm not
sure that you said that, but I was able to read that. <g>

: > I also agree that the functor idiom is an alternative for C++.  I
: > don't see the need for the extension you presented.  It is convient
: > to use it locally, but I can manage with it global.
: >
: > All of these alternatives become much more difficult when the nesting
: > level increases.  That could be a good thing and maybe the best
: > argument against nested functions.

: I totally agree that it is a feature which can be misused.  I've seen
: what people are doing with inner classes in Java -- it's like the early
: days of operator overloading in C++, before the word got out that
: operator overloading was only good if the overloaded operators did
: something similar to what the built-in operator did.

: But since when is the argument that something can be misused been a
: valid argument for C++?

Never.  There are; however, examples of making it hard to misuse.
Functions return rvalues which may only be bound to const&.  We
know how to bypass that but it requires action not accident.  I
seem to remember other examples in D&E where decisions were made
that the added feature could be done otherwise and adding it to
the language would encourage poor practice.  I agree that this
argument is only a very small piece of the picture with little
weight.  But, not invalid.  I give it more weight than returning
a pointer to the nested function from the enclosing function.

Maybe callback with context is a pattern and all patterns are produced
to compensate for a missing language feature.  To date, that is the
only argument that I have seen in this thread.  The original poster
even complained about a few lines needed to use Borland's closure.
I'm satisfied with the idiom/pattern; however, there may yet be
something said on the formal closure to enlighten me.

John
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <dtribble@technologist.com>
Date: 1999/06/17
Raw View
Christopher Eltschka wrote:
>
> David R Tribble wrote:
>> What is hard is adding yet another kind of function pointer, which
>> allows the compiler to properly invoke a pointed-to local function
>> so that its invocation frame is properly constructed.  I'm led to
>> the conclusion that the compiler needs to know it's a local
>> function pointer, distinct from a "normal" function pointer, so that
>> this can occur; this implies a new syntax for distinguishing between
>> the two kinds of pointers.  (I already suggested the syntax
>> '({}::* fp)()' in another post.)  Such a pointer must contain extra
>> information such as the number of nesting levels needed by the
>> pointed-to function's display; perhaps such a pointer points to
>> a static "display descriptor" which contains such information,
>> much like an object's _vtbl pointer points to a static "class
>> descriptor table".
>
> This is the most obvious solution. However, another solution exists
> which encodes the extra information not in the pointer itself, but
> in the code it points to, which is a dynamically created trampoline.
> That solution has the advantage that you can use normal function
> pointers, and pass them to non-C++-functions.

There are undoubtedly architectures upon which you cannot create
trampolines "on the fly".  So this solution is probably not
suitable for the standard.  That's one reason I'm led to believe,
still, that nested function pointers are inherently different
critters than regular function pointers.

(And I still don't think nested functions are that useful.
So there.)

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/06/17
Raw View
David R Tribble <dtribble@technologist.com> writes:

>Christopher Eltschka wrote:
>>
>> [...] another solution exists
>> which encodes the extra information not in the pointer itself, but
>> in the code it points to, which is a dynamically created trampoline.
>> That solution has the advantage that you can use normal function
>> pointers, and pass them to non-C++-functions.
>
>There are undoubtedly architectures upon which you cannot create
>trampolines "on the fly".

It's not necessary to create trampolines "on the fly".  You can
allocate a stack of trampolines statically (at link time, for example),
and allocate trampolines from this stack as needed.  They can be
deallocated when the containing scope is exited.

You don't need to be able to write to code space, because
you can keep the data parts and the code parts of the trampoline
stack in separate parallel arrays.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/17
Raw View
In article <37659D89.565ACF7D@technologist.com>,
  David R Tribble <dtribble@technologist.com> wrote:

> I disagree; I don't think it makes much sense to call or pass a
> pointer to a local function to functions outside its scope (i.e,
> outside its enclosing function).  It's analogous to passing pointers
> to local structures to other functions outside the function containing
> the structure declaration.

In short, something which is both legal and moderately frequent.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orientie objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/06/17
Raw View
David R Tribble <dtribble@technologist.com> writes:

>I disagree; I don't think it makes much sense to call or pass a
>pointer to a local function to functions outside its scope (i.e,
>outside its enclosing function).

On the contrary, it is very useful. It's common to see a pattern
like this in Pascal (but I'll use C++ syntax):

int main()
{
    void dosomething( bool(*fp)(int), int k )
    {
 ...
 if( fp(k) ) // call the callback function
     ...
 else
     ...
    }

    void process1()
    {
 ... decls

 bool getdata(int i) // the callback for process1
 {
     ...
 }

 ...

 dosomething(getdata);
    }
    ...
}

Function dosomething has a callback that uses its own context.
It can be called from outside the scope of the callback's
enclosing function.

The difference between C++ and Pascal is that Pascal does not
have free pointers to functions. A function can be passed to
another function, but saved in a variable. Consequently, you
cannot call a function with a function whose enclosing scope has
been exited. In C++, that programming error becomes possible.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/06/17
Raw View
stanley@West.Sun.COM (Stanley Friesen [Contractor]) writes:

>In article <7jvh45$5ms$1@engnews1.eng.sun.com>,
>Steve Clamage <clamage@eng.sun.com> wrote:
>>"G.B." <gb@web1.ucar.edu> writes:
>>
>>>John Potter <jpotter@falcon.lhup.edu> wrote in message
>>
>>>You can have a var of that type anywhere. I only meant it is useless outside
>>>of the scope of parent function.
>>
>>Huh? You can do it in Pascal, for example.
>>
>>But using it outside the scope of the parent function would
>>be the only point of having local funcitons in C++, it seems
>>to me.

>I think you and John are meaning different things by "outside the
>scope of the parent function".  He took it to mean "the scope of the
>parent function has ended due to the function returning".  In that case
>what he said is *indeed* correct.   And you cannot call nested functions
>like that in Pascal either - the parent function has to be at least *active*.

It doesn't help the discussion to confound the terms "scope"
and "lifetime". They are different concepts.

"Scope" is a static property of the source code. A scope begins
with the declaration of a name and ends with the block in which
it is declared.

"Lifetime" is a dynamic property of the executing code. Lifetime
begins when the flow of control passes through a definition, which
might be never. Lifetime ends according to the flow of control and
the category of the thing: static object, auto object, function.
For a namespace-scope object, or an auto object in a function that
calls no other functions, the scope and lifetime coincide, if
space and time can be said to coincide.  Otherwise, scope and
lifefime are different.

I know that John would not ordinarily confuse these concepts,
although it would appear that some others participating in the
thread have done so.  I assumed John meant what he said.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stanley@West.Sun.COM (Stanley Friesen [Contractor])
Date: 1999/06/18
Raw View
In article <7k6063$r86$1@nnrp1.deja.com>,
 <James.Kanze@dresdner-bank.com> wrote:
>The fact that a particular functionality can be misused is not an
>argument, at least not if there is no convienient way of getting that
>functionality otherwise.

I essentially agree, my argument was not purely that it can be misused.

Rather, I see little added functionality in nested functions.  Certainly not
enough to justify them in the face of the issues they bring up.
>
>The most essential use of nested functions requires precisely that they
>access local variables:
>
>    double
>    integrate( double (*pf)( double ) )
>    {
>        //  ...
>    }
>
>    double
>    someFunc( double a )
>    {
>        double localFunc( double x ) { return a * x ; }
>        return integrate( &localFunc ) ;
>    }
>
>That's with Pascal-like local functions.  Show me a program that does
>this in C++, and I'll show you a program which is significantly longer
>and more complex.
>
Not all that much longer:
template<class X>
double integrate( X &pf )
{
    // ...
}

namepace {  // The only reason localClass is here is because one cannot
     // instantiate the above template on a true local class.
    class localClass // this class could probably be a template, as
       // it is so uniform.  Indeed it is close to the
       // binder classes in the standard library.
    {
         public:
             double operator()(double x) { return mya*x; };
             localClass(const double &ra): mya(ra) {};
         private:
             const double &mya;
    };
}

double someFunc( double a )
{
    localClass lf(a);
    return integrate( lf );
}

>But: IMHO, the interface of integrate is *not* what I would expect of a
>C++ function.  Generally, I would expect a functional object:

Naturally.

>A bit more to type, but it allows the user (someFunc) to maintain state
>(not used in this example).  Of course, this also requires an extension
>in order to work.  (Without the extension, the nested class is
>significantly more complicated.)

How is maintaining an explixit reference to the required auto variable
significantly more complex?
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "G.B." <gb@web1.ucar.edu>
Date: 1999/06/13
Raw View

Steve Clamage <clamage@eng.sun.com> wrote in message
news:7jrv0r$dfq$1@engnews1.eng.sun.com...
>
> Function f is not visible outide this translation unit, yet
> can be called from other translation units via pf. Varible
> k is not visible outside function foo, yet can be accessed
> even from other translation units via pi.
>
Ah, the quirks of C. I have better used the word accessible instead of
visible. Sorry, I'm just a software engineer so my terminology is not very
precise.
The difference between local and global fiunctions is that the first can
access local variables (including parent function parameters) in the scope
where they are defined. These local variables simply do not exist when you
leave the scope, so calling local function out of it parent's scope doesn't
make sense.

> C++ has enough different scope control mechanisms you don't need
> local functions the way you need them in, say, Pascal. The
> primary reason to have local functions in C++ would be to
> implement closures. If you just want to share state among
> cooperating functions, use a class. The code will be simpler
> and easier to maintain.
As the saying goes one can solve every problem with just one more level of
indirection. But in practice its not that simple. A typical example where
local functions are widely used in Pascal is internal iterator- in many
cases they are simpler and more convenient than external iterators. Using
C++ hypothetical syntax it looks like this:

typedef void (*local_function_type)(T& t); // T container element type
class Container
{  public:
   void ForEach(local_function_type f) { for(...) f(t); };
   void DoSomethingToAll(/* function parameters */);
};
void Container::DoSomethingToAll(/* function parameters */)
{
  // local variables
  void DoSomethingToOne(T& t) { /* use t, local variables and function
parameters */ }
  ForEach(DoSomethingToOne);
}
Pascal gives sleek and easy solution. What do you do in C++ in this
situation? Define a global abstract class, define a local class inherited
from it, copy all parameters to the local class, copy function parameters,
create an object  - only to be able to call a single function.

struct local_abstract_class { virtual void DoSomethingToOne(T& t) =0 };
class Container
{  public:
   void ForEach(local_abstract_class& lc) {  for(...)
lc.DoSomethingToOne(t); }
   void DoSomethingToAll(/* function parameters */);
};

void Container::DoSomethingToAll(/* function parameters */)
{
  struct local_parameters { ... } lp;
  struct local_class: public local_abstract_class
  {  ...
     local_class(/* function parameters and  local parameters */);
     virtual void DoSomethingToOne(T& t) { /* use t, local parameters and
function parameters */ }
  } lc(/* function parameters and  local parameters*/);
  ForEach(lc);
}

Now imagine that you need more than one local function - you define another
similar class,etc; you code becomes messier and uglier and slower. Is it why
internal iterators are so unpopular in C?
Now I'm voting with both hands to add closure concept to C++, they are
great. I simply say that local functions is a different beast. Closures, at
least the way they are implemented in Borland compiler, can simplify the
solution of above problem, but you still need a local class, and simple
local functions are still better. And they are easier to implement than
closures.
It's actually not the task of the standard to specify the implementation,
it's enough to introduce a concept. But implementation of local functions
can also be simple, for example: create a table in the data segment with
just one entry for each local function. This entry contains a pointer to the
local context in the stack segment, through which local function can access
local variables and parent function parameters.
Or reserve one pointer in the code segment with each local function for the
same purpose (it may not work if data are not allowed in code segment).
The parent function initializes pointer on entry and resets it before
return. In this way local functions can throw exception if called out of
their scope and don't need any special type of pointer to access them.
Gene.



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/06/13
Raw View
gbush@my-deja.com wrote:

: I think there should be no differences in pointers to the local
: function or to the global function. They should have exactly the same
: signatures, so that any function that recieves function pointer could
: call equally successfully local and global function through that
: pointer. Since local functions are visible only in the scope where they
: are defined such a call could be made only from the same scope.

I don't understand your use of scope.  Consider:

void f1 (void (*g)()) { void f2 () { g(); } f2(); }
void f3 () { void f4 () { printf("Hi\n"); } f1(f4); }

This must work.  You may test it with egcs which supports nested
functions for C.

BTW are functions nested within member functions member functions?

John



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: comeau@panix.com (Greg Comeau)
Date: 1999/06/13
Raw View
In article <081650426190c69CPIMSSMTPU07@email.msn.com> "G.B." <don't.even.think.about.it@isgate.is> writes:
>
>
>Steve Clamage <clamage@eng.sun.com> wrote in message
>news:7jrv0r$dfq$1@engnews1.eng.sun.com...
>>
>> Function f is not visible outide this translation unit, yet
>> can be called from other translation units via pf. Varible
>> k is not visible outside function foo, yet can be accessed
>> even from other translation units via pi.
>>
>Ah, the quirks of C. I have better used the word accessible instead of
>visible. Sorry, I'm just a software engineer so my terminology is not very
>precise.
>The difference between local and global fiunctions is that the first can
>access local variables (including parent function parameters) in the scope
>where they are defined. These local variables simply do not exist when you
>leave the scope, so calling local function out of it parent's scope doesn't
>make sense.

scope is a syntactic thing.  It doesn't apply to a running program
in the same sense.  So, when you say the local vars do not exist when
you leave the scope, they will if the local function calls a different
function, perhaps passing or having pointers to the local vars.

- Greg
--
       Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418-3214
     Producers of Comeau C/C++ 4.2.38 -- New Release!  We now do Windows too.
    Email: comeau@comeaucomputing.com / Voice:718-945-0009 / Fax:718-441-2310
                *** WEB: http://www.comeaucomputing.com ***
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/06/15
Raw View
"G.B." <gb@web1.ucar.edu> writes:

>John Potter <jpotter@falcon.lhup.edu> wrote in message

>> Now that we have a type for it, there is no reason for not having
>> variables of that type anywhere.

>You can have a var of that type anywhere. I only meant it is useless outside
>of the scope of parent function.

Huh? You can do it in Pascal, for example.

But using it outside the scope of the parent function would
be the only point of having local funcitons in C++, it seems
to me.

Maybe you could explain how local functions that could not be
called from outside the enclosing function scope would be a
useful addition to C++. What programming problems can be solved
more easily? It seems to me that a class with member functions
solves all the same problems, and does a better job of it.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/06/15
Raw View
"G.B." <gb@web1.ucar.edu> writes:

>The difference between local and global fiunctions is that the first can
>access local variables (including parent function parameters) in the scope
>where they are defined. These local variables simply do not exist when you
>leave the scope, so calling local function out of it parent's scope doesn't
>make sense.

Of course it does. That is how you implement a closure. It's
the one nice feature of local functions for which C++ does
not already have an equivalent.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1999/06/15
Raw View
G.B. wrote:
....
> The difference between local and global fiunctions is that the first can
> access local variables (including parent function parameters) in the scope
> where they are defined. These local variables simply do not exist when you
> leave the scope, so calling local function out of it parent's scope doesn't
> make sense.

Just because a function is being called outside the parent's scope
doesn't mean that the parent's scope has ended. In fact, that's exactly
the case in one of the examples you gave:

> void Container::DoSomethingToAll(/* function parameters */)
> {
>   // local variables
>   void DoSomethingToOne(T& t) { /* use t, local variables and function
> parameters */ }
>   ForEach(DoSomethingToOne);
> }

Therefore, the question of whether it's possible/desirable to allow
local function pointers to exist and be interchangable with global
function pointers is very relevant.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "G.B." <gb@web1.ucar.edu>
Date: 1999/06/15
Raw View
John Potter <jpotter@falcon.lhup.edu> wrote in message
news:FqA83.38464$wk2.553149@newscene.newscene.com...
> I don't understand your use of scope.  Consider:
>
> void f1 (void (*g)()) { void f2 () { g(); } f2(); }
> void f3 () { void f4 () { printf("Hi\n"); } f1(f4); }
>
> This must work.  You may test it with egcs which supports nested
> functions for C.

Yes, this must work, and I've never implied the opposite. I think I
experience some problems in communication. So I just give an example of what
should be allowed and what - prohibited:
typedef void (*fptr)();
fptr p_global;

void f1()

  void f2(){} ; // local function defined
  fptr p = f2;    // a pointer taken - ok
  p(); // call f2 thru pointer - ok
  p_global = f2; // can be allowed but error prone
                          // and doesn't have any advantages
                          // over the use of local pointers
  p_global(); // ok
}

void f3() {
  void f4(){};
  p_global(); // run-time error; the local context is different
  f1::f2(); // compile-time error; same considerations as above
  p_global = f4; // dangerous assignment
  p_global(); // ok
}

>
> BTW are functions nested within member functions member functions?

Do we gain anything by making them member functions? I think it would be
superfluous; local function already has an access to "this" pointer through
its parent member function. Though it may make sense for pointer
manipulation since the pointer to member function has a different type, so
maybe a new keyword can be added to specify member local function.
Gene.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <dtribble@technologist.com>
Date: 1999/06/15
Raw View
John Potter wrote:
>
> gbush@my-deja.com wrote:
>: I think there should be no differences in pointers to the local
>: function or to the global function. They should have exactly the
>: same signatures, so that any function that recieves function pointer
>: could call equally successfully local and global function through
>: that pointer. Since local functions are visible only in the scope
>: where they are defined such a call could be made only from the same
>: scope.
>
> I don't understand your use of scope.  Consider:
[reformatted for clarity]:
>
> void f1 (void (*g)())
> {
>     void f2 ()
>     {
>         g();
>     }
>
>     f2();
> }
>
> void f3 ()
> {
>     void f4 ()
>     {
>         printf("Hi\n");
>     }
>
>     f1(f4);
> }
>
> This must work.  You may test it with egcs which supports nested
> functions for C.

I disagree; I don't think it makes much sense to call or pass a
pointer to a local function to functions outside its scope (i.e,
outside its enclosing function).  It's analogous to passing pointers
to local structures to other functions outside the function containing
the structure declaration.

On the other hand, it seems entirely reasonable to pass pointers
to local functions to other functions within the same scope of the
outer function.  Consider this example, which "must" work:

    void outer(int n)
    {
        long    count;

        long fact(long i)
        {
            if (i > 0  and  i < 15)
                return (fact(i-1) * i);
            else
                std::printf("count=%ld\n", count);
                                    // Uses outer::count
            return 1;
        }

        long call(long n, long (*fp)(long i))
        {
            return (*fp)(n);        // Call via func ptr
        }

        // begin outer()
        for (count = 0;  count < 20;  count++)
            std::printf("%ld: %ld\n", count, call(count*2, &fact));
                                    // Uses &func
    }

I'm not passing &fact to anything outside the scope of outer(),
but I am passing &fact to functions within the same scope as
fact().  This seems like a reasonable thing to do with nested
functions, and a reasonable restriction to levy on pointers to
nested functions.

If using the existing syntax for function pointers doesn't
quite solve the compiler writer's problem (since pointers to
nested functions might require different invocation code even
with the restriction I mentioned), then perhaps we could use
something like:

    long two(int n, long ({}::* fp)(long i))
                          ^^^^^
                          Means pointer to nested function

> BTW are functions nested within member functions member functions?

Good question.  If so, should they be declared somewhere in the class
declaration?

P.S.  I personally don't see any need for nested functions.  Still,
they make for an interesting discussion in language design.

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stanley@West.Sun.COM (Stanley Friesen [Contractor])
Date: 1999/06/15
Raw View
In article <7k0b01$nod$1@panix.com>,
Greg Comeau <comeau@comeaucomputing.com> wrote:
>scope is a syntactic thing.  It doesn't apply to a running program
>in the same sense.

True - but there is this little rule that variables of automatic *duration*
are destroyed on exit from their scope.

>  So, when you say the local vars do not exist when
>you leave the scope, they will if the local function calls a different
>function, perhaps passing or having pointers to the local vars.

But if the destructors have been called on them, and the sotrage reused for
some other set of automatic variables (as is allowed upon leaving a function),
then those pointers generate undefined behavior, as they are pointers to
variables after their destructors are called.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/06/15
Raw View
jpotter@falcon.lhup.edu (John Potter) writes:
> BTW are functions nested within member functions member functions?

No. However they do have access to the "this" pointer with which their
containing function was called.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Andrei Alexandrescu <andrewalex@hotmail.com>
Date: 1999/06/15
Raw View
In article <37659D89.565ACF7D@technologist.com>,
  David R Tribble <dtribble@technologist.com> wrote:
> I disagree; I don't think it makes much sense to call or pass a
> pointer to a local function to functions outside its scope (i.e,
> outside its enclosing function).  It's analogous to passing pointers
> to local structures to other functions outside the function containing
> the structure declaration.

I'm afraid you are wrong.
Passing pointers to local functions to the outside is fundamental to
LISP-like languages. One basically cannot program in LISP without that.
Your analogy doesn't hold. One reason is that it's wrong :o). I have
cases when I return pointers to local structs. The point is, local
structs inherit global structs:

class Base { ... };

auto_ptr<Base> f()
{
    class Derived : public Base { ... };
    return auto_ptr<Base>(new Derived);
}

> On the other hand, it seems entirely reasonable to pass pointers
> to local functions to other functions within the same scope of the
> outer function.

IMHO you have a peculiar way of concluding what's reasonable and what's
not. All other participants agree that if local functions will be
allowed, one should be able to pass them to the outside world in a way
or another. The debate is whether/how they fit the general design of
C++, and how they can be implemented.

> P.S.  I personally don't see any need for nested functions.

I do. (It's true no single language feature is have-it-or-die, though.)
The problem is, they are hard to implement in the context of the C++
language.

Andrei



Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <dtribble@technologist.com>
Date: 1999/06/16
Raw View
Andrei Alexandrescu wrote:
>
> David R Tribble <dtribble@technologist.com> wrote:
>> I disagree; I don't think it makes much sense to call or pass a
>> pointer to a local function to functions outside its scope (i.e,
>> outside its enclosing function).  It's analogous to passing pointers
>> to local structures to other functions outside the function
>> containing the structure declaration.
>
> I'm afraid you are wrong.
> Passing pointers to local functions to the outside is fundamental to
> LISP-like languages. One basically cannot program in LISP without
> that. Your analogy doesn't hold. One reason is that it's wrong :o).
> I have cases when I return pointers to local structs. The point is,
> local structs inherit global structs:
>
>    class Base { ... };
>
>    auto_ptr<Base> f()
>    {
>        class Derived : public Base { ... };
>        return auto_ptr<Base>(new Derived);
>    }

But my analogy does hold if inheritance doesn't muddy the waters:

    void foo(what_type? *p)
    { ... }

    void bar()
    {
        struct Local
        { ... };

        Local  loc;
        foo(&loc);    // Doesn't make a lot of sense, since
                      // foo() has no idea what struct Local is
    }

>> On the other hand, it seems entirely reasonable to pass pointers
>> to local functions to other functions within the same scope of the
>> outer function.
>
> IMHO you have a peculiar way of concluding what's reasonable and
> what's not. All other participants agree that if local functions will
> be allowed, one should be able to pass them to the outside world in a
> way or another.  The debate is whether/how they fit the general
> design of C++, and how they can be implemented.

Okay, so I'm alone in my opinion that, just as local functions are
only visible (i.e., callable) from other local functions within the
same outer function, pointers to local functions should be restricted
to being passed/invoked within the scope of their outer function.

No one's addressed the problem of what happens when a local function
is invoked through a pointer after its outer function's scope has
ended.  Is this simply undefined behavior?  Is an exception thrown?
My restriction avoids this whole problem.

It also makes the implementation of local function pointers much
simpler, since the compiler has more knowledge of how to invoke the
functions, knowing that they are pointers to local functions (since
the calls must occur within the scope of the outer function).
(See my discussion of "displays" below.)

>> P.S.  I personally don't see any need for nested functions.
>
> I do. (It's true no single language feature is have-it-or-die,
> though.)

Please provide a convincing example; no one's done that yet.

> The problem is, they are hard to implement in the context of the
> C++ language.

My guess is that nested functions would be no more harder to
implement than exception handling.

Oh, and by the way, how do nested functions complicate exception
handling?  No one's discussed that either.

A nested function requires a slightly more complex invocation frame,
called a "display" (see chap.7 of the Red Dragon compiler book),
which allows it to access its outer function's local variables (to
any arbitrary nesting level) in addition to its own local variables.
A display also handles recursion, allowing the function to call
itself while still maintaining accessibility to the proper level
of local and outer local variables.  This in itself is not hard to
do for C++.

What is hard is adding yet another kind of function pointer, which
allows the compiler to properly invoke a pointed-to local function
so that its invocation frame is properly constructed.  I'm led to
the conclusion that the compiler needs to know it's a local
function pointer, distinct from a "normal" function pointer, so that
this can occur; this implies a new syntax for distinguishing between
the two kinds of pointers.  (I already suggested the syntax
'({}::* fp)()' in another post.)  Such a pointer must contain extra
information such as the number of nesting levels needed by the
pointed-to function's display; perhaps such a pointer points to
a static "display descriptor" which contains such information,
much like an object's _vtbl pointer points to a static "class
descriptor table".

But I still don't think nested functions are that useful.

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/06/16
Raw View
Hyman Rosen <hymie@prolifics.com> wrote:

: jpotter@falcon.lhup.edu (John Potter) writes:
: > BTW are functions nested within member functions member functions?

: No. However they do have access to the "this" pointer with which their
: containing function was called.

Ok, I think you have a reasonable partial answer.  A pointer to the
function nested within a member function would be a normal function
pointer and the function would have no this parameter.

What are its access rights?  What can it do with the containing
functions this pointer?  How about a function nested within a
friend function?  Is it a friend?  A partial friend that can
access its inclosing function's objects but not its own or other
global objects?  It seems that the rights should be the same as
the enclosing function.  I don't see this breaking anything, but
have not given it a lot of thought.

John
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/06/16
Raw View
clamage@eng.sun.com (Steve Clamage) writes:
> Of course it does. That is how you implement a closure. It's
> the one nice feature of local functions for which C++ does
> not already have an equivalent.

No it doesn't. You are confusing closures in garbage-collected languages
with closures in C or C++. In non-garbage-collected languages, stack frames
die when their scope is exited. Period. Local functions which refer to
enclosing variables may be used only while their enclosing scope has not
been exited.

People are asking for local functions in C++ so that they can easily use
STL algorithms without the enormous excess verbiage currently needed.

Only a very small number of people want what you are saying, and some of
those probably don't understand the implications, although I'm sure you do.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: comeau@panix.com (Greg Comeau)
Date: 1999/06/16
Raw View
In article <7k3fr2$7el@abyss.West.Sun.COM> stanley@West.Sun.COM (Stanley Friesen [Contractor]) writes:
>In article <7k0b01$nod$1@panix.com>,
>Greg Comeau <comeau@comeaucomputing.com> wrote:
>>scope is a syntactic thing.  It doesn't apply to a running program
>>in the same sense.
>
>True - but there is this little rule that variables of automatic *duration*
>are destroyed on exit from their scope.

As I recall the post I responded to, the scope was not existed yet,
and hence why I made this point.

>>  So, when you say the local vars do not exist when
>>you leave the scope, they will if the local function calls a different
>>function, perhaps passing or having pointers to the local vars.
>
>But if the destructors have been called on them, and the sotrage reused for
>some other set of automatic variables (as is allowed upon leaving a function),
>then those pointers generate undefined behavior, as they are pointers to
>variables after their destructors are called.

Again, as I recall the original context, this didn't seem to apply
(my point was to raise that no function was left yet as I recall it).

I do completely agree with your points when they apply though.

- Greg
--
       Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418-3214
     Producers of Comeau C/C++ 4.2.38 -- New Release!  We now do Windows too.
    Email: comeau@comeaucomputing.com / Voice:718-945-0009 / Fax:718-441-2310
                *** WEB: http://www.comeaucomputing.com ***
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/16
Raw View
In article <FCwu4M.C3I@research.att.com>,
  ark@research.att.com (Andrew Koenig) wrote:
> In article <7jd4c5$nup$1@nnrp1.deja.com>,  <gbush@my-deja.com> wrote:
>
> > C++ unlike other languages doesn't support nested functions. I
> > understand, bad heredity. But C++ had an opportunity to escape from
> > this predicament by allowing classes inside function body see the
local
> > non-static variables, defined in the outer scope as well as function
> > parameters. For some reason it was not done. I wonder, is there at
> > least one good reason why it is so?
>
> Yes -- the reason is that someone proposed it to the committee,
> the committee talked about it, took a vote, and the proposal lost.

Was this a formal proposal?  When during the standardization process?

I know that I mentioned the idea here (or in comp.lang.c++.moderated)
once or twice, but the first time was, if I recall correctly, about the
time of the first CD -- way to late to consider such a significant
extension.  And of course, I never made a formal proposal, or even an
informal one, to the committee.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/16
Raw View
In article <slrn7lrin4.ajs.sbnaran@localhost.localdomain>,
  sbnaran@uiuc.edu wrote:
> On 8 Jun 1999 21:26:57 GMT, Andrei Alexandrescu
<andrewalex@hotmail.com> wrote:
>
> >I'd like to have local functions even in the limited way C++'s design
> >allows. Local classes should have linkage so one could use smll
functors
> >with for_each etc. without adding many methods to the class.
>
> Fine, I agree with both your points.
>
> But answer this one question.  Should the local functions and local
> classes be able to access the local context?  J Kanze and V Bonnard
> suggested that we have a pseudo-class 'local_context', and the
> local class can derive from 'local_context' if it wishes to access
> the local context.  But how does the local function access the
> local context?

It's important to note that I have *not* done the work necessary to
present a formal proposal, and that these are mostly just ideas off the
top of my head.  However, my basic idea is that __local_context would be
defined as containing non-const references to all visible local
variables and parameters, with the same name as the variable, and
initialized to refer to the variable.  I'm not sure whether these
members should be protected or public -- I think I rather favor
protected.  And of course, this just defines the semantic; most
compilers will be able to implement the actual accesses directly,
without the intervening reference.

And it goes without saying that any access to an instance of the class
(even one allocated with new) after leaving the function is undefined
behavior.  (Question: should new even be allowed for a class derived
from __local_context?  In many ways, I would prefer not, but I think it
has to: you might want to pass it as a parameter to a function which
takes an auto_ptr.)

> Or perhaps the ability of the local class or local
> function to access the local context should be automatic, without
> any need for the pseudo-class?

Not automatic, IMHO.  It adds overhead to the class.  Most of the time,
you don't want it, and it in fact just represents an additional danger.
(Returning a reference or a pointer to the class effectively invalidates
the class members.  And I often return references or pointers to local
classes.)

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/16
Raw View
In article <7jfkcr$na6$1@engnews1.eng.sun.com>,
  clamage@eng.sun.com (Steve Clamage) wrote:
> gbush@my-deja.com writes:
>
> >C++ unlike other languages doesn't support nested functions. I
> >understand, bad heredity. But C++ had an opportunity to escape from
> >this predicament by allowing classes inside function body see the
local
> >non-static variables, defined in the outer scope as well as function
> >parameters. For some reason it was not done. I wonder, is there at
> >least one good reason why it is so?
>
> IMHO, no good reason.
>
> You can have a local class with member functions. In order to
> support that, the compiler has most of the mechanism needed
> to support general nested functions.

You've more experience than I with compilers.  But it would seem that
while the same mechanisms are needed at the parsing level, they are
relatively simple, and that the complexity of nested functions is the
need for passing additional context -- there is an additional run-time
complexity (in the generated code) that is not present in nested classes
as currently defined by the standard.

As for why nested functions are not supported, one of the main reasons I
have always heard was the difficulties involved in supported pointers to
the nested function.  The classical solution is for the pointer to
function to contain in fact two pointers, one to the function, and one
to the calling context.  This means either that all C/C++ pointers to
functions become heavier (you pay for what you don't use), or that
pointers to functions and pointers to nested functions are two different
types.

I believe that Fergus Henderson contests this argument, however.  On
many machines, the pointer to a nested function can be implemented as a
pointer to a trampoline, generated on the fly.  I believe that Fergus
has proven, or claims to have proven, that this solution can always be
made to work.

> I once argued that this situation makes no sense. Either nested
> functions should be supported, or local classes should not be
> allowed to have user-defined member functions. That is, the
> member functions in local classes add considerable complexity
> to the compiler for a feature that is not very useful and is
> seldom used.

Well, I've used them rather often.  In many cases, the main reason for
nesting was simply to limit namespace pollution, but not always.  And
more than once, I've transferred part of the local context to the class,
by declaring references in them which were initialized to local
variables.  (This is awkward.  You have to declare the reference as a
data member.  You have to provide a constructor to initialize it.  And
whenever you instantiate the class, you have to pass the local variable
to the constructor.)

In almost all cases, the local class derived from a non-local abstract
class.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/16
Raw View
In article <7jrv0r$dfq$1@engnews1.eng.sun.com>,
  clamage@eng.sun.com (Steve Clamage) wrote:

> C++ has enough different scope control mechanisms you don't need
> local functions the way you need them in, say, Pascal. The
> primary reason to have local functions in C++ would be to
> implement closures. If you just want to share state among
> cooperating functions, use a class. The code will be simpler
> and easier to maintain.

Just a question of vocabulary, but what is a closure, exactly.  I've
always thought that, in layman's terms, it extended the life of the
local context beyond the return from the function.  I think that this is
how it works in lisp (but my lisp experience is limited to customizing
emacs, so I'm not sure).  And of course, Borland has invented a totally
different meaning.  What you are describing would seem to be closure as
I understand it, but without the extended lifetime.  Or are you
suggesting that Pascal extended the lifetime of the function context
beyond the return from the function if the address of the function was
taken.  (The Pascal I used didn't, but there are so many variations of
Pascal, it's hard to know what is standard, and what is fantasy on the
part of the implementer.)

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/16
Raw View
In article <7jp9ff$glj@abyss.West.Sun.COM>,
  stanley@West.Sun.COM (Stanley Friesen [Contractor]) wrote:

> After my experience with the assembler written in PAscal, I never want
to
> see local functions again - at least not unless they do NOT inherit
> access to local variables from the enclosing function.
> [Doing so is too much like global variables - without the restrictions
> on where they can be declared].

After my experience with certain class libraries written in C++, I never
want to see operator overloading again.

The fact that a particular functionality can be misused is not an
argument, at least not if there is no convienient way of getting that
functionality otherwise.

The most essential use of nested functions requires precisely that they
access local variables:

    double
    integrate( double (*pf)( double ) )
    {
        //  ...
    }

    double
    someFunc( double a )
    {
        double localFunc( double x ) { return a * x ; }
        return integrate( &localFunc ) ;
    }

That's with Pascal-like local functions.  Show me a program that does
this in C++, and I'll show you a program which is significantly longer
and more complex.

But: IMHO, the interface of integrate is *not* what I would expect of a
C++ function.  Generally, I would expect a functional object:

    struct Integrator
    {
        virtual double operator()( double ) = 0 ;
    } ;

    double
    integrate( Integrator const& f )
    {
        //  ...
    }

    double
    someFunc( double a )
    {
        struct Func : Integrator , __local_context
        {
            virtual double operator()( double x ) { return a * x ; }
        } ;
        return integrate( Integrator() ) ;
    }

A bit more to type, but it allows the user (someFunc) to maintain state
(not used in this example).  Of course, this also requires an extension
in order to work.  (Without the extension, the nested class is
significantly more complicated.)

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/16
Raw View
In article <37f9872b.643561308@nntp.ix.netcom.com>,
  source@netcom.com (David Harmon) wrote:
> On 10 Jun 99 22:07:54 GMT in comp.std.c++, clamage@eng.sun.com (Steve
> Clamage) wrote:
>
> >What about this:
> >
> >typedef int (*fp)(int);
> >
> >extern void foo(fp);
> >
> >int main()
> >{
> >    int g(int) { ... } // local function
> >    foo(g); // passed to a function that doesn't know about g or main
> >}
>
> I'm afraid that would have to be disallowed too.  The type of &g would
> be something resembling int(main::*)(int) and nothing outside of main
> would know enough about it to use it.  foo(g) would be a type
mismatch.

But then you've eliminated the main reason for wanting local functions.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stanley@West.Sun.COM (Stanley Friesen [Contractor])
Date: 1999/06/16
Raw View
In article <3763A8D5.9786D8C2@wizard.net>,
James Kuyper  <kuyper@wizard.net> wrote:
>
>Just because a function is being called outside the parent's scope
>doesn't mean that the parent's scope has ended.

I guess the problem here is an ambiguity in the phrase "outside of the
parent's scope".  Once can interpret being in a function called by the
the parent function as still being "in" the parent's scope in some sense.

> In fact, that's exactly
>the case in one of the examples you gave:
>
>> void Container::DoSomethingToAll(/* function parameters */)
>> {
>>   // local variables
>>   void DoSomethingToOne(T& t) { /* use t, local variables and function
>> parameters */ }
>>   ForEach(DoSomethingToOne);
>> }
>
>Therefore, the question of whether it's possible/desirable to allow
>local function pointers to exist and be interchangable with global
>function pointers is very relevant.

Well, based solely on this example I do not see why ForEach needs to be
declared to take a generic function pointer.  It could easily be declared
to take a nested function pointer.  Or it could, even better, be declared
as a template. (To be general it needs to be a template anyhow, since
function pointers with different signatures are not interchangeable as it
is, so nothing is lost by doing so).
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/16
Raw View
In article <010804741210d69CPIMSSMTPU07@email.msn.com>,
  "G.B." <don't.even.think.about.it@briar.org> wrote:

> Do we gain anything by making them member functions? I think it would
> be superfluous; local function already has an access to "this" pointer
> through its parent member function. Though it may make sense for
> pointer manipulation since the pointer to member function has a
> different type, so maybe a new keyword can be added to specify member
> local function.

If the local function has access to the class through a this pointer, it
*is* a member function.  If the local function inherits the entire
context, it has access to the this pointer, and so is effectively a
member function.

It's a point I hadn't considered in my __local_context.  Normally,
access in the derived nested class is through the name.  But in the
derived nested class, the name this already has a meaning, and hides
that in the outer function.

Of course, one could imagine something like inner functions in Java.  My
experience with them in Java, however, suggests that their main use is
obfuscation.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stanley@West.Sun.COM (Stanley Friesen [Contractor])
Date: 1999/06/16
Raw View
In article <7jvh45$5ms$1@engnews1.eng.sun.com>,
Steve Clamage <clamage@eng.sun.com> wrote:
>"G.B." <gb@web1.ucar.edu> writes:
>
>>John Potter <jpotter@falcon.lhup.edu> wrote in message
>
>>You can have a var of that type anywhere. I only meant it is useless outside
>>of the scope of parent function.
>
>Huh? You can do it in Pascal, for example.
>
>But using it outside the scope of the parent function would
>be the only point of having local funcitons in C++, it seems
>to me.

I think you and John are meaning different things by "outside the
scope of the parent function".  He took it to mean "the scope of the
parent function has ended due to the function returning".  In that case
what he said is *indeed* correct.   And you cannot call nested functions
like that in Pascal either - the parent function has to be at least *active*.
>
>Maybe you could explain how local functions that could not be
>called from outside the enclosing function scope would be a
>useful addition to C++. What programming problems can be solved
>more easily? It seems to me that a class with member functions
>solves all the same problems, and does a better job of it.

That is my main objection to nested functions - it adds too little for
the pain.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/06/16
Raw View
In article <052212302080969CPIMSSMTPU07@email.msn.com>,
  "G.B." <don't even think about it@uunet.uu.net> wrote:
> <gbush@my-deja.com> wrote in message
news:7jd4c5$nup$1@nnrp1.deja.com...
> > C++ unlike other languages doesn't support nested functions. I

> Thanks everybody for your input. It was better than I expected :)
> I really like the idea that Valentin Bonnard and James Kanze suggested
- to
> provide __local_context class. I can't think about any adverse effect
of it.
> Hope some compilers will implement it as an extension.

I hope they define it precisely first:-).

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient=E9e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh=FCttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/06/16
Raw View
David R Tribble wrote:

[...]

> >> P.S.  I personally don't see any need for nested functions.
> >
> > I do. (It's true no single language feature is have-it-or-die,
> > though.)
>
> Please provide a convincing example; no one's done that yet.

One from real life:

extern "C"
 void fortran_integration_routine_(double(*)(double&),
                                   int const& start, int& end,
                                   double const& prec,
                                   double& result);

double calc_something(double param1, double param2)
{
  // I wish I had this
  double foo(double& pd)
  {
    return param1 + pd*param2;
      // of course, the real function was more complex
  }
  double result;
  fortran_integration_routine_(&foo, 1, 3, 1e-10, result);
  return result;
}

Of course, the real function was much more complex (and the
integral was two-dimensional, so the integration was called
recursively).

>
> > The problem is, they are hard to implement in the context of the
> > C++ language.
>
> My guess is that nested functions would be no more harder to
> implement than exception handling.
>
> Oh, and by the way, how do nested functions complicate exception
> handling?  No one's discussed that either.

Do they? I don't think so. For the EH mechanism, the only difference
between global and local function is an aditional local context
parameter. Quite similar to the additional this parameter in classes.

>
> A nested function requires a slightly more complex invocation frame,
> called a "display" (see chap.7 of the Red Dragon compiler book),
> which allows it to access its outer function's local variables (to
> any arbitrary nesting level) in addition to its own local variables.
> A display also handles recursion, allowing the function to call
> itself while still maintaining accessibility to the proper level
> of local and outer local variables.  This in itself is not hard to
> do for C++.

Look at the Borland Pascal implementation: The function just
gets as additional parameter the local context of the surrounding
function. That is, the code

void foo()
{
  int i=2;
  void bar()
  {
    int j=3;
    void baz(int k)
    {
      i=j+k;
    }
    baz(3);
  }
  bar();
}

would be translated into (qualitatively)

void baz(int k, __bar_local_context* parent)
{
  parent->parent->i = parent->j+k;
}

void bar(__foo_local_context* parent)
{
  int j=3;
  baz(3, __own_local_context);
}

void foo()
{
  int i=2;
  bar(__own_local_context);
}

As you see, accessing variables through more levels gets more
expensive. I don't see that as a big problem.

>
> What is hard is adding yet another kind of function pointer, which
> allows the compiler to properly invoke a pointed-to local function
> so that its invocation frame is properly constructed.  I'm led to
> the conclusion that the compiler needs to know it's a local
> function pointer, distinct from a "normal" function pointer, so that
> this can occur; this implies a new syntax for distinguishing between
> the two kinds of pointers.  (I already suggested the syntax
> '({}::* fp)()' in another post.)  Such a pointer must contain extra
> information such as the number of nesting levels needed by the
> pointed-to function's display; perhaps such a pointer points to
> a static "display descriptor" which contains such information,
> much like an object's _vtbl pointer points to a static "class
> descriptor table".

This is the most obvious solution. However, another solution exists
which encodes the extra information not in the pointer itself, but
in the code it points to, which is a dynamically created trampoline.
That solution has the advantage that you can use normal function
pointers, and pass them to non-C++-functions.

>
> But I still don't think nested functions are that useful.

I think they are.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/06/16
Raw View
Andrew Koenig wrote:
>
> In article <7jma5c$i85@abyss.West.Sun.COM>,
> Stanley Friesen [Contractor] <stanley@west.sun.com> wrote:
>
> > Why do local functions have to have the same calling sequence as non-local
> > functions?
>
> Because otherwise, you can't define a variable
> (of type pointer to function) that can potentially
> contain the address of a local function or a non-local
> function.

Not true: You would be able to assign a global variable to
a local function pointer by just defining that a null local
context pointer means a global function. So:

void foo()

void (*pf)();
void (*local lpf)(); // ad-hoc syntax

void bar()
{
  void loc() {}
  pf = &foo; // certainly OK
  pf = &loc; // not OK
  lpf = &loc; // OK
  lpf = &foo; // also OK (local context pointer set to NULL)
}
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Jerry Leichter <jerrold.leichter@smarts.com>
Date: 1999/06/16
Raw View
| I'm afraid you are wrong.
| Passing pointers to local functions to the outside is fundamental to
| LISP-like languages. One basically cannot program in LISP without
| that....

This is a gross overstatement.  The ability to pass functions "outward"
was very limited in LISP for roughly half of its life - the
implementation issues went under the name "the upwards funarg problem".
Basically, upwards funarg's - function arguments passed back to callers
- didn't work at all well until Scheme introduced static scoping to
LISP.  You can go back and read the classic MIT papers that showed why
this was a good idea - and why you really wanted to support workable
upwards funargs to begin with.

| > On the other hand, it seems entirely reasonable to pass pointers
| > to local functions to other functions within the same scope of the
| > outer function.
|
| IMHO you have a peculiar way of concluding what's reasonable and
| what's not.  All other participants agree that if local functions will
| be allowed, one should be able to pass them to the outside world in a
| way or another....

Don't claim to speak for all other participants.  I, for one, don't
agree.

"Downward" local functions are useful for one class of problems.
"Upward" local functions are useful for another.

Those problems for which "downward" local functions are useful can get
ugly in C++ today.  The classic example is an integrate(f,low,high)
function which integrates f over the interval [low,high].  If f is a
fixed function, this is easy.  But what if f depends on a bunch of
parameters?  The code looks nicest if (a) f can be defined locally in
the context that wants to apply integrate() to it; (b) f's parameters
can be local to that context.  (Actually, you really also want (c) f can
be a lambda expression - i.e., you don't have to give f a name.  This is
easy - a syntactic rewrite - if you already have the ability to do (a)
and (b).)

The C++ approach to this, used in the STL, is to make f an instance of a
class with an () operator and make the setable parameters to f fields in
the class.  *This* is what gets really verbose and ugly.  Java takes the
same approach but, borrowing an idea from Modula-3, gives you an
expression that creates an instance of an anonymous subclass of a class,
with potentially some members changed.  Unfortunately, this approach is
unworkable in C++, since without garbage collection, you're left with no
good way to delete the created object.  The STL tries to get around this
with things like bind1st(), but all but the simplest combinations
written this way rapidly become incomprehensible.  (And, no, it's not
just a matter of getting used to them.  Mathematicians have been writing
expressions of that form for many years, and they have the advantage of
being able to come up with much more compact and expressive notations
than are possible in ASCII; but even so, the functional forms you
actually see written down in this form are very simple, because anything
else is just too hard to follow.)

*Upward* local functions, on the other hand, are useful mainly because
they implicitly create closures.  If you look at how closures actually
get *used*, there's no real advantage to a closure over a class
instance, syntactically or otherwise, in a language that already has the
latter.  Yes, you could *implement* things like bind1st() in terms of
closures a bit more cleanly than is now the case - but the difference
isn't major, and much of it is lost in the headaches of keep track of
when you can delete a closure safely in a non-GC environment.  Without
GC, C++ will never be appropriate for higher-order functional
programming, any more than it's suitable for logic programming.  It
already supports a ton of programming paradigms - why try to cram in
more in a half-hearted fashion?
       -- Jerry




The C++ solution is to use a
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: source@netcom.com (David Harmon)
Date: 1999/06/11
Raw View
On 10 Jun 99 22:07:54 GMT in comp.std.c++, clamage@eng.sun.com (Steve
Clamage) wrote:

>What about this:
>
>typedef int (*fp)(int);
>
>extern void foo(fp);
>
>int main()
>{
>    int g(int) { ... } // local function
>    foo(g); // passed to a function that doesn't know about g or main
>}

I'm afraid that would have to be disallowed too.  The type of &g would
be something resembling int(main::*)(int) and nothing outside of main
would know enough about it to use it.  foo(g) would be a type mismatch.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: source@netcom.com (David Harmon)
Date: 1999/06/11
Raw View
On 10 Jun 99 16:20:58 GMT in comp.std.c++, ark@research.att.com
(Andrew Koenig) wrote:

>> Why do local functions have to have the same calling sequence as non-local
>> functions?
>
>Because otherwise, you can't define a variable
>(of type pointer to function) that can potentially
>contain the address of a local function or a non-local
>function.

Just like you can't define a variable that can hold both a pointer
to a member function or a pointer to a non-member function.  A local
function is actually more like a member function than a non-member
function, but instead of 'this' it gets a pointer to an implicit
local context object (AKA display.)



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1999/06/11
Raw View

Andrew Koenig wrote in message ...
>In article <7jd4c5$nup$1@nnrp1.deja.com>,  <gbush@my-deja.com> wrote:
>
>> C++ unlike other languages doesn't support nested functions. I
>> understand, bad heredity. But C++ had an opportunity to escape from
>> this predicament by allowing classes inside function body see the local
>> non-static variables, defined in the outer scope as well as function
>> parameters. For some reason it was not done. I wonder, is there at
>> least one good reason why it is so?
>
>Yes -- the reason is that someone proposed it to the committee,
>the committee talked about it, took a vote, and the proposal lost.


I think the question asks for a technical rather than a procedural reason.
What compelling technical arguments, if any, influenced the vote?



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: gbush@my-deja.com
Date: 1999/06/11
Raw View
In article <lz%73.9759$wk2.183779@newscene.newscene.com>,
  jpotter@falcon.lhup.edu (John Potter) wrote:
> Functions by their nature are not auto, they are static.
Well, I believe the question of the nature of functions is not settled.
C++ can fix some of the problems of C. And obviously, local functions
as well as any other local objects should exist only in the scope where
they are defined.

> Or did you mean that returning a pointer to a local function would
> need to be made a special case and disallowed?  So assign it to a
> global variable.  Disallow that also?  Pass it to another function
> which makes the assignment.  Disallow passing it to another function?
> That was the reason for wanting it.

Assignment of the local f-n ptr to the global var should be diagnosed
as an error by compiler. The warning must be given when the pointer to
the local f-n is returned by f-n. The same way as compiler gives
warning if f-n returns ptr or ref to the local obj.
No problems with passing a ptr to the local f-n to another f-n, as long
as that f-n doesn't break any of the previous constraints, and call is
originated in the scope where local f-n is defined.
Gene.


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: gbush@my-deja.com
Date: 1999/06/11
Raw View
In article <7jmdcv$a56$1@engnews1.eng.sun.com>,
  clamage@eng.sun.com (Steve Clamage) wrote:
> Consider function pointers:
>
> extern int f(int);
> extern int(fp*)(int);
>
> void g1()
> {
>     int h(int) { ... } // supposing C++ had local functions
>     fp = h;

This must be prohibited. It doesn't make sense to assign local function
pointer to the global variable. Local functions cannot be extern.

> If the calling sequences for g1::h and f are not the same,

There should not be such thing as g1::h. Local functions should be
visible only in the scope where they are defined.

> the code can't work. Either you need a different kind of
> function pointer for local functions, or you extend the
> calling sequence of global functions to match that of local
> functions.

You don't need a different kind of pointer for local functions. You
just don't call them from out of scope.

> Given the amount of complexity, and that you can get many of
> the effects of local functions with function objects or with
> classes in general, adding local functions didn't seem like
> a big win for C++.
There is no "amount of complexity", it works great in Pascal and is
very usefull.

Gene.


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: source@netcom.com (David Harmon)
Date: 1999/06/12
Raw View
On 11 Jun 1999 06:30:31 GMT in comp.std.c++, jpotter@falcon.lhup.edu
(John Potter) wrote:

>Functions by their nature are not auto, they are static.

So how come some are declared with the 'static' keyword and others
aren't, huh?  Huh?

OK, so I stretched the simile too far.  But local functions are as
much auto as a member function x.foo() is part of an object.  Sure,
the code space is statically allocated.  But local functions can be
called only with a local context, which is by nature auto.

As you point out, it is really a question of type, not storage.
You can return a pointer to local function or store it in an
appropriately typed global, but you can only call it where you have
access to a corresponding local context, i.e. from the function
where it was defined or from another local function defined within
that function.  A local function can call itself recursively,
keeping the same outer function context.  Two local functions within
the same outer function can call each other.

<troll>I bet if we tried real hard, we could find a way to make the
keyword 'auto' required.  Let's see, the C syntax
 int foo(int);
is already defined as declaring an extern function, even within a
function.  So, to forward declare a local function, you would have
to write:
    auto int foo(int);

and
    static int foo(int) {...}
would be a locally-scoped function that has C++ linkage, ordinary
free function type, and no access to the context of the function
within which it is defined.
</troll>
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/06/12
Raw View
gbush@my-deja.com writes:

>In article <7jmdcv$a56$1@engnews1.eng.sun.com>,
>  clamage@eng.sun.com (Steve Clamage) wrote:
>> Consider function pointers:
>>
>> extern int f(int);
>> extern int(fp*)(int);
>>
>> void g1()
>> {
>>     int h(int) { ... } // supposing C++ had local functions
>>     fp = h;

>This must be prohibited. It doesn't make sense to assign local function
>pointer to the global variable. Local functions cannot be extern.

I don't understand that reasoning.  Consider this code:

    extern int (*pf)(int);
    extern int* pi;

    static int f(int i) { ... }

    void foo()
    {
 static int k = 1;
 pf = f;
 pi = &k;
    }

Function f is not visible outide this translation unit, yet
can be called from other translation units via pf. Varible
k is not visible outside function foo, yet can be accessed
even from other translation units via pi.

>> If the calling sequences for g1::h and f are not the same,

>There should not be such thing as g1::h. Local functions should be
>visible only in the scope where they are defined.

What does visibility have to do with it?  See above.

>> the code can't work. Either you need a different kind of
>> function pointer for local functions, or you extend the
>> calling sequence of global functions to match that of local
>> functions.

>You don't need a different kind of pointer for local functions. You
>just don't call them from out of scope.

Then you eliminate the only use for local functions in C++.

C++ has enough different scope control mechanisms you don't need
local functions the way you need them in, say, Pascal. The
primary reason to have local functions in C++ would be to
implement closures. If you just want to share state among
cooperating functions, use a class. The code will be simpler
and easier to maintain.

>> Given the amount of complexity, and that you can get many of
>> the effects of local functions with function objects or with
>> classes in general, adding local functions didn't seem like
>> a big win for C++.
>There is no "amount of complexity", it works great in Pascal and is
>very usefull.

You are arguing against yourself.  Pascal allows you to pass a
local function to an outside function, yet you say that must be
prohibited in C++. If it works great, why prohibit it?

Pascal gives you true closures, and does so by using "fat"
function pointers. We can do that in C++, but it breaks C
compatibility if function pointers are uniform. That brings
us back to where this thread started.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/06/12
Raw View
stanley@west.sun.com (Stanley Friesen [Contractor]) writes:
> Why do local functions have to have the same calling sequence as non-local
> functions?  Given the C++ requirement for all functions to be declared
> prior to a call, the compiler can always tell if a call is to a namespace
> scope funcion or to a local one.

You would like to be able to pass pointers to local functions to routines
that expect normal function pointers. For example, you could make a little
comparison routine inside a function which uses locals of that function,
and pass its address to qsort.

There is an easy (for compilers) way to do proper local functions. It works
like this - there is a global data structure called a display which holds a
set of stack frame pointers. It has as many entries as the largest static
nesting depth of any function. The easiset way to implement this is to have
one global display in the runtime library, with some maximum size, say 256.

Whenever a nested function is entered, it saves the display entry at its
depth into its stack frame, and copies its own frame pointer into that
spot of the display. On exit, it restores the saved entry.

A pointer to nested function must carry along all the display items up to
the nesting depth of that function. When the function is called through the
pointer, it must save the entire display up to its nesting depth, then copy
all of its display items into the display. This needs to be undone at exit.
That's why everyone is saying that nested function pointers are incompatible
with ordinary ones. The solution is the generation of a thunk of code in the
stack frame where the pointer to function is first created. This thunk looks
like a structure - it has room for the current display pointers, for the ones
to be swapped out, *and the code to do this*. Then a pointer to this thunk
looks like an ordinary function pointer, and *that* is what gets passed.

Note that this means that pointers to nested functions are valid only while
their containing function has not returned. This is exactly analogous to
pointers to automatic variables, so it is something that any C or C++
programmer should be used to. It is different from the way things work in
scheme or Java, because those are garabge-collected languages, so the
contents of stack frames can live on after their creating functions return
(and in scheme, can be re-entered!).

Also note that functions at nesting level 0 (the only ones that now exist)
don't need to change at all, because "entry 0" of the display does not need
to live within the display array - it is simply the ordinary frame pointer.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/06/12
Raw View
gbush@my-deja.com wrote:

: No problems with passing a ptr to the local f-n to another f-n, as long
: as that f-n doesn't break any of the previous constraints, and call is
: originated in the scope where local f-n is defined.

Consider:

void f (SomeUndecidedType* p);
void g () {
   void h () { }
   f(h);
   }

We need a type for that function pointer or f can not be declared.
Now that we have a type for it, there is no reason for not having
variables of that type anywhere.

Pascal had special rules for function parameters.  That was ok
because Pascal did not have pointers to functions.  We are not
talking about Pascal.

How will you integrate your great local functions into the overall
C++ language?

Please consider a common extension which starts threads using a
function as the "main" of the thread.  I once used a Pascal
implementation which had this feature and started threads using
local functions.  The result was total destruction of the display
and absolutely useless programs.  I then implemented the idea in
C and C++ with very nice results.  I have never missed local
functions since.

John



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/06/12
Raw View
Hyman Rosen <hymie@prolifics.com> writes:

>There is an easy (for compilers) way to do proper local functions. It works
>like this - there is a global data structure called a display which holds a
>set of stack frame pointers. It has as many entries as the largest static
>nesting depth of any function. The easiset way to implement this is to have
>one global display in the runtime library, with some maximum size, say 256.

>Whenever a nested function is entered, it saves the display entry at its
>depth into its stack frame, and copies its own frame pointer into that
>spot of the display. On exit, it restores the saved entry.

>A pointer to nested function must carry along all the display items up to
>the nesting depth of that function. When the function is called through the
>pointer, it must save the entire display up to its nesting depth, then copy
>all of its display items into the display. This needs to be undone at exit.

That doesn't sound easy to me. The implementations I'm familiar
with use a distributed display, without the extra work at function
entry and exit.

Assuming an implementation that uses stack frames for functions,
the frame contains a link to the frame of the calling function --
the next one up the stack. Call that the "dynamic link". To support
local functions, you also need a pointer to the stack frame of the
lexically-enclosing function. Call that the "static link".  The
static link is null if the current function is not nested. Notice
that a local function cannot be active unless it's lexically-
enclosing function is active (was called but hasn't returned).

(That's true in languages like Pascal. In C or C++ you'd have
the possibility of storing a pointer to a local function in
a global variable and trying to call that function when it
wasn't active. As Hyman pointed out, it's a variation on
referring to a deleted object, and is something else to
consider when discussing the merits of nested functions.)

When a local function refers to an auto variable of an enclosing
function, the compiler knows how many levels up to go, and
knows the offset of that variable in the enclosing functions
stack frame. It generates code to walk the static links and
find the offset.

At function entry, the only extra work is setting the static link
in the stack frame. At exit, the calling frame is restored, the
static link coming along with it.

Access to an up-level variable requires a stack walk, making
it more expensive. But experience has shown that up-level
references other than to the immediately-enclosing function
are very rare, so the stack walk is usually just one pointer
dereference, which you cannot avoid no matter what method
you use. (Going up multiple levels is rare because it's
hard for humans reading and writing the code to understand
what's happening, and makes maintenance difficult.)

In short, you pay for up-level access only when you use it
(except for the one extra pointer in a stack frame), and
in the most common cases the access cost is no more than
for any other implementation method.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: gbush@my-deja.com
Date: 1999/06/12
Raw View
In article <FD38vK.CC4@research.att.com>,
  ark@research.att.com (Andrew Koenig) wrote:
> Because otherwise, you can't define a variable
> (of type pointer to function) that can potentially
> contain the address of a local function or a non-local
> function.
I think there should be no differences in pointers to the local
function or to the global function. They should have exactly the same
signatures, so that any function that recieves function pointer could
call equally successfully local and global function through that
pointer. Since local functions are visible only in the scope where they
are defined such a call could be made only from the same scope.
Gene.

Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stanley@West.Sun.COM (Stanley Friesen [Contractor])
Date: 1999/06/12
Raw View
In article <7jmdcv$a56$1@engnews1.eng.sun.com>,
Steve Clamage <clamage@eng.sun.com> wrote:
>
>stanley@west.sun.com (Stanley Friesen [Contractor]) writes:
>
>>Why do local functions have to have the same calling sequence as non-local
>>functions?  ...
>
>Consider function pointers:
>
Apparently you didn't read my third paragraph.

Naturally, pointers to local functions make another category of pointer.
There are already 4 non-mixable categories of pointers in C++: pointer
to object, pointer to ordinary function, pointer to data member, pointer
to function member.  One more is hardly a big burden.
>
>Given the amount of complexity, and that you can get many of
>the effects of local functions with function objects or with
>classes in general, adding local functions didn't seem like
>a big win for C++.

That I have no argument with.

After my experience with the assembler written in PAscal, I never want to
see local functions again - at least not unless they do NOT inherit
access to local variables from the enclosing function.
[Doing so is too much like global variables - without the restrictions
on where they can be declared].
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/06/12
Raw View
source@netcom.com (David Harmon) wrote:

: As you point out, it is really a question of type, not storage.
: You can return a pointer to local function or store it in an
: appropriately typed global, but you can only call it where you have
: access to a corresponding local context, i.e. from the function
: where it was defined or from another local function defined within
: that function.  A local function can call itself recursively,
: keeping the same outer function context.  Two local functions within
: the same outer function can call each other.

A local function can call its containing function(s), indirect
recursion.  A pointer to local function can be passed to another
function as an argument.  That function can call a function which
it can not see.  It can even pass the pointer on to its nested
function.  This does not involve the nasty things above and
does work in languages which have nested functions.  The local
context is still available until the containing function exits.
The machinery is well known but I do not understand the gain.  I do
see the costs of maintaining the machinery (maybe low), the costs of
multilevel global references (maybe high).

John
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "G.B." <gb@web1.ucar.edu>
Date: 1999/06/12
Raw View
John Potter <jpotter@falcon.lhup.edu> wrote in message
news:_xh83.25803$wk2.383242@newscene.newscene.com...
> We need a type for that function pointer or f can not be declared.

We don't really need a special type for local function, though we can. The
need of it appears only when local functions are implemented with local
context passed in the stack to the local function. I don't have anything
against it, but IMHO it could be more convenient to keep the local context
pointer in the data or code segment. See my answer to "Steve Clamage
<clamage@eng.sun.com> wrote in message
news:7jrv0r$dfq$1@engnews1.eng.sun.com..." few entries above for possible
mechanism of this.

> Now that we have a type for it, there is no reason for not having
> variables of that type anywhere.

You can have a var of that type anywhere. I only meant it is useless outside
of the scope of parent function.

> Pascal had special rules for function parameters.  That was ok
> because Pascal did not have pointers to functions.  We are not
> talking about Pascal.

Pascal has a type of function, which is essentially a pointer. The only
difference is that you are not allowed to manipulate with that pointer -
only to call a function. I don't think we need any kind of pointer
arithmetic with local function pointers, do we? So what is the difference?

Gene.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "G.B." <uunet!home!gb@ncar.UCAR.EDU>
Date: 1999/06/09
Raw View
<gbush@my-deja.com> wrote in message news:7jd4c5$nup$1@nnrp1.deja.com...
> C++ unlike other languages doesn't support nested functions. I

Thanks everybody for your input. It was better than I expected :)
I really like the idea that Valentin Bonnard and James Kanze suggested - to
provide __local_context class. I can't think about any adverse effect of it.
Hope some compilers will implement it as an extension.
Gene.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stanley@west.sun.com (Stanley Friesen [Contractor])
Date: 1999/06/09
Raw View
In article <7jjjr6$r02$1@nnrp1.deja.com>,  <wmm@fastdial.net> wrote:
>In article <7jd4c5$nup$1@nnrp1.deja.com>,
>1) Runtime overhead.  The function calling sequence has to be
>modified to maintain a display pointer or the like. ...

Why do local functions have to have the same calling sequence as non-local
functions?  Given the C++ requirement for all functions to be declared
prior to a call, the compiler can always tell if a call is to a namespace
scope funcion or to a local one.
>
>2) Implementation complexity.  Although the problems are well
>understood from experience with other languages, people felt that
>the utility of nested functions was sufficiently limited that it was
>not a good tradeoff.

2.5) The potential for writing obscure code due to "hidden" references
to mid-scope variables is not worth the small gain in utility.

[One of the hardest to maintain programs I ever saw was an assembler
written in Pascal that made heavy use of local functions, and of the local
function's ability to access variables in containing functions].
>
>3) C data compatibility.  A function pointer in C is a simple object,
>just the address of the code of the function.  A pointer to a nested
>function is more complex, requiring a pointer to the automatic
>storage area.  ...

Since pointer-to-member-functions are already non-compatible with ordinary
function pointers, why do pointers to local functions need to be compatible
either?  Why not just use a different category of pointers for pointers
to local functions?


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/06/09
Raw View
stanley@west.sun.com (Stanley Friesen [Contractor]) writes:

>In article <7jjjr6$r02$1@nnrp1.deja.com>,  <wmm@fastdial.net> wrote:
>>In article <7jd4c5$nup$1@nnrp1.deja.com>,
>>1) Runtime overhead.  The function calling sequence has to be
>>modified to maintain a display pointer or the like. ...

>Why do local functions have to have the same calling sequence as non-local
>functions?  Given the C++ requirement for all functions to be declared
>prior to a call, the compiler can always tell if a call is to a namespace
>scope funcion or to a local one.

Consider function pointers:

extern int f(int);
extern int(fp*)(int);

void g1()
{
    int h(int) { ... } // supposing C++ had local functions
    fp = h;
}

void g2()
{
    fp = f;
}

int main()
{
    if( ... )
 g1(); // sets fp to local function
    else
 g2(); // sets fp to global function

    fp(3);
}

If the calling sequences for g1::h and f are not the same,
the code can't work. Either you need a different kind of
function pointer for local functions, or you extend the
calling sequence of global functions to match that of local
functions.

A possible approach, as Mike Miller suggested, is to give C++
functions the extended calling sequence so that C compatibility
would be maintained. A local function could not have C linkage.

Another approach, as you suggested, would be to make local
functions (and pointers to them) a different category, as
are non-static class member functions (and pointers to them).

Given the amount of complexity, and that you can get many of
the effects of local functions with function objects or with
classes in general, adding local functions didn't seem like
a big win for C++.

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stanley@West.Sun.COM (Stanley Friesen [Contractor])
Date: 1999/06/09
Raw View
In article <7jjq0g$tlu$1@nnrp1.deja.com>,
Andrei Alexandrescu  <andrewalex@hotmail.com> wrote:
>On the other hand, with C++ the situation changed quite radically.
>Templates are in, and they (and the way the standard library uses
>them) enable working with local functions in a natural, elegant way.

While this is so, I see local functions as providing too much potential
for abuse and obscured code, for too little added power for me to want
to see the feature.
>
>With all due respect, the fact that there are local classes but no local
>functions is to me an over-OOPism of the commitee members. Andrew's
>spartan answer is not relieving. Okay, the proposal was rejected, but
>the question is: was it rejected for a good reason? If yes, what's the
>good reason - and what's the one for adding local classes? Furthermore,
>why does one reason not apply to the other case? Etcaetera.

Actually, I have found little good use for local classes either.

Most cases I have seen where one might want this are better handled as
embedded classes or as classes in an anonymous namespace.

I would not really be too upset if local classes were eliminated from
the language.
>
>As it is now, the local classes feature is kind of like the preprocessor
>is: a nice idea, but implemented in a way that's deceptively close to
>usefulness.

I am not convinced that local classes are really that nice an idea.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Jerry Leichter <jerrold.leichter@smarts.com>
Date: 1999/06/09
Raw View
| >Why do local functions have to have the same calling sequence as
| >non-local functions?  Given the C++ requirement for all functions to
| >be declared prior to a call, the compiler can always tell if a call
| >is to a namespace scope funcion or to a local one.
|
| Consider function pointers:
|
| [Function pointer fp set to either a local or a global function]
|
| If the calling sequences for g1::h and f are not the same,
| the code can't work. Either you need a different kind of
| function pointer for local functions, or you extend the
| calling sequence of global functions to match that of local
| functions.

... or you use trampolines:  When you call a local function through a
pointer, you're really calling a small bit of code dynamically generated
code that sets up the environment and calls the real function.  This
adds a cost to calls to local functions through pointers, but has no
effect on any existing code, or on code that calls local functions
directly.  I believe GCC uses this technique.

BTW, Modula-3 takes an interesting half-way approach:  It has local
procedures, but their addresses can only be passed as arguments, not
assigned (which I think implicitly prevents them from being returned as
the value of a function; one way or another, this isn't allowed).  This
lets you use local procedures to access local state, but does *not*
allow you to create closures - so the implementation can still use
purely stack-implemented procedure frames (and could even put
trampolines on the stack on machines that let you run from the stack).

Local procedures subject to this constraint would be a significantly
less intrusive C++ extension. They are much less powerful, of course,
but then again you *do* have a reasonable alternative (an object) for
most uses of true closures.
       -- Jerry
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/06/10
Raw View
On 09 Jun 99 20:00:41 GMT, Stanley Friesen

>Actually, I have found little good use for local classes either.

You can use them in template functions.  One alternative is putting the
class at namespace scope, but this does not provide strong locality of
reference.  Another alternative is to use various function objects from
<functional>, but the resulting code may be bulky looking.

You can use local classes for fancy iterators.  Eg,
   void f() { struct I { ... }; for (I i(1,11); i.ok(0); ++i) ; }

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: source@netcom.com (David Harmon)
Date: 1999/06/10
Raw View
On 9 Jun 1999 18:09:53 GMT in comp.std.c++, stanley@west.sun.com
(Stanley Friesen [Contractor]) wrote:
>In article <7jjjr6$r02$1@nnrp1.deja.com>,  <wmm@fastdial.net> wrote:
>>In article <7jd4c5$nup$1@nnrp1.deja.com>,
>>1) Runtime overhead.  The function calling sequence has to be
>>modified to maintain a display pointer or the like. ...
>
>Why do local functions have to have the same calling sequence as non-local
>functions?  Given the C++ requirement for all functions to be declared
>prior to a call, the compiler can always tell if a call is to a namespace
>scope funcion or to a local one.

Also, a local function can only be called from within the context of a
function that knows about it.  Returning a pointer to a local function
would be undefined, just like returning a pointer to an auto variable.
Code elsewhere needs no overhead added to the calling sequence.

I want it.

But when all is said and done, I don't need it.  You can do everything
AFAIK by passing explicit argements, and other techniques mentioned on
this thread.  You just lose structure.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/06/10
Raw View
source@netcom.com (David Harmon) writes:

>Also, a local function can only be called from within the context of a
>function that knows about it.  Returning a pointer to a local function
>would be undefined, just like returning a pointer to an auto variable. ...

>Code elsewhere needs no overhead added to the calling sequence.

What about this:

typedef int (*fp)(int);

extern void foo(fp);

int main()
{
    int g(int) { ... } // local function
    foo(g); // passed to a function that doesn't know about g or main
}

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Michael Cook <cook@sightpath.com>
Date: 1999/06/11
Raw View
ark@research.att.com (Andrew Koenig) writes:

> Stanley Friesen [Contractor] <stanley@west.sun.com> wrote:
>
> > Why do local functions have to have the same calling sequence as non-local
> > functions?
>
> Because otherwise, you can't define a variable
> (of type pointer to function) that can potentially
> contain the address of a local function or a non-local
> function.

So then pointers to local functions would be analogous to pointers
to member functions.  No?
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/06/11
Raw View
source@netcom.com (David Harmon) wrote:

: Also, a local function can only be called from within the context of a
: function that knows about it.

s type.  Not it.

: Returning a pointer to a local function
: would be undefined, just like returning a pointer to an auto variable.

Functions by their nature are not auto, they are static.

typedef int (*fp) (int);
int a (int v) { return v & 1; }
fp pick_a_func () {
   int b (int v) { return v * v; }
   return rand() & 1 ? a : b;
   }

Or did you mean that returning a pointer to a local function would
need to be made a special case and disallowed?  So assign it to a
global variable.  Disallow that also?  Pass it to another function
which makes the assignment.  Disallow passing it to another function?
That was the reason for wanting it.

On the system that I use, there would be no overhead.  In C a pointer
to function points to a struct which contains the address of the
function, other stuff and the display.  I am already paying the
expense of the concept.  A function pointer dereference requires
two levels of indirection.

I've seen it.  I've broken it.  I don't want it.

John



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: gbush@my-deja.com
Date: 1999/06/06
Raw View
C++ unlike other languages doesn't support nested functions. I
understand, bad heredity. But C++ had an opportunity to escape from
this predicament by allowing classes inside function body see the local
non-static variables, defined in the outer scope as well as function
parameters. For some reason it was not done. I wonder, is there at
least one good reason why it is so? (You see, I don't ask about five
good reasons anymore, just one.) I understand, certainly, that someone
could return object that contains references to local variables, but it
hardly can be considered a good reason.
Gene.

Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/06/06
Raw View
gbush@my-deja.com wrote:

> C++ unlike other languages doesn't support nested functions. I
> understand, bad heredity. But C++ had an opportunity to escape from
> this predicament by allowing classes inside function body see the local
> non-static variables, defined in the outer scope as well as function
> parameters. For some reason it was not done. I wonder, is there at
> least one good reason why it is so? (You see, I don't ask about five
> good reasons anymore, just one.) I understand, certainly, that someone
> could return object that contains references to local variables, but it
> hardly can be considered a good reason.

This has already been discussed here.

Andrew Koenig said (approximatly) that it was a big
philosophical change to allow local classes to
access locals.

James and I propose to introduce a new class,
__local_context, defined in every function
scope, which represents the locals in the scope.

Then all you would need to do is to derive your
local class from this class:

void foo ()
{
    int i;

    struct loc : __local_context {
        int operator() () { return i; }
        loc (__local_context c) : __local_context (c) {}
    };
    cout << loc (__local_context());
}

...well, you get the idea; if you add a lambda
construct for creating local clases easilly, and
give local classes external linkage, then you
get a functionnal language.

--

Valentin Bonnard
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: gbush@my-deja.com
Date: 1999/06/07
Raw View
In article <375A17D3.482@wanadoo.fr>,
  Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
> James and I propose to introduce a new class,
> __local_context, defined in every function
> scope, which represents the locals in the scope.
This looks very good and clean solution. Though it didn't become a part
of the Standard, it would be nice if compiler vendors made this
implementation available along with other extensions. Compiler vendors,
are you there !?
Gene.


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James.Kanze@dresdner-bank.com
Date: 1999/06/07
Raw View
In article <7jeroc$7bk$1@nnrp1.deja.com>,
  gbush@my-deja.com wrote:
>
> In article <375A17D3.482@wanadoo.fr>,
>   Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
> > James and I propose to introduce a new class,
> > __local_context, defined in every function
> > scope, which represents the locals in the scope.

> This looks very good and clean solution. Though it didn't become a
part
> of the Standard, it would be nice if compiler vendors made this
> implementation available along with other extensions. Compiler
vendors,
> are you there !?

Just to clarify: I obviously think it is a good and clean solution,
since I thought of it:-).  But there are several very good reasons why
it isn't in the standard today.  Perhaps the most important reason is
that the idea only occured to me after there was a freeze on new
features.  And of course, until now (unless Valentin has done some work
I'm not aware of), it has been a fairly vague idea.  There has never
been a formal proposal, and it requires a fair amount of work to convert
a vague idea into a formal proposal.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1999/06/08
Raw View
Valentin Bonnard wrote:
....
> James and I propose to introduce a new class,
> __local_context, defined in every function
> scope, which represents the locals in the scope.

There's at least two regular posters on this group named James, and I'm
not the one you're talking about. Could you use last names when context
doesn't make the reference clear?
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/06/08
Raw View
gbush@my-deja.com writes:

>C++ unlike other languages doesn't support nested functions. I
>understand, bad heredity. But C++ had an opportunity to escape from
>this predicament by allowing classes inside function body see the local
>non-static variables, defined in the outer scope as well as function
>parameters. For some reason it was not done. I wonder, is there at
>least one good reason why it is so?

IMHO, no good reason.

You can have a local class with member functions. In order to
support that, the compiler has most of the mechanism needed
to support general nested functions.

I once argued that this situation makes no sense. Either nested
functions should be supported, or local classes should not be
allowed to have user-defined member functions. That is, the
member functions in local classes add considerable complexity
to the compiler for a feature that is not very useful and is
seldom used.

For whatever reasons, there was little support in the committee
for adding general nested functions, and no support for removing
member functions of local classes. I think mainly no one
cared strongly about the issues (I cared more about other
issues and didn't spend any time on this one), so by default
nothing was changed.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/06/08
Raw View
James Kuyper wrote:

> There's at least two regular posters on this group named James, and I'm
> not the one you're talking about. Could you use last names when context
> doesn't make the reference clear?

It was James Kanze. Sorry. Won't do it again.

--

Valentin Bonnard


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Andrei Alexandrescu <andrewalex@hotmail.com>
Date: 1999/06/08
Raw View
In article <7jfkcr$na6$1@engnews1.eng.sun.com>,
  clamage@eng.sun.com (Steve Clamage) wrote:
[on local functions]
> IMHO, no good reason.

I agree with Steve.

IMHO, C didn't follow the Pascal tradition of local functions for the
sake of simplicity and closeness to the machine. I actually *like* the
fact that C doesn't have local functions. They are just too large a
cloak for C. It doesn't fit.

I think maybe the commitee members thought something along the same
lines when they refused to add local functions to C++.

On the other hand, with C++ the situation changed quite radically.
Templates are in, and they (and the way the standard library uses
them) enable working with local functions in a natural, elegant way.

Often I find myself defining small local classes that have only static
functions inside a template function. To my happiness, in 11 cases out
of 10, this breaks MSVC.

With all due respect, the fact that there are local classes but no local
functions is to me an over-OOPism of the commitee members. Andrew's
spartan answer is not relieving. Okay, the proposal was rejected, but
the question is: was it rejected for a good reason? If yes, what's the
good reason - and what's the one for adding local classes? Furthermore,
why does one reason not apply to the other case? Etcaetera.

I'd like to have local functions even in the limited way C++'s design
allows. Local classes should have linkage so one could use smll functors
with for_each etc. without adding many methods to the class.

As it is now, the local classes feature is kind of like the preprocessor
is: a nice idea, but implemented in a way that's deceptively close to
usefulness.

Andrei


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/06/09
Raw View
Steve Clamage wrote:
>
> gbush@my-deja.com writes:
>
> >C++ unlike other languages doesn't support nested functions. I
> >understand, bad heredity. But C++ had an opportunity to escape from
> >this predicament by allowing classes inside function body see the local
> >non-static variables, defined in the outer scope as well as function
> >parameters. For some reason it was not done. I wonder, is there at
> >least one good reason why it is so?
>
> IMHO, no good reason.
>
> You can have a local class with member functions. In order to
> support that, the compiler has most of the mechanism needed
> to support general nested functions.

Maybe we aren't talking about the same things:

void foo (int i)
{
    struct bar { int foobar () { return i; } };
}

and

void foo (int i)
{
    int foobar () { return i; }
}

are clearly equivalent, and none is supported by the standard.

> I once argued that this situation makes no sense. Either nested
> functions should be supported, or local classes should not be
> allowed to have user-defined member functions. That is, the
> member functions in local classes add considerable complexity
> to the compiler for a feature that is not very useful and is
> seldom used.
>
> For whatever reasons, there was little support in the committee
> for adding general nested functions, and no support for removing
> member functions of local classes. I think mainly no one
> cared strongly about the issues (I cared more about other
> issues and didn't spend any time on this one), so by default
> nothing was changed.

I think that local class are mainly usefull as template
arguments (as Functors), but they can't be used as template
arguments (they have no linkage).

So I agree that they make almost no sens.

--

Valentin Bonnard
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: wmm@fastdial.net
Date: 1999/06/09
Raw View
In article <7jd4c5$nup$1@nnrp1.deja.com>,
  gbush@my-deja.com wrote:
> C++ unlike other languages doesn't support nested functions. I
> understand, bad heredity. But C++ had an opportunity to escape from
> this predicament by allowing classes inside function body see the
local
> non-static variables, defined in the outer scope as well as function
> parameters. For some reason it was not done. I wonder, is there at
> least one good reason why it is so? (You see, I don't ask about five
> good reasons anymore, just one.) I understand, certainly, that someone
> could return object that contains references to local variables, but
it
> hardly can be considered a good reason.

As I recall the discussion, there were three main arguments against
allowing nested functions:

1) Runtime overhead.  The function calling sequence has to be
modified to maintain a display pointer or the like.  Considering
all the howls that went up when multiple inheritance was added to
the language and virtual function calls became slightly more
expensive, there wasn't a lot of enthusiasm for adding this overhead.

2) Implementation complexity.  Although the problems are well
understood from experience with other languages, people felt that
the utility of nested functions was sufficiently limited that it was
not a good tradeoff.

3) C data compatibility.  A function pointer in C is a simple object,
just the address of the code of the function.  A pointer to a nested
function is more complex, requiring a pointer to the automatic
storage area.  (This was back in the days before the language linkage
became a part of the function type; these days, pointers to C and C++
functions aren't compatible anyway, so the value of this argument is
now much less.)

[BTW, I'm just reporting the objections, not espousing them; I think
nested functions are a reasonable idea and would address some of the
problems resulting from the Committee's decision not to have resumable
exceptions.]

--
William M. Miller, wmm@fastdial.net
Software Emancipation Technology (www.setech.com)


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/06/09
Raw View
On 8 Jun 1999 21:26:57 GMT, Andrei Alexandrescu <andrewalex@hotmail.com> wrote:

>I'd like to have local functions even in the limited way C++'s design
>allows. Local classes should have linkage so one could use smll functors
>with for_each etc. without adding many methods to the class.

Fine, I agree with both your points.

But answer this one question.  Should the local functions and local
classes be able to access the local context?  J Kanze and V Bonnard
suggested that we have a pseudo-class 'local_context', and the
local class can derive from 'local_context' if it wishes to access
the local context.  But how does the local function access the
local context?  Or perhaps the ability of the local class or local
function to access the local context should be automatic, without
any need for the pseudo-class?

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/06/09
Raw View
Valentin Bonnard <Bonnard.V@wanadoo.fr> writes:

>Steve Clamage wrote:
>>
>> You can have a local class with member functions. In order to
>> support that, the compiler has most of the mechanism needed
>> to support general nested functions.

>Maybe we aren't talking about the same things:

>void foo (int i)
>{
>    struct bar { int foobar () { return i; } };
>}

>and

>void foo (int i)
>{
>    int foobar () { return i; }
>}

>are clearly equivalent, and none is supported by the standard.

Right. But you can do things like the following:

extern int g(int);

void foo(int i)
{
    static int z;

    class bar {
    public:
 class baz; // nested class
 bar(int x, baz* pb) : k(x), p(pb) { } // constructor
 int val() { return g(k); } // use global function
 int operator++() { // use local static, throw exception
     if (k == INT_MAX) throw z;
     return ++k;
 }
 ...
    private:
 int k;
 baz* p;
    };
    class bar::baz { // nested class defined outside containing class
       ...
    };
    ...
}

A local class cannot have static data members, and member
functions can be defined only in the class body. A local
class cannot reference auto variables or parameters of the
enclosing function. Those restrictions eliminate the normal
uses of nested functions, particularly closures.

Allowing something like class bar significantly complicates
the compiler, yet does not add much power to C++. Local
structs or unions are sometimes useful for manipulating data,
but the extra C++ class features tend not to be useful when they
are so restricted.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: JG@opticon.demon.co.uk (John Goodwin)
Date: 1998/05/07
Raw View
On 06 May 98 03:49:37 GMT, clamage@Eng.Sun.COM (Steve Clamage) wrote:

>In article 510389881@news.demon.co.uk, JG@opticon.demon.co.uk (John Goodwin) writes:
>>
>>On investigation it was found that EVERY SINGLE ONE of the goto's was
>>there because a local function was required. ...
>>It would have been nice to be able to replace them tidily with local
>>functions but ....
>>
>>I've now read the rest of the thread, and realise that what I would
>>like is a very small subset of what could be involved in providing
>>local functions.
>>
>>To handle the cases I have in mind, you can put two restrictions on
>>your local functions:
>>
>>1) No address taking.
>>2) No other local function of the calling function is in scope
>> inside the local function.
>
>Perhaps you could explain why classes and/or function objects do
>not solve the problem equally well.
>

OK

On general 'good practice' grounds::

  It would require moving initialisations away from declarations.

On code efficiency grounds::
  It would require an extra function call _every_ time the 'outer'
  function was invoked.

On aesthetic grounds:

  It would be verbose, messy, and tend to obsfucate the code.

Having said that, I agree that in _many_ cases, the methods you
suggest are quite satisfactory.

JG
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/05/08
Raw View
J. Kanze wrote:
>
> "Paul D. DeRocco" <pderocco@ix.netcom.com> writes:
>
> |>  However, allowing recursion is only a small increase in
> |>  complexity. The
> |>  mechanism for remembering the context of the original call (i.e.,
> |>  the
> |>  address of the enclosing stack frame) is well-understood, and is
> |>  even
> |>  built into the x86 ENTER instruction.
>
> Correct.  But none of the x86 C/C++ compilers I know use this
> instruction, because it costs more time than a simple PUSH EBP; MOV
> EBP,ESP sequence.  (Or has this changed?  It's been some time since I
> last looked at the generated output of a C/C++ compiler on an Intel
> processor.)

No, the compilers I use avoid ENTER/LEAVE. I'm merely saying that the
algorithm is well-known, and that ENTER would probably be more efficient
for nested functions, even though it isn't for non-nested ones.

--

Ciao,
Paul


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/05/04
Raw View
Andreas Rossberg <rossberg@ips.cs.tu-bs.de> writes:

> For example, would C++ have closures then the whole tedious
> business with iterators in the STL would be almost redundant, because
> you can factor out the most common kinds of iterations over arbitrary
> containers into a small set of simple library template functions like
> iterate, fold, map, etc.

The iterators in the STL just do what you describe: factor out
iterations over arbitrary containers into a set of simple
library template functions: for_each, copy, find, ect.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: JHB NIJHOF <nijhojhb@aston.ac.uk>
Date: 1998/05/04
Raw View
Paul D. DeRocco <pderocco@ix.netcom.com> wrote:
: JHB NIJHOF wrote:
:>
:> You can do that with a class:
:> Class Output {
:> private:
:> char* buf;
:> unsigned buflen;
:> public:
:>   Output(char *pointer,int length)
:>         : buf(pointer), buflen(length) {};
:>   void operator()(char c) {
:>             *buf++ = c;
:>             if (!--buflen) throw length_error();
:>             }
:> }
:>
:> Then you can use Output as:
:>
:> Output append(somebuffer, itslength);
:> ...
:> append(c);

: That's a nice way to solve the readability problem, but it's still
: rather inefficient internally, since append(c) is really
: append->operator()(c), and the access to buf and buflen involve
: dereferencing the this pointer.

It seems to be efficient enough for use in STL, though
(after inlining, of course): this is how the function adapters
like bind2nd() work.

--
Jeroen Nijhof      J.H.B.Nijhof@aston.ac.uk
Accordion Links    http://www-th.phys.rug.nl/~nijhojhb/accordions.html



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/05/04
Raw View
Hyman Rosen wrote:
>
> Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:
> > But as long as f didn't return, you don't need a closure mechanism,
> > as the usual nested function mechanism would work well.
>
> Perhaps I am misusing the term closure? I understand a closure to be the
> combination of a function pointer plus a set of stack frame pointers, one
> for each static nesting level of the pointed-to function. What do you mean
> by it? Are Scheme closures different? In Scheme, automatic variables can
> outlive the exit from their scope, but that's because Scheme is a garbage
> collected language. Java now has the same sort of thing.

Maybe my understanding of the term "closure" is wrong. The posting which
introduced the term to the thread spoke about "true closures" with an
example where the function context outlives the return, and the
behaviour
of the program demonstrated just this by creating two such contexts.
Also it mentioned the gcc model as not being "true closures". Therefore
I concluded that closures are function contexts which "survive"
the return of the function (which makes sense as those contexts are in
some way "closed" by the return: they cannot be accessed directly
any more, but only indirectly by the local functions).

BTW, you don't need a frame pointer for each nesting level. You
just need one for the level below. From there, you can get to the other
levels sequencially.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: antonio@Somewhere.@.USC (Antonio)
Date: 1998/05/05
Raw View


  Jim Coplien's book (C++ Idioms) has an interesting implementation
  of nested functions. I think it's quite easy and very portable,
  maybe worth to take into consideration.

  Hope it helps,
  Antonio


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: JG@opticon.demon.co.uk (John Goodwin)
Date: 1998/05/05
Raw View
On 19 Apr 98 03:54:41 GMT, "Lo   c Tr   gan" <loic.tregan@isdnet.net>
wrote:

>Are nested functions a good thing ? (of course, i have my opinion...)
>
>void f()
>{
>      void InternalA() {}
>      void InternalB() {}
>
>    InternalA();
>    InternalB();
>}
>
>if YES, why they are nt in the draft ?
>if NO, why are they allowed in C and not C++ ?
>
>thanks.
>---

I was once involved in an audit on a program of around 110,000 lines
of code.

It was believed to contain about a dozen goto's, but in fact turned
out to have around 100.

On investigation it was found that EVERY SINGLE ONE of the goto's was
there because a local function was required.

Some of the drones who considered themselves "purists" wanted the code
modified with semaphores and extra if statements, but sanity ruled,
and the goto,s were allowed to stand.

It would have been nice to be able to replace them tidily with local
functions but ....

-----------

I've now read the rest of the thread, and realise that what I would
like is a very small subset of what could be involved in providing
local functions.

To handle the cases I have in mind, you can put two restrictions on
your local functions:

1) No address taking.
2) No other local function of the calling function is in scope
 inside the local function.

This creates no extra overhead, and would provide a significant
benefit in those cases where it is needed.

But it's not going to happen so I suppose we'll just have to accept
it.

JG



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1998/05/06
Raw View
In article 510389881@news.demon.co.uk, JG@opticon.demon.co.uk (John Goodwin) writes:
>
>On investigation it was found that EVERY SINGLE ONE of the goto's was
>there because a local function was required. ...
>It would have been nice to be able to replace them tidily with local
>functions but ....
>
>I've now read the rest of the thread, and realise that what I would
>like is a very small subset of what could be involved in providing
>local functions.
>
>To handle the cases I have in mind, you can put two restrictions on
>your local functions:
>
>1) No address taking.
>2) No other local function of the calling function is in scope
> inside the local function.

Perhaps you could explain why classes and/or function objects do
not solve the problem equally well.

The features already in C++ provide you with the functionality of
nested functions except for lexical closure. But neither the "goto"
solution nor your restricted version of nested functions provide
lexical closure either.

A class with member functions eliminates both the restrictions
above, and so would seem to be more powerful than what you are asking.

---
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/04/29
Raw View
Christopher Eltschka wrote:
> Closures might be useful, but have too complicated interaction
> with the C++ object model (I guess they would work well with the
> Java object model). Note however, that once you return from the
> enclosing function, a closure is in no way different from a function
> object, from the user's point of view. And before the return, they
> are not any different to ordinary nested functions. Indeed I guess
> I would never use them at all.
>
> However, I'd still like to see nested functions in C++. While
> they are not a tool you use everyday, they are very handy in
> some situations, and they don't cause any problems with the C++
> object model.

One benefit of nested functions that I haven't seen mentioned is
that they act a lot like private member functions but they don't
need to be declared in the class declaration.  For programmers (like
me) who believe it's sinful to show off class private members in
header files (to client functions that have no business seeing the
class's privates), this is a good thing.

A function nested within a normal (non-static) member function
acts like a file-static function as far as scoping, but still has
access to all the class members like a true private member
function does.

Not that I'm in favor of adding nested functions to C++, mind you.
I'd rather see a way of declaring private member functions within
a source file that didn't require adding a function declaration to
the class header file.  This would accomplish the same thing for me.

In fact, it would be nice if I could somehow put only the public
members in the class declaration in the (distributed) header file,
and extend the declaration by adding the protected and private
member declarations in a local (undistributed) header file.
Now that would be true data hiding.

-- David R. Tribble, david.tribble@noSPAM.central.beasys.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1998/04/29
Raw View
Loic Tregan wrote:
>
> Manfred Knemeyer wrote:
> >
> > Nested function definitions are not allowed in C either.
> >
>
> maybe, but in gcc yes :

gcc with no compiler options selected implements a language inspired by
C, but which comes nowhere near meeting the ANSI standards for C.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/04/29
Raw View
Bradd W. Szonye wrote:
>
> Okay, no argument there. I thought the original poster was talking
> about
> the 'toy' local functions in, say, Pascal, not the higher-order
> functions available in functional programming languages, which I'll
> agree are very powerful.

What I bemoan the lack of is precisely what you call "toy" local
functions. I know I can do fancier stuff with functors that carry data
along with them. However, every now and then, I have to write some big
function, perhaps containing a long switch statement, and I find there's
the same little tidbit of code in it over and over and over again, that
I'd really like to wrap in a function, except that it needs access to
two or three of the local variables of the outer function. For instance,
suppose I'm writing a disassembler that fetches bytes from memory, and
appends characters to a character buffer:

 int disassemble(
  const unsigned char* bin, // instruction
  char* buf,                // result buffer
  unsigned buflen);         // buffer length

Such code generally involves big switch statements, but I need to
produce output by appending to the buffer and checking against the
buffer length. This is done in dozens of places, so I'd like to do it
with a function:

 void append(char c, char*& buf, unsigned& buflen) {
     *buf++ = c;
     if (!--buflen) throw length_error();
     }

If I could write it as a nested function, I could leave off the buf and
buflen parameters, which makes the resulting code more efficient in
terms of space, speed, and clarity. Since I can't do that, I end up
storing buf and buflen into globals, which is a kludge.

--

Ciao,
Paul
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Steven Perryman" <stevenp@nortel.ca>
Date: 1998/04/29
Raw View
In article <q1l11.32$vA5.779136@cam-news-reader1.bbnplanet.com> Barry Margolin <barmar@bbnplanet.com> writes:
>In article <35459993.3BC581B0@physik.tu-muenchen.de>,
>Christopher Eltschka  <celtschk@physik.tu-muenchen.de> wrote:
>>Closures might be useful, but have too complicated interaction
>>with the C++ object model (I guess they would work well with the
>>Java object model).

>Which probably explains why closures are generally only found in languages
>with garbage collection.

I think it's more general than that.
As C++ has stack-based object allocation as well as heap, closures would
be a problem. This is why C++ cannot have nested classes a la Simula, cos
if the outer object was stack allocated, and the inner objects were on the
heap, the 'environment' of the inner objects would be trashed once the
outer object goes (stack frame folds etc) .

If a compiler was clever and forced outer classes to always be allocated
on the heap, then perhaps we could do it.


Regards,
Steven Perryman
stevenp@nortel.co.uk
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/04/29
Raw View
Hyman Rosen wrote:
>
> Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:
> > Other thanm nested functions, closures would cause problems with the C++
> > object model. Look for example at the following code:
> >
> > struct X { };
> > typedef X* (*fun)();
> > fun f(int i)
> > {
> >   X x;
> >   X* c1() { return &x; }
> >   X* c2() { return 0; }
> >   return i > 0 ? c1 : c2;
> > };
> >
> > Now, when should the destructor of x be called?
>
> At the normal time, right before f returns. Closures in C and C++ do
> not, and are not meant to, behave like closures in Scheme. C/C++ is
> not a garbage-collected language, and automatic variables do not
> survive the exit of their block. In your example, users of the return
> value of f may will access a dangling pointer. Mot only x, but c1 and
> c2 themselves no longer exist after f returns. Closures in C/C++ are
> still needed for mutually recursive or further nested inner functions,
> however.

But as long as f didn't return, you don't need a closure mechanism,
as the usual nested function mechanism would work well (you could, of
course, define this as a specialized closure, but then you could
as well say C++ already supports nested functions, but limited to
the first level, which is functions at global scope). As I see them,
closures are just there to ensure that variables of the outer scope
survive long enough.
Note that f.ex. Pascal doesn't have closures, but supports nested
functions at arbitrary levels including direct and indirect
recursion. This more than proves that closures are not necessary
for this.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1998/04/29
Raw View
ark@research.att.com (Andrew Koenig) writes:

>The reason C++ does not have nested functions is that implementing them
>in full generality would make every function pointer into a two-word
>object -- it would need the address of the code and the address of the
>corresponding activation record.  It might be possible to avoid the
>space overhead by using the `trampoline' technique, but that requires
>the ability to generate code in data space, which not every processor
>supports.

There are trampoline-based techniques that do not require the
ability to generate code in data space.

For example, the system can have a fixed-size array of trampoline code
fragments, computed at code generation time or link time, and a
corresponding array of two-word (code address, data address) pairs.
Each trampoline fragment looks up the corresponding slot in the array,
puts the data address in a register, and jumps to the code address.  In
addition to these two arrays, you have a trampoline stack pointer.
Trampolines are allocated from the trampoline stack when needed, and
deallocated when the containing function exits.

The drawback of this approach is that the size of the trampoline stack must
be fixed at link time.  This does not seem too bad -- after all, many
C implementations and thread libraries used fixed-sized stacks.
Most programs would use very few trampolines at any given point in time,
so a single page (or less) would suffice for the vast majority of programs.

In addition, if the processor / OS has appropriate virtual memory
support, then you can avoid the need for a fixed-size trampoline stack,
still without doing any code generation at runtime, and with no need to
flush the instruction cache.  I'll leave that one as an exercise for
the reader.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Hyman Rosen <hymie@prolifics.com>
Date: 1998/04/29
Raw View
Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:
> But as long as f didn't return, you don't need a closure mechanism,
> as the usual nested function mechanism would work well.

Perhaps I am misusing the term closure? I understand a closure to be the
combination of a function pointer plus a set of stack frame pointers, one
for each static nesting level of the pointed-to function. What do you mean
by it? Are Scheme closures different? In Scheme, automatic variables can
outlive the exit from their scope, but that's because Scheme is a garbage
collected language. Java now has the same sort of thing.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/04/29
Raw View
Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:
>>> Other than nested functions, closures would cause problems with the
>>> C++ object model. Look for example at the following code:
>>>
>>> struct X { };
>>> typedef X* (*fun)();
>>> fun f(int i)
>>> {
>>>   X x;
>>>   X* c1() { return &x; }
>>>   X* c2() { return 0; }
>>>   return i > 0 ? c1 : c2;
>>> };
>>>
>>> Now, when should the destructor of x be called?

Hyman Rosen wrote:
>> At the normal time, right before f returns. Closures in C and C++ do
>> not, and are not meant to, behave like closures in Scheme. C/C++ is
>> not a garbage-collected language, and automatic variables do not
>> survive the exit of their block. In your example, users of the return
>> value of f may will access a dangling pointer. Mot only x, but c1 and
>> c2 themselves no longer exist after f returns. Closures in C/C++ are
>> still needed for mutually recursive or further nested inner
>> functions, however.

Christopher Eltschka wrote:
> But as long as f didn't return, you don't need a closure mechanism,
> as the usual nested function mechanism would work well (you could, of
> course, define this as a specialized closure, but then you could
> as well say C++ already supports nested functions, but limited to
> the first level, which is functions at global scope). As I see them,
> closures are just there to ensure that variables of the outer scope
> survive long enough.
> Note that f.ex. Pascal doesn't have closures, but supports nested
> functions at arbitrary levels including direct and indirect
> recursion. This more than proves that closures are not necessary
> for this.

Not exactly.  In compiler terminology, the nested functions need
a "display block" in their call activation records.  Each display
allows the nested function to access its outer function's local
variables in addition to its own local variables, and works very
well with recursion.

An example illustrates more of the problems:

    class Foo
    {
        int   bar(int i)      // A member func
        {
            int  baz()        // A nested func
            {
                count += i;   // Accesses this->count and bar.i
            };

            int  boz()        // Another nested func
            {
                count -= i;   // Accesses this->count and bar.i
                if (...)
                   boz();     // Recursive call
            };

            if (...)
                baz();
            else
                boz();
        }

        int     count;        // Member of *this
    };

Here, both nested functions baz() and boz() access a local variable
(i) of their outer function bar().  They also access a member (count)
of the 'this' object of bar(), which is technically also a local
variable.  Note than boz() has to access the same 'count' and 'i'
locals even if it's been called recursively.

All of these are solved by some form of "display" activation record.
Pascal, which supports nested routines, uses this kind of mechanism.
Apparently g++ uses something similar (called a "trampoline") but
that has less overhead for non-nested routines.

-- David R. Tribble, david.tribble@noSPAM.central.beasys.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: ark@research.att.com (Andrew Koenig)
Date: 1998/04/30
Raw View
In article <6i7h14$e33$1@mulga.cs.mu.OZ.AU>,
Fergus Henderson <fjh@cs.mu.OZ.AU> wrote:

> >It might be possible to avoid the
> >space overhead by using the `trampoline' technique, but that requires
> >the ability to generate code in data space, which not every processor
> >supports.

> There are trampoline-based techniques that do not require the
> ability to generate code in data space.

Maybe so, but they did not surface during the committee's discussions.
--
    --Andrew Koenig
      ark@research.att.com
      http://www.research.att.com/info/ark



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/04/30
Raw View
Fergus Henderson wrote:
>
> For example, the system can have a fixed-size array of trampoline code
> fragments, computed at code generation time or link time, and a
> corresponding array of two-word (code address, data address) pairs.
> Each trampoline fragment looks up the corresponding slot in the array,
> puts the data address in a register, and jumps to the code address.
> In addition to these two arrays, you have a trampoline stack pointer.
> Trampolines are allocated from the trampoline stack when needed, and
> deallocated when the containing function exits.
>
> The drawback of this approach is that the size of the trampoline stack
> must be fixed at link time. This does not seem too bad -- after all,
> many C implementations and thread libraries used fixed-sized stacks.

The other drawback is that you need to allocate one of these trampoline
stacks every time you start a new thread, in a multi-threaded
environment. You need, in effect, two stacks per thread, since what you
are trying to simulate is one stack that the machine architecture won't
let you do because it prohibits executing code stored on the real stack.

--

Ciao,
Paul


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: JHB NIJHOF <nijhojhb@aston.ac.uk>
Date: 1998/05/01
Raw View
Paul D. DeRocco <pderocco@ix.netcom.com> wrote:

: What I bemoan the lack of is precisely what you call "toy" local
: functions. I know I can do fancier stuff with functors that carry data
: along with them. However, every now and then, I have to write some big
: function, perhaps containing a long switch statement, and I find there's
: the same little tidbit of code in it over and over and over again, that
: I'd really like to wrap in a function, except that it needs access to
: two or three of the local variables of the outer function. For instance,
: suppose I'm writing a disassembler that fetches bytes from memory, and
: appends characters to a character buffer:

:  int disassemble(
:   const unsigned char* bin, // instruction
:   char* buf,                // result buffer
:   unsigned buflen);         // buffer length

: Such code generally involves big switch statements, but I need to
: produce output by appending to the buffer and checking against the
: buffer length. This is done in dozens of places, so I'd like to do it
: with a function:

:  void append(char c, char*& buf, unsigned& buflen) {
:      *buf++ = c;
:      if (!--buflen) throw length_error();
:      }

: If I could write it as a nested function, I could leave off the buf and
: buflen parameters, which makes the resulting code more efficient in
: terms of space, speed, and clarity. Since I can't do that, I end up
: storing buf and buflen into globals, which is a kludge.

You can do that with a class:
Class Output {
private:
char* buf;
unsigned buflen;
public:
  Output(char *pointer,int length)
 : buf(pointer), buflen(length) {};
  void operator()(char c) {
      *buf++ = c;
      if (!--buflen) throw length_error();
      }
}

Then you can use Output as:

Output append(somebuffer, itslength);
...
append(c);

Jeroen Nijhof
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1998/05/01
Raw View
"Didier Trosset-Moreau" <tmd@iprolink.fr> writes:

|>  That's the main reason, even if adding some notions of locality inside
|>  functions could be a good thing.
|>
|>  He also say that would encourage people to write large functions, and that
|>  it was not a good thing, at all, for their OO designs !

There's a lot in C++ which could be eliminated by that argument:-).

Seriously, however, my preferred solution WOULD be more OO : I'd make
the local context available as a built-in class, from which you could
inherit.  So that local functional objects could have access to the
local context.

Specifying this exactly is not trivial, however. Given the strong
template-orientation of the standard library, to be really effective,
you would want to be able to instantiate templates over the local
functional objects, which introduces a number of other technical
problems.

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient   e objet --
              -- Beratung in objektorientierter Datenverarbeitung


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1998/05/01
Raw View
"Paul D. DeRocco" <pderocco@ix.netcom.com> writes:

|>  J. Kanze wrote:
|>  >
|>  > Good thing or not, they are not allowed in either C or C++.  During the
|>  > recent revision of the C standard, I think that they were actually
|>  > considered and voted down.  Of course, this might be partially because
|>  > of difficulties in introducing them into the language as it exists
|>  > today, without breaking anything else, and without imposing additional
|>  > cost on people who don't use them.
|>
|>  As far as I can figure, it would be trivial to allow nested functions,
|>  as long as taking the address of them was prohibited, and as long as
|>  recursion was prohibited.

In which case, most of the utility is gone.  Why on earth would you want
local functions, if not to pass their address to another function?

|> The latter could be prohibited by banning
|>  self-calling, and by banning declarations without definitions, thus
|>  banning the forward calling necessary for mutual recursion.
|>
|>  However, allowing recursion is only a small increase in complexity. The
|>  mechanism for remembering the context of the original call (i.e., the
|>  address of the enclosing stack frame) is well-understood, and is even
|>  built into the x86 ENTER instruction.

Correct.  But none of the x86 C/C++ compilers I know use this
instruction, because it costs more time than a simple PUSH EBP; MOV
EBP,ESP sequence.  (Or has this changed?  It's been some time since I
last looked at the generated output of a C/C++ compiler on an Intel
processor.)

|>  To allow pointers to nested functions would be more complex, since the
|>  pointer would have to contain the address of the function and the
|>  address of the enclosing context.

There are other solutions.  For example, one could generate a small bit
of code on the fly, which loads the pointer to the context (as a
constant), then jumps to the actual function.

|>  But a doubly-nested function would
|>  need two context addresses, and so on. Thus, the type of a pointer to a
|>  nested function would have to be "pointer to function taking blah-blah
|>  parameters and returning blah-blah, and nested n deep". In other words,
|>  you wouldn't be able to use a pointer to a singly-nested function where
|>  a pointer to a non-nested function was expected, and so on.
|>
|>  The only completely general solution would be to require that all
|>  pointers to functions, nested or not, be implemented as the combination
|>  of a pointer the actual code, plus a (possibly null) pointer to an array
|>  of context pointers. This would seem burdensome for the usual case of
|>  non-nested pointers. A compromise would be to distinguish nested and
|>  non-nested functions, and represent only the latter as the combination
|>  of a pointer to code plus a pointer to array of context pointers. But
|>  rather than open this can of worms, I'd vote simply to disallow pointers
|>  to nested functions entirely.
|>
|>  Besides, the sort of thing I usually want to do with nested functions is
|>  to wrap up some short bit of code that gets used over and over again
|>  within some big function, but that can't be broken out into a separate
|>  function because it needs access to lots of the big function's locals.
|>  In this case, I don't need to take its address.

That's easily done with a local class.  (For that matter, most of what
can be done with a nested function can easily be done with a nested
class. On the condition that the function to which you pass the address
expects a pointer to a class rather than a pointer to a function.)

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient   e objet --
              -- Beratung in objektorientierter Datenverarbeitung


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1998/05/01
Raw View
"Paul D. DeRocco" <pderocco@ix.netcom.com> writes:

|>  What I bemoan the lack of is precisely what you call "toy" local
|>  functions. I know I can do fancier stuff with functors that carry data
|>  along with them. However, every now and then, I have to write some big
|>  function, perhaps containing a long switch statement, and I find there's
|>  the same little tidbit of code in it over and over and over again, that
|>  I'd really like to wrap in a function, except that it needs access to
|>  two or three of the local variables of the outer function. For instance,
|>  suppose I'm writing a disassembler that fetches bytes from memory, and
|>  appends characters to a character buffer:
|>
|>   int disassemble(
|>    const unsigned char* bin, // instruction
|>    char* buf,                // result buffer
|>    unsigned buflen);         // buffer length
|>
|>  Such code generally involves big switch statements, but I need to
|>  produce output by appending to the buffer and checking against the
|>  buffer length. This is done in dozens of places, so I'd like to do it
|>  with a function:
|>
|>   void append(char c, char*& buf, unsigned& buflen) {
|>       *buf++ = c;
|>       if (!--buflen) throw length_error();
|>       }
|>
|>  If I could write it as a nested function, I could leave off the buf and
|>  buflen parameters, which makes the resulting code more efficient in
|>  terms of space, speed, and clarity. Since I can't do that, I end up
|>  storing buf and buflen into globals, which is a kludge.

You chose a bad example.  This is precisely the type of thing that IS
best done with a class, since you probably don't want any access to buf
outside of append.  The function should thus take a reference to a
Buffer, which encapsulates buf and buflen, rather than two separate
arguments.

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient   e objet --
              -- Beratung in objektorientierter Datenverarbeitung


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/05/02
Raw View
JHB NIJHOF wrote:
>
> You can do that with a class:
> Class Output {
> private:
> char* buf;
> unsigned buflen;
> public:
>   Output(char *pointer,int length)
>         : buf(pointer), buflen(length) {};
>   void operator()(char c) {
>             *buf++ = c;
>             if (!--buflen) throw length_error();
>             }
> }
>
> Then you can use Output as:
>
> Output append(somebuffer, itslength);
> ...
> append(c);

That's a nice way to solve the readability problem, but it's still
rather inefficient internally, since append(c) is really
append->operator()(c), and the access to buf and buflen involve
dereferencing the this pointer.

--

Ciao,
Paul
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1998/05/03
Raw View
"Paul D. DeRocco" <pderocco@ix.netcom.com> writes:

>Fergus Henderson wrote:
>>
>> For example, the system can have a fixed-size array of trampoline code
>> fragments, computed at code generation time or link time, and a
>> corresponding array of two-word (code address, data address) pairs.
>> Each trampoline fragment looks up the corresponding slot in the array,
>> puts the data address in a register, and jumps to the code address.
>> In addition to these two arrays, you have a trampoline stack pointer.
>> Trampolines are allocated from the trampoline stack when needed, and
>> deallocated when the containing function exits.
>>
>> The drawback of this approach is that the size of the trampoline stack
>> must be fixed at link time. This does not seem too bad -- after all,
>> many C implementations and thread libraries used fixed-sized stacks.
>
>The other drawback is that you need to allocate one of these trampoline
>stacks every time you start a new thread, in a multi-threaded
>environment. You need, in effect, two stacks per thread, since what you
>are trying to simulate is one stack that the machine architecture won't
>let you do because it prohibits executing code stored on the real stack.

You don't need to have one stack of trampoline code fragments per thread,
because you can reuse the same trampoline code fragments for the different
threads.  You do have to have a separate trampoline data address stack
for each thread.  However, you can allocate that on the heap, lazily,
so threads which don't use trampolines need not incur any overhead for
this.

--------------------

I'll explain in a little bit more detail how you can reuse the same
trampoline code fragments for different threads, and how you can
implement this all in an efficient manner.

Each trampoline code fragment could be reduced to just a single (CISC)
instruction:

  jsr do_trampoline

All it does is push the program counter on the stack,
and jump to `do_trampoline'.  Most of the work is done in
do_trampoline(), of which there need only be one copy.
Note that this code fragment is *very* short!
This allows you to use a relatively large trampoline
code fragment stack without using up much code space.

The do_trampoline() function would look something like this:

 typedef void Func (void);
 struct Slot { Func *code_address; void *data_address }:

 // `__thread_local' causes data to be allocated
 // in thread-local storage
 __thread_local Slot *trampoline_stack;
 __thread_local int trampoline_stack_size;
 __thread_local int trampoline_stack_pointer;

 extern char *trampoline_code_start;

 // pseudo-code
 do_trampoline() {
   int trampoline_num = (saved_pc - trampoline_code_start) / TRAMPOLINE_SIZE;
  Func *func = trampoline_stack[trampoline_num].code_address;
  void *data = trampoline_stack[trampoline_num].data_address;
  return (*func)(data);  // tailcall
 }

Here I've used `__thread_local' to declare thread-local storage.
By doing this, I'm skipping over some details, of course, but
if you want to know how to implement that, I can explain that too.
`saved_pc' is the program counter that was pushed onto the stack
by the trampoline code fragment.
`trampoline_code_start' is the address at the beginning of the
trampoline code fragment array.
`TRAMPOLINE_SIZE' is the size of each trampoline code fragment.

Apart from that, all the compiler needs is a couple of routines to
allocate and deallocate trampolines:

 Func *push_trampoline(Func *func, void *data) {
  if (!trampoline_stack) {
   trampoline_stack_size = INITIAL_SIZE;
   trampoline_stack = (Slot *)
    malloc(trampoline_stack_size * sizeof(Slot));
   trampoline_stack_pointer = 0;
  }
  if (trampoline_stack_ptr >= trampoline_stack_size) {
   trampoline_stack_size *= 2;
   trampoline_stack = (Slot *)
    realloc(trampoline_stack_size * sizeof(Slot));
  }
  trampoline_stack[trampoline_stack_ptr].code_address = func;
  trampoline_stack[trampoline_stack_ptr].data_address = data;
  return (Func *) (trampoline_code_start +
   TRAMPOLINE_SIZE * trampoline_stack_pointer++);
 }

 void pop_trampoline() {
  trampoline_stack_pointer--;
 }

This implementation would completely avoid "distributed fat".
For programs which don't use trampolines at all, the linker would
not need to link in the trampoline code stack or any of the above code.
For programs which do take the address of nested functions,
the parts of the program that use this feature will be the only
parts that incur any execution overhead.  And even for those parts,
the overheads should be fairly small.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Jason Merrill <jason@cygnus.com>
Date: 1998/05/03
Raw View
>>>>> David R Tribble <david.tribble@noSPAM.central.beasys.com> writes:

> All of these are solved by some form of "display" activation record.
> Pascal, which supports nested routines, uses this kind of mechanism.
> Apparently g++ uses something similar (called a "trampoline") but
> that has less overhead for non-nested routines.

gcc uses a dynamic chain, which is an alternative to displays.  But only
the C frontend (and, naturally, the Pascal frontend) supports this; g++
does not, because nobody has done the necessary work.

Jason
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/04/28
Raw View
Igor Boukanov wrote:
>
> GCC uses on fly code generation to make possible free mixture of
> pointers
> to non-nested and nested functions that result in no overhead for
> ordinary
> pointers. Basically it constructs a code that that would restore
> necessary
> context and then call the nested function itself.

In other words, GCC generates a thunk at runtime that passes the context
into the function, perhaps by loading it into a register? This is what
Win16 used to do for callbacks, although it was loading the DS register
with the instance's data segment. The problem is, where do you put these
thunks? The obvious place is on the stack, like any other temporary, but
many architectures don't let you execute code out of pages that are used
for data. This means the compiler has to allocate the thunk somewhere
else, and include the necessary exception handling code to guarantee
that the thunk is deallocated when the stack is unwound. Certainly
doable, but slightly messy. It's probably worth it, though.

--

Ciao,
Paul
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/04/28
Raw View
Jens Kilian wrote:
>
> "Didier Trosset-Moreau" <tmd@iprolink.fr> writes:
> > Bjarne Stroustrup himself has explained that allowing them would generate
> > lots of overhead in calls (if you think a little about the call mechanism,
> > you'll reach the same problem very early). And decided to accept no overhead
> > when designing C++.
>
> To properly implement nested functions, you must have true closures.

I disagree. To properly implement nested functions, you have to
implement
nested functions. To properly implement closures, you have to implement
closures (which indeed includes support for nested functions).

> AFAIK, even GCC supports only downward closures.  If nested functions
> were supported the way they are (and have been for decades) in Lisp,
> the following would be legal:
>
>         int (*)(void) make_counter(void)
>         {
>           int counter = 0;
>           int count(void) { return counter++; }
>
>           return count;
>         }
>
>         void
>         some_function(void)
>         {
>           int (*counter1)(void) = make_counter();
>           int (*counter2)(void) = make_counter();
>
>           // This would output the sequence 0, 0, 1, 1.
>           cout << counter1() << counter2() << counter1() << counter2();
>         }
>
> I think it's safe to say that C/C++ will *never* support such constructs.

Other thanm nested functions, closures would cause problems with the C++
object model. Look for example at the following code:

struct X
{
  X() { cout << "X()" << endl; }
  ~X() { cout << "~X()" << endl; }
};

typedef X* (*fun)();

fun f(int i)
{
  X x;
  X* c1() { return &x; }
  X* c2() { return 0; }
  if (i>0)
    return c1;
  else
    return c2;
};

Now, when should the destructor of x be called?
Normally, it would be called at exit from f, but due to closures
x might still be in use (it is, if i>0).
Now, if i<=0, c2 is returned which doesn't need x, so x may be
destructed at once. However, if c1 is returned, x is still needed.
Indeed, it is still needed as long as the function pointer is in use
(including all copies). Thus it's very much overhead just to deside
when X should be destroyed.
Note that you don't have this problem if you just have nested
functions, as the pointer to the local function is invalid as soon as
f returns (just as any other pointer to local entities).

Closures might be useful, but have too complicated interaction
with the C++ object model (I guess they would work well with the
Java object model). Note however, that once you return from the
enclosing function, a closure is in no way different from a function
object, from the user's point of view. And before the return, they
are not any different to ordinary nested functions. Indeed I guess
I would never use them at all.

However, I'd still like to see nested functions in C++. While
they are not a tool you use everyday, they are very handy in
some situations, and they don't cause any problems with the C++
object model.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Barry Margolin <barmar@bbnplanet.com>
Date: 1998/04/28
Raw View
In article <35459993.3BC581B0@physik.tu-muenchen.de>,
Christopher Eltschka  <celtschk@physik.tu-muenchen.de> wrote:
>Closures might be useful, but have too complicated interaction
>with the C++ object model (I guess they would work well with the
>Java object model).

Which probably explains why closures are generally only found in languages
with garbage collection.

--
Barry Margolin, barmar@bbnplanet.com
GTE Internetworking, Powered by BBN, Cambridge, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Bradd W. Szonye" <bradds@concentric.net>
Date: 1998/04/29
Raw View
> Bradd W. Szonye wrote:
> >
> > Nesting functions can be a useful scoping construct, but they add
> > little new utility or expressiveness to a language, so their
> > absence is generally not seen as a major failing of C or C++,
> > except by advocates of languages that do support function nesting.

Andreas Rossberg wrote:
>
> True nested functions (ie. closures) are a _very_ powerful feature
> that is absolutely essential if you're seriously using functionals
> (functions taking function(pointer)s as argument, also called
> higher-order functions).

Okay, no argument there. I thought the original poster was talking about
the 'toy' local functions in, say, Pascal, not the higher-order
functions available in functional programming languages, which I'll
agree are very powerful.

I'd put simple local functions in the same category as the 'super'
facility: nice to have, but not necessary if there are other features
more important to develop in the time available. Just as 'super' is
possible (more or less) with 'typedef base base_type,' simple local
functions are possible with the unnamed namespace and functor classes.

As for closures, that's a very interesting addition to the language...
but the interactions with the C++ object lifetime model could get nasty.
Also, what is the possibility of a roll-your-own closure with the
facilities already available in C++? I'm not especially knowledgeable
about the issues in implementing closures; functional programming is
just an occasional hobby for me, and I'm much more familiar with, say,
implementation of polymorphism, heap memory management, and exception
handling.

(If answers to that question are too far off-topic, e-mail me comments,
but please let me know whether it's a CC.)
--
Bradd W. Szonye
bradds@concentric.net
http://www.concentric.net/~Bradds

My reply address is correct as-is. The courtesy of providing a correct
reply address is more important to me than time spent deleting spam.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Matthias Neeracher <neeri@iis.ee.ethz.ch>
Date: 1998/04/29
Raw View
"Bradd W. Szonye" <bradds@concentric.net> writes:
> Nesting functions can be a useful scoping construct, but they add little
> new utility or expressiveness to a language, so their absence is
> generally not seen as a major failing of C or C++, except by advocates
> of languages that do support function nesting.

Nested *anonymous* functions would, IMHO, be quite useful in combination with
the STL:

   for_each(container.begin(), container.end(),
      void (*)(const Element & elt) {
         // Do something with elt
      }
   );

I'd prefer that style over the bind2nd/mem_fun etc. template calculus.
Matthias

--
Matthias Neeracher   <neeri@iis.ee.ethz.ch>   http://www.iis.ee.ethz.ch/~neeri
  "Paranotions, which designate constructs, may now contain metanotions and
   ``hypernotions'' have been introduced in order to designate protonotions"
                -- A. van Wijngaarden et al., _ALGOL 68 Revised Report_
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Hyman Rosen <hymie@prolifics.com>
Date: 1998/04/29
Raw View
Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:
> Other thanm nested functions, closures would cause problems with the C++
> object model. Look for example at the following code:
>
> struct X { };
> typedef X* (*fun)();
> fun f(int i)
> {
>   X x;
>   X* c1() { return &x; }
>   X* c2() { return 0; }
>   return i > 0 ? c1 : c2;
> };
>
> Now, when should the destructor of x be called?

At the normal time, right before f returns. Closures in C and C++ do
not, and are not meant to, behave like closures in Scheme. C/C++ is
not a garbage-collected language, and automatic variables do not
survive the exit of their block. In your example, users of the return
value of f may will access a dangling pointer. Mot only x, but c1 and
c2 themselves no longer exist after f returns. Closures in C/C++ are
still needed for mutually recursive or further nested inner functions,
however.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Loic Tregan <loic.tregan@cogisoft.fr>
Date: 1998/04/22
Raw View
Manfred Knemeyer wrote:
>
> Nested function definitions are not allowed in C either.
>

maybe, but in gcc yes :

main()
{
 int f() { return 5; }

 printf( "%d", f());

}


test.c : compile
test.cc : does not compile
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Andreas Rossberg <rossberg@ips.cs.tu-bs.de>
Date: 1998/04/23
Raw View
Bradd W. Szonye wrote:
>
> Nesting functions can be a useful scoping construct, but they add little
> new utility or expressiveness to a language, so their absence is
> generally not seen as a major failing of C or C++, except by advocates
> of languages that do support function nesting.

True nested functions (ie. closures) are a _very_ powerful feature that
is absolutely essential if you're seriously using functionals (functions
taking function(pointer)s as argument, also called higher-order
functions). For example, would C++ have closures then the whole tedious
business with iterators in the STL would be almost redundant, because
you can factor out the most common kinds of iterations over arbitrary
containers into a small set of simple library template functions like
iterate, fold, map, etc. that do the looping for you (possibly in an
optimized way) while you just supply the 'body' -- as a simple local
function given directly.

That's why programs in functional languages tend to be shorter by a
factor of 10 than equivalent C/C++ code. A language with good support
for higher-order functions and appropriate libraries highly increases
productivity and modularity. So your statement is plainly false.

--
Andreas Rossberg, rossberg_antispam@ips.cs.tu-bs.de
Please remove the `_antispam' when replying via email.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: fake@email.address.net
Date: 1998/04/23
Raw View
"Didier Trosset-Moreau" <tmd@iprolink.fr> writes:

> Bjarne Stroustrup himself has explained that allowing them would generate
> lots of overhead in calls (if you think a little about the call mechanism,
> you'll reach the same problem very early). And decided to accept no overhead
> when designing C++.

Nested functions produce no overhead if you don't use them (just look
at the gcc implementation).  As such, they obey Bjarne's zero-overhead
rule, just like exceptions (which are in fact harder to implement in a
way that obeys this rule).

Regards,
Bas de Bakker
basde dot bakker at pica dot nl


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Jens Kilian <Jens_Kilian@bbn.hp.com>
Date: 1998/04/23
Raw View
"Didier Trosset-Moreau" <tmd@iprolink.fr> writes:
> Bjarne Stroustrup himself has explained that allowing them would generate
> lots of overhead in calls (if you think a little about the call mechanism,
> you'll reach the same problem very early). And decided to accept no overhead
> when designing C++.

To properly implement nested functions, you must have true closures.
AFAIK, even GCC supports only downward closures.  If nested functions
were supported the way they are (and have been for decades) in Lisp,
the following would be legal:

 int (*)(void) make_counter(void)
 {
   int counter = 0;
   int count(void) { return counter++; }

   return count;
 }

 void
 some_function(void)
 {
   int (*counter1)(void) = make_counter();
   int (*counter2)(void) = make_counter();

   // This would output the sequence 0, 0, 1, 1.
   cout << counter1() << counter2() << counter1() << counter2();
 }

I think it's safe to say that C/C++ will *never* support such constructs.
Bye,
 Jens.
--
mailto:jjk@acm.org                 phone:+49-7031-14-7698 (HP TELNET 778-7698)
  http://www.bawue.de/~jjk/          fax:+49-7031-14-7351
PGP:       06 04 1C 35 7B DC 1F 26 As the air to a bird, or the sea to a fish,
0x555DA8B5 BB A2 F0 66 77 75 E1 08 so is contempt to the contemptible. [Blake]


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/04/24
Raw View
J. Kanze wrote:
>
> Good thing or not, they are not allowed in either C or C++.  During the
> recent revision of the C standard, I think that they were actually
> considered and voted down.  Of course, this might be partially because
> of difficulties in introducing them into the language as it exists
> today, without breaking anything else, and without imposing additional
> cost on people who don't use them.

As far as I can figure, it would be trivial to allow nested functions,
as long as taking the address of them was prohibited, and as long as
recursion was prohibited. The latter could be prohibited by banning
self-calling, and by banning declarations without definitions, thus
banning the forward calling necessary for mutual recursion.

However, allowing recursion is only a small increase in complexity. The
mechanism for remembering the context of the original call (i.e., the
address of the enclosing stack frame) is well-understood, and is even
built into the x86 ENTER instruction.

To allow pointers to nested functions would be more complex, since the
pointer would have to contain the address of the function and the
address of the enclosing context. But a doubly-nested function would
need two context addresses, and so on. Thus, the type of a pointer to a
nested function would have to be "pointer to function taking blah-blah
parameters and returning blah-blah, and nested n deep". In other words,
you wouldn't be able to use a pointer to a singly-nested function where
a pointer to a non-nested function was expected, and so on.

The only completely general solution would be to require that all
pointers to functions, nested or not, be implemented as the combination
of a pointer the actual code, plus a (possibly null) pointer to an array
of context pointers. This would seem burdensome for the usual case of
non-nested pointers. A compromise would be to distinguish nested and
non-nested functions, and represent only the latter as the combination
of a pointer to code plus a pointer to array of context pointers. But
rather than open this can of worms, I'd vote simply to disallow pointers
to nested functions entirely.

Besides, the sort of thing I usually want to do with nested functions is
to wrap up some short bit of code that gets used over and over again
within some big function, but that can't be broken out into a separate
function because it needs access to lots of the big function's locals.
In this case, I don't need to take its address.

--

Ciao,
Paul
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1998/04/24
Raw View
"Paul D. DeRocco" <pderocco@ix.netcom.com> writes:

>The only completely general solution would be to require that all
>pointers to functions, nested or not, be implemented as the combination
>of a pointer the actual code, plus a (possibly null) pointer to an array
>of context pointers. This would seem burdensome for the usual case of
>non-nested pointers.

No, there are other solutions based on "trampolines", for example the
one used in GNU C.

This topic has been debated in great detail in this newsgroup
in the distant past -- try DejaNews.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: boukanov@sentef2.fi.uib.no (Igor Boukanov)
Date: 1998/04/24
Raw View
In comp.std.c++ Paul D. DeRocco <pderocco@ix.netcom.com> wrote:
> To allow pointers to nested functions would be more complex, since the
> pointer would have to contain the address of the function and the
> address of the enclosing context. But a doubly-nested function would
> need two context addresses, and so on. Thus, the type of a pointer to a
> nested function would have to be "pointer to function taking blah-blah
> parameters and returning blah-blah, and nested n deep". In other words,
> you wouldn't be able to use a pointer to a singly-nested function where
> a pointer to a non-nested function was expected, and so on.

GCC uses on fly code generation to make possible free mixture of pointers
to non-nested and nested functions that result in no overhead for ordinary
pointers. Basically it constructs a code that that would restore necessary
context and then call the nested function itself.

And this ability to mix is exactly the thing that is nice to have when
calling routines written in other languages that expect function pointer.
You do not need to introduce a static variables to store additional
information. All other usages of the nested functions may be rewritten
in plain C++ without lost of efficiency, but that ability can not be emulated
at all.

--
Regards, Igor Boukanov.
igor.boukanov@fi.uib.no
http://www.fi.uib.no/~boukanov/



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/04/25
Raw View
Loic Tregan wrote:
>
> Manfred Knemeyer wrote:
> >
> > Nested function definitions are not allowed in C either.
>
> maybe, but in gcc yes :

gcc allows many things only remotely related with C and C++.

;-)

Try with gcc -ansi -pedantic. (I actually think that the
default behaviour of gcc/g++ w/o any options is a problem.)

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Lo c Tr gan" <loic.tregan@isdnet.net>
Date: 1998/04/19
Raw View
Are nested functions a good thing ? (of course, i have my opinion...)

void f()
{
      void InternalA() {}
      void InternalB() {}

    InternalA();
    InternalB();
}

if YES, why they are nt in the draft ?
if NO, why are they allowed in C and not C++ ?

thanks.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Mathew Hendry <scampi@dev.null>
Date: 1998/04/19
Raw View
Lo=EFc Tr=E9gan <loic.tregan@isdnet.net> wrote:
: Are nested functions a good thing ?

I think they would have a rather limited place in C++.

A very simple way of emulating them is to provide a unique namespace
for your function; this is roughly what would happen under the surface
if they were provided explicitly.

Or perhaps you are talking about local functions, rather than nested
functions. That is, where an inner function has access to the outer
function's variables and functions. (Forgive me if I'm using the wrong
terminology here.)

Local functions are rather more tricky to implement, but the functor
style can be used, with the variables to be used in the inner function
provided as members of the functor class; if the functor class is
nested, you can provide multiple levels of function nesting, too. A
functor can be wrapped up to appear as a normal function, so this sort
of implementation can made entirely invisible to users:

int func( int i ) {
  class func_functor {
  public:
    func_functor()          { /* ... */ }
    int operator()( int i ) { /* ... */ }
  private:
    // ...
  };
  return func_functor()( i );
};

In fact, this is a cleaner way to implement nested functions, too, as
the encapsulation is more clearly visible, configurable, and
enforcible. (If you use the simpler namespace method, there's nothing
to prevent another function from using the same namespace, and not all
that much to indicate that it shouldn't.)

: (of course, i have my opinion...)

Well, what is it? :)

: if YES, why they are nt in the draft ?

Many people feel that the language is complicated enough, if not too
complicated, already. There are already reasonably simple ways to
achieve this sort of thing, and in a much more flexible manner.

: if NO, why are they allowed in C and not C++ ?

They're not allowed in C either. Perhaps you're thinking of Pascal.

--
       Mathew Hendry (actually at dial.pipex.com, not dev.null)
                                                                    --




[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Manfred Knemeyer" <nospam@ix.netcom.com>
Date: 1998/04/20
Raw View
Nested function definitions are not allowed in C either.

Lo   c Tr   gan wrote in message <6hac23$8lb$1@news2.isdnet.net>...
>Are nested functions a good thing ? (of course, i have my opinion...)
>
>void f()
>{
>      void InternalA() {}
>      void InternalB() {}
>
>    InternalA();
>    InternalB();
>}
>
>if YES, why they are nt in the draft ?
>if NO, why are they allowed in C and not C++ ?
>
>thanks.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Oleg Zabluda <zabluda@math.psu.edu>
Date: 1998/04/20
Raw View
Lo=EFc Tr=E9gan <loic.tregan@isdnet.net> wrote:
: Are nested functions a good thing ? (of course, i have my opinion...)

If they inherit the context from the enclosing function, then
probably not.

: void f()
: {
:       void InternalA() {}
:       void InternalB() {}

:     InternalA();
:     InternalB();
: }

You can achieve the same effect with local classes:

void f()
{
 struct InternalA { InternalA() {} }
 struct InternalB { InternalB() {} }

    InternalA();
    InternalB();

// A little bit of syntactic sugar never hurt anyone.

}

: if YES, why they are nt in the draft ?
: if NO, why are they allowed in C and not C++ ?

They are not allowed in C either.

Oleg.
--=20
Life is a sexually transmitted, 100% lethal disease.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Chuck McCorvey" <chuckm@solutionware.com>
Date: 1998/04/20
Raw View
Lo   c Tr   gan wrote in message <6hac23$8lb$1@news2.isdnet.net>...
>Are nested functions a good thing ? (of course, i have my opinion...)
>
>void f()
>{
>      void InternalA() {}
>      void InternalB() {}
>
>    InternalA();
>    InternalB();
>}
>
>if YES, why they are nt in the draft ?
>if NO, why are they allowed in C and not C++ ?
>


They can be useful to provide further scoping.  However, they are probably
(?) less valuable in the presence of classes as in C++.

They are NOT allowed for in C or C++.  The above code snippet should have
caused compiler errors of the form (compiled under VC++ 5.0):

test.cpp(3) : error C2601: 'InternalA' : local function definitions are
illegal
test.cpp(4) : error C2601: 'InternalB' : local function definitions are
illegal

--
Chuck McCorvey
Creative SolutionWare, Inc.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Bradd W. Szonye" <bradds@concentric.net>
Date: 1998/04/20
Raw View
Lo=EFc Tr=E9gan wrote:
>
> Are nested functions a good thing ? (of course, i have my opinion...)
>
> void f()
> {
>       void InternalA() {}
>       void InternalB() {}
>
>     InternalA();
>     InternalB();
> }
>
> if YES, why they are nt in the draft ?
> if NO, why are they allowed in C and not C++ ?
>
> thanks.

They are not allowed in C. Nested functions are allowed by some C
compilers as an extension to the language, but they are not a C feature.

Nesting functions can be a useful scoping construct, but they add little
new utility or expressiveness to a language, so their absence is
generally not seen as a major failing of C or C++, except by advocates
of languages that do support function nesting.
--
Bradd W. Szonye
bradds@concentric.net
http://www.concentric.net/~Bradds

My reply address is correct as-is. The courtesy of providing a correct
reply address is more important to me than time spent deleting spam.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: tony@online.tmx.com.au (Tony Cook)
Date: 1998/04/20
Raw View
Lo   c Tr   gan (loic.tregan@isdnet.net) wrote:
: Are nested functions a good thing ? (of course, i have my opinion...)

: void f()
: {
:       void InternalA() {}
:       void InternalB() {}

:     InternalA();
:     InternalB();
: }

Nested functions have some increased runtime costs, though I suspect
they pass the normal 'you only pay for it if you use it' rule for C++.

: if YES, why they are nt in the draft ?
: if NO, why are they allowed in C and not C++ ?

They aren't allowed in C, though your compiler may implement them as
an extension.

--
        Tony Cook - tony@online.tmx.com.au


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1998/04/20
Raw View
"Lo   c Tr   gan" <loic.tregan@isdnet.net> writes:

|>  Are nested functions a good thing ? (of course, i have my opinion...)
|>
|>  void f()
|>  {
|>        void InternalA() {}
|>        void InternalB() {}
|>
|>      InternalA();
|>      InternalB();
|>  }
|>
|>  if YES, why they are nt in the draft ?
|>  if NO, why are they allowed in C and not C++ ?

Whether they are a good thing or not is a subject of discussion -- I
happen to like them, although I think that there are even better
solutions in the context of C++.

Good thing or not, they are not allowed in either C or C++.  During the
recent revision of the C standard, I think that they were actually
considered and voted down.  Of course, this might be partially because
of difficulties in introducing them into the language as it exists
today, without breaking anything else, and without imposing additional
cost on people who don't use them.

If your compiler does not issue a diagnostic in the above program, it is
either seriously broken, or it is not a C or C++ compiler.  (Gcc
requires special compiler options, for example, to compile C; be
default, it compiles a language which is only somewhat similar to C.
G++ is somewhat better with regards to C++, but you still need special
options to get C++.)

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient   e objet --
              -- Beratung in objektorientierter Datenverarbeitung


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Didier Trosset-Moreau" <tmd@iprolink.fr>
Date: 1998/04/20
Raw View
Hello,

they aren't in the draft and will probably never be.

Bjarne Stroustrup himself has explained that allowing them would generate
lots of overhead in calls (if you think a little about the call mechanism,
you'll reach the same problem very early). And decided to accept no overhead
when designing C++.

That's the main reason, even if adding some notions of locality inside
functions could be a good thing.

He also say that would encourage people to write large functions, and that
it was not a good thing, at all, for their OO designs !

Didier Trosset-Moreau
PAM Development
tmd@iprolink.fr


Lo   c Tr   gan a    crit dans le message <6hac23$8lb$1@news2.isdnet.net>...
>Are nested functions a good thing ? (of course, i have my opinion...)
>
>void f()
>{
>      void InternalA() {}
>      void InternalB() {}
>
>    InternalA();
>    InternalB();
>}
>
>if YES, why they are nt in the draft ?
>if NO, why are they allowed in C and not C++ ?


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/04/21
Raw View
Oleg Zabluda wrote:
>=20
> Lo=EFc Tr=E9gan <loic.tregan@isdnet.net> wrote:
> : Are nested functions a good thing ? (of course, i have my opinion...)
>=20
> If they inherit the context from the enclosing function, then
> probably not.
>=20
> : void f()
> : {
> :       void InternalA() {}
> :       void InternalB() {}
>=20
> :     InternalA();
> :     InternalB();
> : }
>=20
> You can achieve the same effect with local classes:
>=20
> void f()
> {
>         struct InternalA { InternalA() {} }
>         struct InternalB { InternalB() {} }
>=20
>     InternalA();
>     InternalB();
>=20
> // A little bit of syntactic sugar never hurt anyone.
>=20
> }

That's not really the same:

void f(int i)
{
  int j=3D1;
  void internalA() { j+=3Di; }
  void internalB() { j*=3Di; }

  internalA();
  internalB();

  assert( j =3D=3D i*(i+1) );
}

With your replacement, you would need to give all needed variables
as parameters. If the functions are recursive, this may be a big
overhead (no inlining possible, so parameters *must* be pushed
on the stack!) or otherwise require ugly constructs (to reduce the
parameters to one pointer to the actual data; thus making the
function (nearly) as efficient as with local functions).
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]