Topic: Local functions?


Author: "Piotr Dobrogost" <pbc@poczta.onet.pl>
Date: Thu, 28 Jun 2001 18:11:51 GMT
Raw View
"Marcus Lindblom" <d98macke@dtek.chalmers.se> wrote in message


> Anyway, if it can be done close enough with classes, why not allow exactly
> the same for functions?

>From the other side; if we have inner classes and static methods why not
just use them "instead" of functions ?

Piotr Dobrogost


---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Carl Daniel" <cpdaniel@pacbell.net>
Date: Mon, 18 Jun 2001 04:30:55 GMT
Raw View
"Paul Mensonides" <pmenso57@home.com> wrote in message
news:zMcW6.171991$p33.3574243@news1.sttls1.wa.home.com...
> "Carl Daniel" <cpdaniel@pacbell.net> wrote in message
> news:KhKV6.1831$Eb7.324819@news.pacbell.net...
>
> > Unfortunately, a simple offset cannot be used - a pointer is required.
In
> > the case of a recursive local function, the distance between the local
> > function's stack variables and the parent function's stack variables
> > increases with each recursion.
>
> I didn't mean a fixed compile time offset per function; I meant a closure
on a
> *variable* offset that is bound at compile-time from the point of call to
a
> local function and that value is passed to the local function implicitly.
This
> could be handled recursively as well.  I'm making the assumption that the
stack
> can be navigated via pointer arithmetic, however, and I'm not sure that is
the
> case.  Please enlighten me if it isn't. :)
>

That assumption is true on every architecture I've ever worked on, but there
are some wierd ones out there :)   In systems I've used (e.g. various Pascal
implementations) which support local functions, the nested function is
supplied with an implicit parameter which is the stack-frame pointer for the
lexical parent function - this can either be the direct caller, or in the
case of recursion, a caller located an arbitrary number of levels "up" the
call stack.  Some CPUs (e.g. Intel) have special instructions (enter, leave)
which manage a arbirtray number of up-level stack frame pointers
automatically just for this purpose.  Using these special instructions,
up-level local variables suffer from only a single extra indirection
regardless of the number of lexical and dynamic scopes crossed.  The
down-side is that these instructions are costly and consume lots of stack
space, so most implementations I'm aware of instead rely on an implicit
linked-list of lexical parent frames.  With this approach, function
entry/exit time is relatively independent of the number of nesting levels,
but up-level variable access incurs an indirection per nest-level.  Which
pattern is better is naturally highly dependent on the complexity of the
functions and the number of up-level variables which are accessed.

-cd


---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Thu, 14 Jun 2001 22:49:19 GMT
Raw View
nick.thurn@db.com (Nick Thurn) wrote (abridged):
> Are local struct/classes with inline functions permitted?

Yes, but they don't have external linkage, which means they cannot be used
with templates such as std::for_each(). This greatly diminishes their
value.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Paul Mensonides" <pmenso57@home.com>
Date: Fri, 15 Jun 2001 16:10:07 GMT
Raw View
"Carl Daniel" <cpdaniel@pacbell.net> wrote in message
news:KhKV6.1831$Eb7.324819@news.pacbell.net...

> Unfortunately, a simple offset cannot be used - a pointer is required.  In
> the case of a recursive local function, the distance between the local
> function's stack variables and the parent function's stack variables
> increases with each recursion.

I didn't mean a fixed compile time offset per function; I meant a closure on a
*variable* offset that is bound at compile-time from the point of call to a
local function and that value is passed to the local function implicitly.  This
could be handled recursively as well.  I'm making the assumption that the stack
can be navigated via pointer arithmetic, however, and I'm not sure that is the
case.  Please enlighten me if it isn't. :)

Paul Mensonides

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Carl Daniel" <carl@pixami.com>
Date: Wed, 13 Jun 2001 17:43:12 GMT
Raw View
"Marco Manfredini" <marco@technoboredom.net> wrote in message
news:Xns90BFAB19CEAE0marcotechnobore@technoboredom.net...
> "Carl Daniel" <cpdaniel@pacbell.net> wrote in
> news:uECV6.1823$FS6.165894@news.pacbell.net:
>
> >
> >
> > Personally, I'd love to see "pointer to bound function" added as a
> > class of types in C++.  It's a key building block of properly
> > supporting closures and local functions in general, and would heal
> > a wart with pointer-to-member function that exists now (that being
> > that most uses of pointer-to-member-function end up carting around
> > two pointers: a PMF and a pointer to an object -
> > pointer-to-bound-function simply formalizes & cements the
> > relationship between such pairs of pointers).
> >
>
> I think you will find many people in this NG that will reject the idea
> to add more builtin types to the language. I recently had the idea, that
> instead of adding a type to the language for, say, the implementation of
> "real" bound member functions, C++ should provide a way to delegate the
> implementation to the user:
>
[snip]

Interesting idea.  Definitely would be a step in the right direction if we
can't get real pointer-to-bound-function support.

>
> Currently resistance against new language features is based onto 2 good
> points: a) They add complexity to the compiler b) There is no good
> compromise between generality and overhead.
>

I also completely agree with the resistance to new language features - it
_should_ be like pulling teeth to get new core language feature added.  That
said, I natually also think that this feature is A) useful enough and B)
orthogonal enough to warrant the trouble of adding a whole new class of
types to the type system.  I believe that a well-designed (syntax-wise)
implementation of pointer-to-bound-function would make much mnore sense to
beginners than the pointer-to-member function does (look how many postings
there are about "how do I use ->*" and "is ->* really an operator?" etc.
Witness the inclusion of delegates in C#...

Having grown up on Pascal, I'm equally passionate about the inclusion of
local functions - there are some algorithms (e.g. recursive descent parsers)
which are so much easier to write using nested functions, that I think it's
a real shame that C++ doesn't support them.

Whatever we end up with for "C++0x", I'll use it - with or without PBF &
local functions/closures.

-cd.


---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Marcus Lindblom" <d98macke@dtek.chalmers.se>
Date: Wed, 13 Jun 2001 20:05:46 GMT
Raw View
"Marco Manfredini" <marco@technoboredom.net> wrote in message
news:Xns90BF129BB3EA7marcotechnobore@technoboredom.net...
> "Marcus Lindblom" <d98macke@dtek.chalmers.se> wrote in
> news:9g5v8p$25n$1@news.gu.se:
> > What if AA wasn't allowed to access B? Would that remove too much
> > of the usefulness? (That was what I had in mind initially, it would
> > be less versatile, but still quite good.)
>
> local functions could be done the way local classes are done, that is
> lexically bound to the types and static's of the enclosing function (as
> an encapsulation feature) - but binding to the current stack frame would
> much, much more powerful than that.

Yes, binding is more powerful, but also more (and perhaps too) complex, but
for encapsulation purposes it would be quite nice to allow it instead of the
current 'trick' with a local class.

> > I wasn't aware of the stackframe problem. (After thinking trying
> > some naive stuff, I realise the problem.) Can't we just disallow
> > recursive calls and use a global pointer to A's stack frame? ;)
>
> Doesn't work, AA could call something that calls A in turn, the compiler
> can't check that.

Of course, that's why I was putting the smiley there.

> > Ada doesn't allow sending the adress of a local function to a more
> > globally declared function (if I understand things correctly),
> > perhaps the same restriction could be applied here?
>
> Hmm. I don't quite understand the Ada restiction. Pascal doesn't allow
> to take the adress of a function pointer in general - their way.

The restriction means that you cannot call AA from the outside, say a
function called by AA. Sending the adress of AA to AAA is legal, which makes
sense.

> Anyway, if you want *some kind* of local functions, you can write a
> local class that performs the job. Local classes have access to the
> types and the statics defined in the function. Using a special trick,
> they can be actually made looking like function:

[snipped]

> [Note: Accessing x in my example does not work with the Microsoft "C++"
> "Compiler". Try this with GNU/Borland or Intel]

Will I ever learn? I actually have access to both GNU and Intel, but use
MSVC mainly and didn't think about testing with other compilers. (Too bad
Intel is so slow, and that GNU isn't (to my knowledge) easily integrated
into Visual Studio.)

Anyway, if it can be done close enough with classes, why not allow exactly
the same for functions?

> If you ask the google newsgroup archive for 'closure' and 'c++' you'll
> get >5000 hits, so this is probably not the dumbest question.

I wonder which question is? :)

/Marcus


---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Marcus Lindblom" <d98macke@dtek.chalmers.se>
Date: Wed, 13 Jun 2001 21:44:37 GMT
Raw View
"Al Grant" <tnarga@arm.REVERSE-NAME.com> wrote in message
news:9g7956$n6j$1@cam-news1.cambridge.arm.com...
> "Marcus Lindblom" <d98macke@dtek.chalmers.se> wrote in message
> news:9g5v8p$25n$1@news.gu.se...
> > What if AA wasn't allowed to access B?
>
> That is exactly the BCPL local functions rule - that
> local functions cannot access "dynamic" (i.e. auto)
> "free" (i.e. not defined within the local function)
> variables.  It makes local functions a code structuring
> mechanism with no runtime implications.

That works for me, although having full stackframe binding would be
oh-so-beautiful.

> I guess the real reason it did not carry over to C is
> because with C's function syntax it would be a lot
> harder to parse.  In BCPL this was not a problem as
> definitions were introduced with the keyword LET.

Would it? It feels as if there are worser things in the language already.

/Marcus


---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: marco@technoboredom.net (Marco Manfredini)
Date: Tue, 12 Jun 2001 19:12:28 GMT
Raw View
"Marcus Lindblom" <d98macke@dtek.chalmers.se> wrote in
news:9g2sps$nu8$1@news.gu.se:

> There is probably a good reason why they aren't allowed, but I
> can't think of one, so if someone could explain why I'd be really
> grateful. I personally like local functions, esp. in Ada, and all
> this template stuff generally requires both small functions and
> small classes that are very local.
>

The problem with a local function is, that it requires a pointer to the
enclosing environment (the current stackframe or what ever, of the
enclosing function body). Take this hypothetical piece of code:

int A(int a)
{
     int b=a*2;
     int AA(int aa)
     {
          return aa+b+a;
     }

     return AA(a+b);
}

There a two ways to implement this: rewrite AA to accept an extra
parameter to the A's current stackframe (here simulated with a struct)

struct AFrame
{
 int &a,&b;
 AFrame(int &_a, int &_b) : a(_a), b(_b) {}
};

int A_AA(AFrame &aframe, int aa)
{
 return aa+aframe.b+aframe.a;
}

int A(int a)
{
     int b=a*2;
     AFrame aframe(a,b);
     return AA(aframe, a+b);
}

Well the struct isn't explicitly neccesary, since the compiler could
pass a pointer to the stack and use it's known layout in AA. But in any
case it would mean, that the signature of AA will change!! Therefore you
will not be able to use it a function-pointer, AA is -not- a int (*)
(int) anymore but some form of int(*)(AFrame &,int) - and how do you
pass the function-pointer -and- the necesary AFrame? So this lacks
generality.

The second way is, to form a closure, that is an object that contains
both the code pointer and the current data pointer (the AFrame). Forming
objects is no problem in C++, but if the object formed shall be
accesible as a  function pointer, we will come into the problem, that we
need to form a new piece of code -at runtime-.

struct AFrame
{
 int &a,&b;
 AFrame(int &_a, int &_b) : a(_a), b(_b) {}
};

int A_AA(AFrame &aframe, int aa)
{
 return aa+aframe.b+aframe.a;
}

int A(int a)
{
     int b=a*2;
     return thunk(aframe(a,b),A_AA)(a+b);
}

Here an operator 'thunk' creates a new int (*)() from the AFrame and
A_AA which in turn is used for application. Since it is a ordinary
function what is returned from thunk, it should be obvious that the code
himself it points to must contain the current AFrame data (or at least a
pointer to it). The GNU-C compiler does this (he has local functions,
but not the C++ compiler) - they call the piece of code a "trampoline".
The problem for the language now is (beside the memory management issues
), that the hardware/OS must allow the program to generate code in the
data segment. This cannot be guaranteed, many OS explicitly disallow
this for safety reasons (think of buffer-overflow exploits, they come
from the fact that code is "injected" into data space).

So local functions have their implications.

--
Marco

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Marcus Lindblom" <d98macke@dtek.chalmers.se>
Date: Tue, 12 Jun 2001 20:54:43 GMT
Raw View
"Marco Manfredini" <marco@technoboredom.net> wrote in message
news:Xns90BE9DC195344marcotechnobore@technoboredom.net...
> The problem with a local function is, that it requires a pointer to the
> enclosing environment (the current stackframe or what ever, of the
> enclosing function body). Take this hypothetical piece of code:
>
> int A(int a)
> {
>     int b=a*2;
>     int AA(int aa)
>     {
>         return aa+b+a;
>     }
>
>     return AA(a+b);
> }

What if AA wasn't allowed to access B? Would that remove too much of the
usefulness? (That was what I had in mind initially, it would be less
versatile, but still quite good.)

> There a two ways to implement this: rewrite AA to accept an extra
> parameter to the A's current stackframe (here simulated with a struct)
[snip]

I wasn't aware of the stackframe problem. (After thinking trying some naive
stuff, I realise the problem.) Can't we just disallow recursive calls and
use a global pointer to A's stack frame? ;)

Ada doesn't allow sending the adress of a local function to a more globally
declared function (if I understand things correctly), perhaps the same
restriction could be applied here?

If I'm being an ignorant bastard not knowing when to shut up, just tell me.
:)

/Marcus


---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: Barry Margolin <barmar@genuity.net>
Date: Tue, 12 Jun 2001 21:08:05 GMT
Raw View
In article <9g5v8p$25n$1@news.gu.se>,
Marcus Lindblom <d98macke@dtek.chalmers.se> wrote:
>"Marco Manfredini" <marco@technoboredom.net> wrote in message
>news:Xns90BE9DC195344marcotechnobore@technoboredom.net...
>> The problem with a local function is, that it requires a pointer to the
>> enclosing environment (the current stackframe or what ever, of the
>> enclosing function body). Take this hypothetical piece of code:
>>
>> int A(int a)
>> {
>>     int b=a*2;
>>     int AA(int aa)
>>     {
>>         return aa+b+a;
>>     }
>>
>>     return AA(a+b);
>> }
>
>What if AA wasn't allowed to access B? Would that remove too much of the
>usefulness? (That was what I had in mind initially, it would be less
>versatile, but still quite good.)

If AA isn't allowed to access variables in the enclosing environment, then
what's the point of defining it locally?

--
Barry Margolin, barmar@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: nick.thurn@db.com (Nick Thurn)
Date: Tue, 12 Jun 2001 21:13:42 GMT
Raw View
"Marcus Lindblom" <d98macke@dtek.chalmers.se> wrote in message news:<9g2sps$nu8$1@news.gu.se>...
> There is probably a good reason why they aren't allowed, but I can't think
> of one, so if someone could explain why I'd be really grateful. I personally
> like local functions, esp. in Ada, and all this template stuff generally
> requires both small functions and small classes that are very local.
>
> (I don't have D&E currently, being a poor student and all that..)
>
The dog actually ate mine ... but that's another story ;-)

Are local struct/classes with inline functions permitted?

eg

void func()
{
    struct hidden {
        bool operator()(int a, int b) const {
            return a > b;
        }
    };
    //...
}

I recall having problems with these sort of constructs
in Andrei's Loki (ie having to move them elsewhere for
the code to work with g++)

cheers
Nick



> /Marcus
>
>
> ---
> [ 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://www.research.att.com/~austern/csc/faq.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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Marcus Lindblom" <d98macke@dtek.chalmers.se>
Date: Tue, 12 Jun 2001 21:36:05 GMT
Raw View
"Barry Margolin" <barmar@genuity.net> wrote in message
news:rtvV6.21$5G3.219@burlma1-snr2...
> In article <9g5v8p$25n$1@news.gu.se>,
> Marcus Lindblom <d98macke@dtek.chalmers.se> wrote:
> >What if AA wasn't allowed to access B? Would that remove too much of the
> >usefulness? (That was what I had in mind initially, it would be less
> >versatile, but still quite good.)
>
> If AA isn't allowed to access variables in the enclosing environment, then
> what's the point of defining it locally?

Much the same reasons as to why local classes exist (unless there is
something in there I don't know about).

Clearer syntax (putting things closer to where they belong), hiding (not
exposing that function) plus allowing access to static variables would still
work, right?

One could put all local functions in an anonymous namespace right before
each 'parent function' and get halfway there, I assume. But I'm after
something that is similar to the 'where' keyword in Haskell.

And what about local classes in functions?

/Marcus


---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Marcus Lindblom" <d98macke@dtek.chalmers.se>
Date: Mon, 11 Jun 2001 18:28:31 GMT
Raw View
There is probably a good reason why they aren't allowed, but I can't think
of one, so if someone could explain why I'd be really grateful. I personally
like local functions, esp. in Ada, and all this template stuff generally
requires both small functions and small classes that are very local.

(I don't have D&E currently, being a poor student and all that..)

/Marcus


---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Marcus Lindblom" <d98macke@dtek.chalmers.se>
Date: Tue, 12 Jun 2001 22:29:26 GMT
Raw View
"Nick Thurn" <nick.thurn@db.com> wrote in message
news:62cbbbdf.0106120011.698c78b9@posting.google.com...
> Are local struct/classes with inline functions permitted?

Yes, it seems that way. (And so, I've made a fool out of myself in the
previous post).

[snip]
> I recall having problems with these sort of constructs
> in Andrei's Loki (ie having to move them elsewhere for
> the code to work with g++)

That compiles here (MSVC 6.0). Accessing variables (auto/args/static)
declared in the function does not work however.

/Marcus


---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: marco@technoboredom.net (Marco Manfredini)
Date: Tue, 12 Jun 2001 23:51:31 GMT
Raw View
"Marcus Lindblom" <d98macke@dtek.chalmers.se> wrote in
news:9g5v8p$25n$1@news.gu.se:

> "Marco Manfredini" <marco@technoboredom.net> wrote in message
> news:Xns90BE9DC195344marcotechnobore@technoboredom.net...
>> The problem with a local function is, that it requires a pointer
>> to the enclosing environment (the current stackframe or what ever,
>> of the enclosing function body). Take this hypothetical piece of
>> code:
>>
>> int A(int a)
>> {
>>     int b=a*2;
>>     int AA(int aa)
>>     {
>>         return aa+b+a;
>>     }
>>
>>     return AA(a+b); }
>
> What if AA wasn't allowed to access B? Would that remove too much
> of the usefulness? (That was what I had in mind initially, it would
> be less versatile, but still quite good.)
>

local functions could be done the way local classes are done, that is
lexically bound to the types and static's of the enclosing function (as
an encapsulation feature) - but binding to the current stack frame would
much, much more powerful than that.

>> There a two ways to implement this: rewrite AA to accept an extra
>> parameter to the A's current stackframe (here simulated with a
>> struct)
> [snip]
>
> I wasn't aware of the stackframe problem. (After thinking trying
> some naive stuff, I realise the problem.) Can't we just disallow
> recursive calls and use a global pointer to A's stack frame? ;)

Doesn't work, AA could call something that calls A in turn, the compiler
can't check that.

>
> Ada doesn't allow sending the adress of a local function to a more
> globally declared function (if I understand things correctly),
> perhaps the same restriction could be applied here?

Hmm. I don't quite understand the Ada restiction. Pascal doesn't allow
to take the adress of a function pointer in general - their way.

Anyway, if you want *some kind* of local functions, you can write a
local class that performs the job. Local classes have access to the
types and the statics defined in the function. Using a special trick,
they can be actually made looking like function:

void A(int b)
{
 static int x=2; // here a static
 class SomeFun // here's a local "function"
 {
  int result;
  public:

  SomeFun(int z) { result = z+x; }
  operator int () { return result; }
 };

 return b+SomeFun(b+b);
}

[Note: Accessing x in my example does not work with the Microsoft "C++"
"Compiler". Try this with GNU/Borland or Intel]

>
> If I'm being an ignorant bastard not knowing when to shut up, just
> tell me.
>:)

If you ask the google newsgroup archive for 'closure' and 'c++' you'll
get >5000 hits, so this is probably not the dumbest question.

--
Marco

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Paul Mensonides" <pmenso57@home.com>
Date: Wed, 13 Jun 2001 12:22:49 GMT
Raw View
"Marco Manfredini" <marco@technoboredom.net> wrote in message
news:Xns90BE9DC195344marcotechnobore@technoboredom.net...
> "Marcus Lindblom" <d98macke@dtek.chalmers.se> wrote in
> news:9g2sps$nu8$1@news.gu.se:
>
> > There is probably a good reason why they aren't allowed, but I
> > can't think of one, so if someone could explain why I'd be really
> > grateful. I personally like local functions, esp. in Ada, and all
> > this template stuff generally requires both small functions and
> > small classes that are very local.
> >
>
> The problem with a local function is, that it requires a pointer to the
> enclosing environment (the current stackframe or what ever, of the
> enclosing function body). Take this hypothetical piece of code:
>
> int A(int a)
> {
>     int b=a*2;
>     int AA(int aa)
>     {
>         return aa+b+a;
>     }
>
>     return AA(a+b);
> }
>
> There a two ways to implement this: rewrite AA to accept an extra
> parameter to the A's current stackframe (here simulated with a struct)
>
> struct AFrame
> {
>  int &a,&b;
>  AFrame(int &_a, int &_b) : a(_a), b(_b) {}
> };
>
> int A_AA(AFrame &aframe, int aa)
> {
>  return aa+aframe.b+aframe.a;
> }
>
> int A(int a)
> {
>     int b=a*2;
>     AFrame aframe(a,b);
>     return AA(aframe, a+b);
> }
>
> Well the struct isn't explicitly neccesary, since the compiler could
> pass a pointer to the stack and use it's known layout in AA. But in any
> case it would mean, that the signature of AA will change!! Therefore you
> will not be able to use it a function-pointer, AA is -not- a int (*)
> (int) anymore but some form of int(*)(AFrame &,int) - and how do you
> pass the function-pointer -and- the necesary AFrame? So this lacks
> generality.

I don't see why this is a big problem.  The function could be forced to be
completely private, and nested functions could be something that required
closure similar to member functions:

int main() {
    int a = 0;
    int add(int x) { // private function
        return x + a;
    }
    int substract(int x) { // private function
        int a; // hiding
        return x - this->a; // explicit reference
    }
    typedef int (main::* op)(int); // private typedef
    op lf = &add;
    int b = (*lf)(0); // closure with stack frame on call
    b = substract(2); // closure with stack frame here also
    return 0;
}

The functions add() and substract() would only be able to access those
declarations that are declared prior to the function's definition and/or first
declaration (if you are allowed to define the local function outside the parent
function).  Therefore, only a compile-time stack offset would be necessary to
implement it stablily.  This requires no runtime code generation.  It only
introduces a slightly new syntax (which is orthogonal to member functions) for
local function pointers.  It requires no new keywords, breaks no existing code,
and only implies a very slight overhead of an indirection for each use of local
variable from a directly enclosing scope.  Multiply nested functions can be
handled similarly:

int main() {
    int local_var1 = 0;
    int f() { // implicitly passed a stack offset to main()
        int local_var2 = 0;
        int g() { // implicitly pass a stack offset to f()
            return local_var2 + localvar1;
        }
        return g();
    }
}

Within a given nested function, an offset can be treated as a const.  Therefore,
the compiler knows full well that access to local_var2 in g() requires the
offset to f() and that access to local_var1 requires the offset to f() and the
offset from f() to main().  I am not as familiar with stack layout as I should
be, so maybe a simple offset closure would not work.  However, a pointer could
achieve the same effect, and that pointer could be stored on the stack for ease
of implementation of multiple nested functions.

i.e. in the case of g(), &local_var1 == f_stk->main_stk->local_var1.

Paul Mensonides

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Carl Daniel" <cpdaniel@pacbell.net>
Date: Wed, 13 Jun 2001 14:01:57 GMT
Raw View
"Paul Mensonides" <pmenso57@home.com> wrote in message
news:k5EV6.161148$p33.3390192@news1.sttls1.wa.home.com...
>
> "Marco Manfredini" <marco@technoboredom.net> wrote in message
> news:Xns90BE9DC195344marcotechnobore@technoboredom.net...
> > "Marcus Lindblom" <d98macke@dtek.chalmers.se> wrote in
> > news:9g2sps$nu8$1@news.gu.se:
> >
>
[snip]

> Within a given nested function, an offset can be treated as a const.
Therefore,
> the compiler knows full well that access to local_var2 in g() requires the
> offset to f() and that access to local_var1 requires the offset to f() and
the
> offset from f() to main().  I am not as familiar with stack layout as I
should
> be, so maybe a simple offset closure would not work.  However, a pointer
could
> achieve the same effect, and that pointer could be stored on the stack for
ease
> of implementation of multiple nested functions.
>

Unfortunately, a simple offset cannot be used - a pointer is required.  In
the case of a recursive local function, the distance between the local
function's stack variables and the parent function's stack variables
increases with each recursion.

I'd really like to see C++ add a feature to support local functions and
closures for all the reasons that have already been mentioned.  In my mind,
there's a logical and straightforward progression, lacking only the
definition of a little bit of syntax and a bit of code generation ability.

Ordinary member function:
class A
{
    int m1;
    int m2;
    int f();
    void g();
}

In order to call f(), one requires an A* and the address of f() (unless it's
inline, but that's an orthogonal complication).

Local function:
void main()
{
  int l1;
  int l2;

  int f()
  {
    // access l1 and/or l2
  }

  // more of main...
}

In order to call f(), one requires a "main*" (imagine a struct which matches
the layout of local variables which are in-scope at the point of f's
definition/declaration) and the address of ().

With a suitable syntax, closures (at least upward closures (or is it
downward?  whatever)) can be implemented as unnamed local functions.

With one more addition, a new family of types for "pointer to bound
function", local functions & closures could be harmoniously integrated with
the rest of the C++ type system and with templates.

-cd

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Carl Daniel" <cpdaniel@pacbell.net>
Date: Wed, 13 Jun 2001 14:09:17 GMT
Raw View
"Marcus Lindblom" <d98macke@dtek.chalmers.se> wrote in message
news:9g2sps$nu8$1@news.gu.se...
> There is probably a good reason why they aren't allowed, but I can't think
> of one, so if someone could explain why I'd be really grateful. I
personally
> like local functions, esp. in Ada, and all this template stuff generally
> requires both small functions and small classes that are very local.
>
> (I don't have D&E currently, being a poor student and all that..)
>

As others have posted, the problem with local functions is that they're a
different kind of beast than ordinary functions.  In fact, they share a LOT
with ordinary (non-static, non-virtual) member functions - to call such
beasts requires two pieces of information: a context (object or stack frame)
and the address of the function.  The combination of the two is sometimes
referred to as a bound function.

Having local functions would not require supporting
pointer-to-bound-function as a type (afterall, Pascal has local functions,
and it doesn't support such a type), but the lack of such a type would be a
serious inconsistency with the rest of the language (after all, we have
ordinary pointers to functions and pointers to member functions).  Having
local functions does not require generating "trampoline" functions at
run-time either - that's a hack to shoe-horn local functions into the
existing 'C' pointer-to-function machinery.

Personally, I'd love to see "pointer to bound function" added as a class of
types in C++.  It's a key building block of properly supporting closures and
local functions in general, and would heal a wart with pointer-to-member
function that exists now (that being that most uses of
pointer-to-member-function end up carting around two pointers: a PMF and a
pointer to an object - pointer-to-bound-function simply formalizes & cements
the relationship between such pairs of pointers).

-cd


---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Al Grant" <tnarga@arm.REVERSE-NAME.com>
Date: Wed, 13 Jun 2001 14:09:25 GMT
Raw View
"Marcus Lindblom" <d98macke@dtek.chalmers.se> wrote in message
news:9g5v8p$25n$1@news.gu.se...
> What if AA wasn't allowed to access B?

That is exactly the BCPL local functions rule - that
local functions cannot access "dynamic" (i.e. auto)
"free" (i.e. not defined within the local function)
variables.  It makes local functions a code structuring
mechanism with no runtime implications.

I guess the real reason it did not carry over to C is
because with C's function syntax it would be a lot
harder to parse.  In BCPL this was not a problem as
definitions were introduced with the keyword LET.



---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: celtschk@web.de ("Christopher Eltschka")
Date: Wed, 13 Jun 2001 14:11:38 GMT
Raw View
"Marcus Lindblom" <d98macke@dtek.chalmers.se> writes:

> "Marco Manfredini" <marco@technoboredom.net> wrote in message
> news:Xns90BE9DC195344marcotechnobore@technoboredom.net...
> > The problem with a local function is, that it requires a pointer to the
> > enclosing environment (the current stackframe or what ever, of the
> > enclosing function body). Take this hypothetical piece of code:
> >
> > int A(int a)
> > {
> >     int b=a*2;
> >     int AA(int aa)
> >     {
> >         return aa+b+a;
> >     }
> >
> >     return AA(a+b);
> > }
>
> What if AA wasn't allowed to access B? Would that remove too much of the
> usefulness? (That was what I had in mind initially, it would be less
> versatile, but still quite good.)

It would IMHO remove much of the usefulness. More exactly, it
wouldn't give you anything not possible today, although with
a slightly more complicated syntax:

int A(int a)
{
  struct local
  {
    static int AA(int aa)
    {
      return aa+1;
    }
  };

  return local::AA(5);
}

Note that local::AA is an ordinary function which can be assigned
to normal function pointers and passed around. It cannot, however,
access A's local variables.

[...]

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: marco@technoboredom.net (Marco Manfredini)
Date: Wed, 13 Jun 2001 14:43:57 GMT
Raw View
"Paul Mensonides" <pmenso57@home.com> wrote in
news:k5EV6.161148$p33.3390192@news1.sttls1.wa.home.com:

>
> "Marco Manfredini" <marco@technoboredom.net> wrote in message
> news:Xns90BE9DC195344marcotechnobore@technoboredom.net...
>>
>> Well the struct isn't explicitly neccesary, since the compiler
>> could pass a pointer to the stack and use it's known layout in AA.
>> But in any case it would mean, that the signature of AA will
>> change!! Therefore you will not be able to use it a
>> function-pointer, AA is -not- a int (*) (int) anymore but some
>> form of int(*)(AFrame &,int) - and how do you pass the
>> function-pointer -and- the necesary AFrame? So this lacks
>> generality.
>
> I don't see why this is a big problem.  The function could be
> forced to be completely private, and nested functions could be
> something that required closure similar to member functions:
>
> int main() {
>     int a = 0;
>     int add(int x) { // private function
>         return x + a;
>     }
>     int substract(int x) { // private function
>         int a; // hiding
>         return x - this->a; // explicit reference
>     }
>     typedef int (main::* op)(int); // private typedef
>     op lf = &add;
>     int b = (*lf)(0); // closure with stack frame on call
>     b = substract(2); // closure with stack frame here also
>     return 0;
> }
>
> The functions add() and substract() would only be able to access
> those declarations that are declared prior to the function's
> definition and/or first declaration (if you are allowed to define
> the local function outside the parent function).  Therefore, only a
> compile-time stack offset would be necessary to implement it
> stablily.  This requires no runtime code generation.  It only
> introduces a slightly new syntax (which is orthogonal to member
> functions) for local function pointers.  It requires no new
> keywords, breaks no existing code, and only implies a very slight
> overhead of an indirection for each use of local variable from a
> directly enclosing scope.  Multiply nested functions can be handled
> similarly:
>
> int main() {
>     int local_var1 = 0;
>     int f() { // implicitly passed a stack offset to main()
>         int local_var2 = 0;
>         int g() { // implicitly pass a stack offset to f()
>             return local_var2 + localvar1;
>         }
>         return g();
>     }
> }
>
> Within a given nested function, an offset can be treated as a
> const.  Therefore, the compiler knows full well that access to
> local_var2 in g() requires the offset to f() and that access to
> local_var1 requires the offset to f() and the offset from f() to
> main().  I am not as familiar with stack layout as I should be, so
> maybe a simple offset closure would not work.  However, a pointer
> could achieve the same effect, and that pointer could be stored on
> the stack for ease of implementation of multiple nested functions.
>
> i.e. in the case of g(), &local_var1 ==
> f_stk->main_stk->local_var1.
>

You can call the local function only from the defining environment. This
is very likely to Pascal, I think, but it lacks the ability to treat the
local function as a regular function, i.e. passing pointers of it
around.

However you are right when you argue that a simple const-offset approach
might not work with C++. Here is what I mean:

void foo(int n)
{
 int p;
 void bar()
 {
 }

 bar(); // ok given offset to the current stack.
 {
  int k[10];
  bar(); // now the offset is changed by 40 bytes, the compiler can
correct this, by generating a different entry to bar, which uses a
different offset
  {
   void *p=alloca(n);
   bar(); // and now?
  }
 }
}

In the last invocation of bar() the stack-offset is unknown. The only
way to determine the original defining environment of bar (where only p
and n are) is to keep a pointer to it. This pointer has bar to be given
knowledge. So one can forget about the const offsets, since we need a
hidden parameter anyway.

--
Marco

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: marco@technoboredom.net (Marco Manfredini)
Date: Wed, 13 Jun 2001 14:53:07 GMT
Raw View
"Carl Daniel" <cpdaniel@pacbell.net> wrote in
news:uECV6.1823$FS6.165894@news.pacbell.net:

>
>
> Personally, I'd love to see "pointer to bound function" added as a
> class of types in C++.  It's a key building block of properly
> supporting closures and local functions in general, and would heal
> a wart with pointer-to-member function that exists now (that being
> that most uses of pointer-to-member-function end up carting around
> two pointers: a PMF and a pointer to an object -
> pointer-to-bound-function simply formalizes & cements the
> relationship between such pairs of pointers).
>

I think you will find many people in this NG that will reject the idea
to add more builtin types to the language. I recently had the idea, that
instead of adding a type to the language for, say, the implementation of
"real" bound member functions, C++ should provide a way to delegate the
implementation to the user:

class A
{
  int foo(int k);
};

template<class FN>
void call(FN fn, int arg)
{
 cout << fn(arg);
}

void use()
{
 A a;
 call(a.foo, 3); // (!)
}

The (!) doesn't work currently in C++. The idea is now, that the
compiler sees, that a.foo is a bound member function expression that is
NOT used to call the member. Instead of giving you an error message for
that, he treats the expression "a.foo" as the invocation of an new
operator "operator PMF" which has to return an object that can be used
in a function-calling form. Example:

user defined closure for A:
class XY
{
 A &a;
 int (A::*fn)(int);
 XY(A &_a, int (A::*_fn)(int)) : a(_a), fn(_fn) {}
 int operator () (int x) { return a.*fn(x); }
};

+ user defined closure operator:

XY operator PMF(A &a, int (A::*fn)(int)) { return XY(a,fn); }

replaces "call(a.foo,x);"
with "call(operator PMF(a,foo),3);"

(Just simplified, you'd prepare some more general template impl)

Currently resistance against new language features is based onto 2 good
points: a) They add complexity to the compiler b) There is no good
compromise between generality and overhead.

The nice thing about the above idea is, that it a) minimizes the the
burden to the compiler, since it can be implemented without adding new
entities to the type system or semantics. It's just a replacement in the
syntax tree. b) leaves it to the user to select an implementation which
fits his generality/overhead/memory management needs.

--
Marco

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]