From: V.Ch.
Subject: Please help to understand closures
Date: 
Message-ID: <d6337j$2u09$1@gavrilo.mtu.ru>
Even after reading about closures in "ANSI Common Lisp", I still don't 
quite understand them. More specifically, the way I understand them, 
they don't look such a great thing as the author suggests.

I understand that a closure is a set of functions sharing a state.
But in that case, it can be very easily achieved in such unglamorous and 
totally uncool language as C++. Just create a class - all member 
variables is your state, and public methods - your functions. And it 
seems to be much more powerfull construction - you have more control 
over the state, and you don't have to share the state between all you 
functions.

In a way, closures in Lisp look like static function variables in C++ - 
the thing I normally try to avoid, because "globality" of such variables 
greatly limits the number of usage scenarios, e.g. just think about 
multithreading.

Given all this, I think that perhaps I don't quite understand what 
closures really are?

From: Tayssir John Gabbour
Subject: Re: Please help to understand closures
Date: 
Message-ID: <1116020638.182485.158240@z14g2000cwz.googlegroups.com>
V.Ch. wrote:
> Even after reading about closures in "ANSI Common Lisp", I still
> don't quite understand them. More specifically, the
> way I understand them, they don't look such a great thing as the
> author suggests.
>
> I understand that a closure is a set of functions sharing a state.
> But in that case, it can be very easily achieved in such
> unglamorous and totally uncool language as C++. Just create a class
> - all member variables is your state, and public methods - your
> functions. And it seems to be much more powerfull construction -
> you have more control over the state, and you don't have to share
> the state between all you functions.
>
> In a way, closures in Lisp look like static function variables in
> C++ - the thing I normally try to avoid, because "globality" of
> such variables greatly limits the number of usage scenarios, e.g.
> just think about multithreading.
>
> Given all this, I think that perhaps I don't quite understand what
> closures really are?

Your bewilderment is common and correct. I just think of them as
"functions done sanely" or "lexical bubbles". They're not exciting,
just extremely handy at times. And even now uncommon.

And yes, "lambda" is an awful name. Life goes on.
From: Ron Garret
Subject: Re: Please help to understand closures
Date: 
Message-ID: <rNOSPAMon-C7BE81.19034313052005@news.gha.chartermi.net>
In article <·············@gavrilo.mtu.ru>, "V.Ch." <····@notreal.com> 
wrote:

> Even after reading about closures in "ANSI Common Lisp", I still don't 
> quite understand them.

Try: http://www.flownet.com/ron/specials.pdf

rg
From: Pascal Costanza
Subject: Re: Please help to understand closures
Date: 
Message-ID: <3ekjcdF3n9mjU1@individual.net>
V.Ch. wrote:
> Even after reading about closures in "ANSI Common Lisp", I still don't 
> quite understand them. More specifically, the way I understand them, 
> they don't look such a great thing as the author suggests.
> 
> I understand that a closure is a set of functions sharing a state.
> But in that case, it can be very easily achieved in such unglamorous and 
> totally uncool language as C++. Just create a class - all member 
> variables is your state, and public methods - your functions.

Exactly. You have to create a class, which means quite an effort. 
Closures are "just" objects with shared variables and a function that 
can be executed. There are two advantages of closures:

- You can create them on the fly, without the need to declare or define 
anything somewhere else, like the classes you have in mind. You also 
don't have to worry to decide upfront which variables you want to share 
and which not. Just use the ones you want, and Lisp will take care of 
creating the correct internal structures for that. With classes, you 
always have the overhead of extending them when you need more, or 
reducing them when you need less.

- The code that is associated with a closure is in just one function. 
Because it is just one function, it doesn't need a name. In a class, all 
the methods have to be named. This means that you need more source code 
at call sites. In the cases in which closures are effectively simulated, 
the names are typically very boring, like "execute", "perform" or the 
like. This indicates that the name is rather useless. With closures, 
it's much more straightforward to actually call them.

So one way to think about closures is that they are objects that are 
very light-weight in terms of programming overhead. This can be very 
handy, and when you get used to it you tend to use them quite often.

However, some people, including Paul Graham, are indeed overemphasizing 
some language constructs at the expense of others. Paul Graham doesn't 
like object-oriented programming, and to him closures are "all you 
need". Indeed, it's relatively straightforward to build a simple 
object-oriented system only with closures.

I understand where that view comes from: The less concepts a language 
has the less details about the language you have to keep in your head. 
There's also a danger that complex languages distract you from solving 
your actual problem, but instead make you think about the language 
itself (instead of the problem). However, I think that in the long run, 
such "minimalists" only shift the complexity, but don't remove it: If 
you need to build all the machinery yourself that an advanced OOP system 
gives you for free, you have to remember the details of your own system 
later on. There's a trade-off here: If your system is simpler than, say, 
CLOS you need to remember less. If your system becomes more complex over 
time, though, there's noone else to ask when you get into trouble.

Greenspun's tenth rule means that all programs tend to get complex 
enough that they are in fact reimplementing a considerable amount of 
what more full-fledged languages already give you from the start.

> Given all this, I think that perhaps I don't quite understand what 
> closures really are?

No, you have just not used them a lot yet.


Pascal

-- 
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
From: Kenny Tilton
Subject: Re: Please help to understand closures
Date: 
Message-ID: <W59he.8937$yl6.3924574@twister.nyc.rr.com>
Pascal Costanza wrote:
> I understand where that view comes from: The less concepts a language 
> has the less details about the language you have to keep in your head. 

WTF does that mean, btw? I know Graham said it, but I have the same 
question for him.

Can someone tell me which part of Common Lisp I am having trouble 
keeping in my head? Spare me anything available a keystroke away in the 
hyperspec, such as abstruse FORMAT directives.

Am I just smarter than everyone else?

:)

kenny
From: Pascal Costanza
Subject: Re: Please help to understand closures
Date: 
Message-ID: <3ekm6kF3mnbdU1@individual.net>
Kenny Tilton wrote:
> Pascal Costanza wrote:
> 
>> I understand where that view comes from: The less concepts a language 
>> has the less details about the language you have to keep in your head. 
> 
> WTF does that mean, btw? I know Graham said it, but I have the same 
> question for him.

Simple: If your lanugage doesn't provide OO, you don't have to remember 
the details of method dispatch, inheritance rules, order of 
initialization, and so forth. If your language doesn't have, say, 
numbers, you don't have to remember the details of arithmetics. And so 
on. ;)

> Can someone tell me which part of Common Lisp I am having trouble 
> keeping in my head? Spare me anything available a keystroke away in the 
> hyperspec, such as abstruse FORMAT directives.

The argument only matters when you think that the overhead of learning 
OOP, FORMAT, LOOP, numbers, etc. doesn't pay off.

> Am I just smarter than everyone else?
> 
> :)

No, just smarter than Paul Graham. ;)


Pascal

-- 
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
From: Kenny Tilton
Subject: Re: Please help to understand closures
Date: 
Message-ID: <l%9he.8939$yl6.3929690@twister.nyc.rr.com>
Pascal Costanza wrote:
> Kenny Tilton wrote:
> 
>> Pascal Costanza wrote:
>>
>>> I understand where that view comes from: The less concepts a language 
>>> has the less details about the language you have to keep in your head. 
>>
>>
>> WTF does that mean, btw? I know Graham said it, but I have the same 
>> question for him.
> 
> 
> Simple: If your lanugage doesn't provide OO, you don't have to remember 
> the details of method dispatch,...

Duh-uhhhh! My question is, who cannot remember the language they are 
using? I should limit that to Common Lisp, because it works so 
predictably syntactically and in the functionality of all those functions.

To make it worse, Graham is designing a language for smart programmers 
(who cannot remember whether :before methods run most or least specific 
first, I guess).

I think this dog of an issue simply won't hunt.

>> Am I just smarter than everyone else?
>>
>> :)
> 
> 
> No, just smarter than Paul Graham. ;)

I heard him at ILC 2003 and can rule this out.

:)

kt
From: André Thieme
Subject: Re: Please help to understand closures
Date: 
Message-ID: <d658b1$p06$1@ulric.tng.de>
Kenny Tilton schrieb:

> My question is, who cannot remember the language they are using?

 > ...


>>> Am I just smarter than everyone else?
>>
>> No, just smarter than Paul Graham. ;)
> 
> I heard him at ILC 2003 and can rule this out.

Perhaps this example shows why Graham is right?
Graham thinks that people can forget simple things.

Now the same happened to you. You heared Graham at ILC and from this
moment you knew he is smarter than you. It means there exist at least
one person who is smarter than you. But anyway, you were asking if you
were smarter than everyone else - although you knew the answer.
It is simply because you forgot the detail.
Sounds logical, hmm?


Andr�
--

PS: I think Kenny is smarter than I am.
From: Kenny Tilton
Subject: Re: Please help to understand closures
Date: 
Message-ID: <yCuhe.596$mt.214@twister.nyc.rr.com>
Andr� Thieme wrote:
> Kenny Tilton schrieb:
> 
>> My question is, who cannot remember the language they are using?
> 
> 
>  > ...
> 
> 
>>>> Am I just smarter than everyone else?
>>>
>>>
>>> No, just smarter than Paul Graham. ;)
>>
>>
>> I heard him at ILC 2003 and can rule this out.
> 
> 
> Perhaps this example shows why Graham is right?
> Graham thinks that people can forget simple things.
> 
> Now the same happened to you. You heared Graham at ILC and from this
> moment you knew he is smarter than you. It means there exist at least
> one person who is smarter than you. But anyway, you were asking if you
> were smarter than everyone else - although you knew the answer.
> It is simply because you forgot the detail.
> Sounds logical, hmm?

If my question was rhetorical, your argument collapses in a heap.

> PS: I think Kenny is smarter than I am.

I am just a simple application programmer.

:)

kt

-- 
Cells? Cello?: http://www.common-lisp.net/project/cells/
Cells-Gtk?: http://www.common-lisp.net/project/cells-gtk/
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film

"Doctor, I wrestled with reality for forty years, and I am happy to 
state that I finally won out over it." -- Elwood P. Dowd
From: André Thieme
Subject: Re: Please help to understand closures
Date: 
Message-ID: <d666ot$ki0$1@ulric.tng.de>
Kenny Tilton schrieb:

>> PS: I think Kenny is smarter than I am.
> 
> I am just a simple application programmer.

You understand how Cells work, I don't.
Are you still working on your GUI-System Cello?


Andr�
--
From: Kenny Tilton
Subject: Re: Please help to understand closures
Date: 
Message-ID: <dEyhe.9736$yl6.4065253@twister.nyc.rr.com>
Andr� Thieme wrote:
> Kenny Tilton schrieb:
> 
>>> PS: I think Kenny is smarter than I am.
>>
>>
>> I am just a simple application programmer.
> 
> 
> You understand how Cells work, I don't.

You never asked. That is lack of will, not intelligence. Your logic 
continues to disappoint. :)

You should have asked. I am just finishing up a new use case (stock 
index tracker) for someone crazy enough to ask for help on his Cells 
project. Want to be a reader so I can make it more understandable?

> Are you still working on your GUI-System Cello?

Yes. Developing a PDF backend tight now, looking at VRML support as 
well. Text-to-speech would rock. Libraries!

kenny

-- 
Cells? Cello?: http://www.common-lisp.net/project/cells/
Cells-Gtk?: http://www.common-lisp.net/project/cells-gtk/
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film

"Doctor, I wrestled with reality for forty years, and I am happy to 
state that I finally won out over it." -- Elwood P. Dowd
From: Joel Ray Holveck
Subject: Re: Please help to understand closures
Date: 
Message-ID: <y7czmutmdez.fsf@sindri.juniper.net>
>> Perhaps this example shows why Graham is right?
> If my question was rhetorical, your argument collapses in a heap.

He could have avoided that by declaring his argument to be dynamic, so
it could be stack-allocated.  Not only would it not be in a heap, but
it wouldn't collapse; the stack pointer would just be moved after the
extent ended (which seems to have been about two days ago).

Of course, then I couldn't refer to his argument now like I'm doing,
since its extent ended.  But if it had been dynamic, then your
response wouldn't have saved it, and I wouldn't have to.

I think I need a break from coding.

joelh
From: Peter Seibel
Subject: Re: Please help to understand closures
Date: 
Message-ID: <m3br7baxhw.fsf@gigamonkeys.com>
Pascal Costanza <··@p-cos.net> writes:

> However, some people, including Paul Graham, are indeed
> overemphasizing some language constructs at the expense of others.
> Paul Graham doesn't like object-oriented programming, and to him
> closures are "all you need". Indeed, it's relatively straightforward
> to build a simple object-oriented system only with closures.

I'd second that. Closures are handy but Graham, IMO, overemphasizes
them. If you want to take a run at Lisp using a book that doesn't put
quite so much emphasis on them, you might check out:

  <http://www.gigamonkeys.com/book/>

or the treeware version:

  <http://www.amazon.com/exec/obidos/ASIN/1590592395>

-Peter

-- 
Peter Seibel                                     ·····@gigamonkeys.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Pascal Bourguignon
Subject: Re: Please help to understand closures
Date: 
Message-ID: <871x8710l7.fsf@thalassa.informatimago.com>
Peter Seibel <·····@gigamonkeys.com> writes:

> Pascal Costanza <··@p-cos.net> writes:
>
>> However, some people, including Paul Graham, are indeed
>> overemphasizing some language constructs at the expense of others.
>> Paul Graham doesn't like object-oriented programming, and to him
>> closures are "all you need". Indeed, it's relatively straightforward
>> to build a simple object-oriented system only with closures.
>
> I'd second that. Closures are handy but Graham, IMO, overemphasizes
> them. 

It's hard to speak about lisp without emphasizing one feature or the
other, given we speak linearly, because all the features are needed to
make this great language.  Yes, closure alone are not so great, yes,
parentheses are not great, yes, macros alone are not really great.
But put them all in one bag and you have a super great language.

Does Graham's text speaks only about closures?  Or should we consider
the whole book.

> If you want to take a run at Lisp using a book that doesn't put
> quite so much emphasis on them, you might check out:
>
>   <http://www.gigamonkeys.com/book/>
>
> or the treeware version:
>
>   <http://www.amazon.com/exec/obidos/ASIN/1590592395>
>
> -Peter
>
> -- 
> Peter Seibel                                     ·····@gigamonkeys.com
>
>          Lisp is the red pill. -- John Fraser, comp.lang.lisp

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Until real software engineering is developed, the next best practice
is to develop with a dynamic system that has extreme late binding in
all aspects. The first system to really do this in an important way
is Lisp. -- Alan Kay
From: Edi Weitz
Subject: Re: Please help to understand closures
Date: 
Message-ID: <uhdh3vwv2.fsf@agharta.de>
On Mon, 16 May 2005 20:34:44 +0200, Pascal Bourguignon <···@informatimago.com> wrote:

> Peter Seibel <·····@gigamonkeys.com> writes:
>
>> Closures are handy but Graham, IMO, overemphasizes them.
>
> It's hard to speak about lisp without emphasizing one feature or the
> other, given we speak linearly, because all the features are needed
> to make this great language.  Yes, closure alone are not so great,
> yes, parentheses are not great, yes, macros alone are not really
> great.  But put them all in one bag and you have a super great
> language.
>
> Does Graham's text speaks only about closures?  Or should we
> consider the whole book.

Which part of "overemphasizes" did you not understand?

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: jonathon
Subject: Re: Please help to understand closures
Date: 
Message-ID: <1116269134.637163.26170@g47g2000cwa.googlegroups.com>
Edi Weitz wrote:
> Which part of "overemphasizes" did you not understand?

Why, yes, I *do* still beat my wife.  Why do you ask?
From: Pascal Bourguignon
Subject: Re: Please help to understand closures
Date: 
Message-ID: <87wtpyzxi0.fsf@thalassa.informatimago.com>
Edi Weitz <········@agharta.de> writes:

> On Mon, 16 May 2005 20:34:44 +0200, Pascal Bourguignon <···@informatimago.com> wrote:
>
>> Peter Seibel <·····@gigamonkeys.com> writes:
>>
>>> Closures are handy but Graham, IMO, overemphasizes them.
>>
>> It's hard to speak about lisp without emphasizing one feature or the
>> other, given we speak linearly, because all the features are needed
>> to make this great language.  Yes, closure alone are not so great,
>> yes, parentheses are not great, yes, macros alone are not really
>> great.  But put them all in one bag and you have a super great
>> language.
>>
>> Does Graham's text speaks only about closures?  Or should we
>> consider the whole book.
>
> Which part of "overemphasizes" did you not understand?

This one.  When I copy the text from the file 
http://www.paulgraham.com/lib/paulgraham/onlisp.pdf
then s/[ ,:.;]\+/ /g, then count each word, I get:

(("MACRO" . 1123)
 ("CLOSURE" . 109)
 ("FUNCTION" . 1118)
 ("OBJECT" . 167)
 ("PARENTHESIS" . 4)
 ("PARENTHESES" . 5))>

So the part of "overemphasizes" I don't understand is that where the
number of occurences of the closure/closures word is ten times less
than that of macro/macros or function/functions, and is even less than
that of object/objects.

I note objects get one whole chapter while closures are only a little
section in the chapter about functions.

But perhaps Pascal had in mind another of Paul's book?


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

There is no worse tyranny than to force a man to pay for what he does not
want merely because you think it would be good for him. -- Robert Heinlein
From: Pascal Costanza
Subject: Re: Please help to understand closures
Date: 
Message-ID: <3esneiF4mcl3U1@individual.net>
Pascal Bourguignon wrote:

> Edi Weitz <········@agharta.de> writes:
> 
>>On Mon, 16 May 2005 20:34:44 +0200, Pascal Bourguignon <···@informatimago.com> wrote:
>>
>>>Does Graham's text speaks only about closures?  Or should we
>>>consider the whole book.
>>
>>Which part of "overemphasizes" did you not understand?
> 
> This one.  When I copy the text from the file 
> http://www.paulgraham.com/lib/paulgraham/onlisp.pdf
> then s/[ ,:.;]\+/ /g, then count each word, I get:
> 
> (("MACRO" . 1123)
>  ("CLOSURE" . 109)
>  ("FUNCTION" . 1118)
>  ("OBJECT" . 167)
>  ("PARENTHESIS" . 4)
>  ("PARENTHESES" . 5))>
> 
> So the part of "overemphasizes" I don't understand is that where the
> number of occurences of the closure/closures word is ten times less
> than that of macro/macros or function/functions, and is even less than
> that of object/objects.
> 
> I note objects get one whole chapter while closures are only a little
> section in the chapter about functions.
> 
> But perhaps Pascal had in mind another of Paul's book?

I haven't had a particular book in mind when I made that statement. Paul 
Graham regularly plays the role of OOP down, in talks, discussions and 
his writings.

But I can quote from "On Lisp":

"The objects of object-oriented programming can easily be implemented as 
Lisp objects, and their methods as lexical closures. By taking 
advantage of such isomorphisms, we were able to provide a rudimentary 
form of object-oriented programming in just a few lines of code, and a 
sketch of CLOS in a few pages."

"Methods can do this because, underneath the syntax, they are closures. 
In the expansion of a defmethod, its body appears intact in the body of 
a sharp-quoted lambda-expression."

"[...] the secret to understanding CLOS is to understand how it maps 
onto the fundamental abstractions of Lisp."

"With the addition of CLOS, Common Lisp has become the most powerful 
object-oriented language in widespread use. Ironically, it is also the 
language in which object-oriented programming is least necessary."

Doesn't sound to me like a strong advertisement for CLOS.

I think his reasoning is wrong here. You don't understand abstractions 
by understanding how they are implemented. That may be helpful, but it's 
not the most important aspect. This would be like saying that you 
understand Lisp best by understanding how it's mapped to INTEL assembler.

You don't have to mention a concept a lot when you want to overemphasize 
it. ;)


Pascal

-- 
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
From: Pascal Bourguignon
Subject: Re: Please help to understand closures
Date: 
Message-ID: <87br7azq8r.fsf@thalassa.informatimago.com>
Pascal Costanza <··@p-cos.net> writes:
> [...]
> "[...] the secret to understanding CLOS is to understand how it maps
> onto the fundamental abstractions of Lisp."
>
> "With the addition of CLOS, Common Lisp has become the most powerful
> object-oriented language in widespread use. Ironically, it is also the
> language in which object-oriented programming is least necessary."
>
> Doesn't sound to me like a strong advertisement for CLOS.

Perhaps it's more a discussion internal to the OO world.  The features
required to get the "OO" label depend on the author, and base lisp
(without CLOS) might match the most lax required feature set.

For example, http://c2.com/cgi/wiki?ObjectOrientedPurity
requires only:

    - encapsulation,
    - inheritance (or delegation), and
    - polymorphim.

Encapsulation: use the package system, or just use naming convention,
               or use closures with "encapsulated" data and procedures.
  
Inheritance (or delegation): inheritance is specified for structures;
                             delegation is easily implemented as any 
                             other procedural abstraction.

                [1]> (defstruct s a b c)
                S
                [2]> (defstruct (r (:include s)) x y z)
                R
                [3]> (make-r :a 1 :x 2)
                #S(R :A 1 :B NIL :C NIL :X 2 :Y NIL :Z NIL)
                [4]> (s-a (make-r :a 1 :x 2))
                1

Polymorphim: since variables are not typed (values are), you get 100%
             polymorphims 100% of the time:
                  (defun do-something-with-anything (anything)
                     (list anything anything))


So basic lisp is already OO.

Of course, I'd ask slightly more of a OO language, namely the dispatch
to different methods according to the type of (at least) one
argument. Generic functions will do.  All the rest is sugar.


> I think his reasoning is wrong here. You don't understand abstractions
> by understanding how they are implemented. That may be helpful, but
> it's not the most important aspect. This would be like saying that you
> understand Lisp best by understanding how it's mapped to INTEL
> assembler.

Perhaps not to INTEL, but it's a good way to understand something, to
explain it in terms of something else.  Formal semantics don't do
anything else.


> You don't have to mention a concept a lot when you want to
> overemphasize it. ;)

Right.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
From: Raffael Cavallaro
Subject: Re: Please help to understand closures
Date: 
Message-ID: <2005051701292916807%raffaelcavallaro@pasdespamsilvousplaitdotmaccom>
On 2005-05-16 19:48:52 -0400, Pascal Bourguignon <···@informatimago.com> said:

> Perhaps it's more a discussion internal to the OO world.  The features
> required to get the "OO" label depend on the author, and base lisp
> (without CLOS) might match the most lax required feature set.

Paul Graham has made it clear exactly why he isn't a very big fan of 
object oriented programming in his essay entitled "Why Arc Isn't 
Especially Object Oriented" at <http://www.paulgraham.com/noop.html>

FWIW, some of his reasons are similar to Pascal B's argument that lisp 
without CLOS already has the minimum feature set to be considered 
"object-oriented," although Paul Graham puts this more negatively for 
o-o fans: "Object-oriented programming is exciting if you have a 
statically-typed language without lexical closures or macros. To some 
degree, it offers a way around these limitations."
From: Pascal Bourguignon
Subject: Re: Please help to understand closures
Date: 
Message-ID: <871x8abyxo.fsf@thalassa.informatimago.com>
"V.Ch." <····@notreal.com> writes:

> Even after reading about closures in "ANSI Common Lisp", I still don't
> quite understand them. More specifically, the way I understand them,
> they don't look such a great thing as the author suggests.
>
> I understand that a closure is a set of functions sharing a state.
> But in that case, it can be very easily achieved in such unglamorous
> and totally uncool language as C++. Just create a class - all member
> variables is your state, and public methods - your functions. And it
> seems to be much more powerfull construction - you have more control
> over the state, and you don't have to share the state between all you
> functions.
>
> In a way, closures in Lisp look like static function variables in C++
> - 
> the thing I normally try to avoid, because "globality" of such
> variables greatly limits the number of usage scenarios, e.g. just
> think about multithreading.
>
> Given all this, I think that perhaps I don't quite understand what
> closures really are?

Indeed, objects can be implemented with closures, and when you don't
have closures,  you can simulate them with objects. 

But the advantage of closures over classes and objects is the same as
the advantage of anonymous functions (lambda) over named functions.
More, you can catch into a closure _lexical_ _variables_.  With
classes you must explicitely add members to the class and initialize
them, and they're not accessible as lexical local variables anymore in
the calling functions. 


It's much easier to write:

(defun g (a)
   (let ((v (* 3 a)))
     (lambda (b) (incf v b))))

(let ((c (g 1))) (print (list (c 1) (c 0) (c 1))))

than:

class gc {
public:
gc(int a);
int call(int b);
private:
int v;
}
gc::gc(int a){v=3*a;}
gc::call(int b){v+=b;return(b);}

{gc* c=new gc(1);printf("(%d %d %d)\n",c->call(1),c->call(0),c->call(1));}



And then, when you introduce macros, try to write the equivalent in C++:


(defmacro later (&body body) `(lambda () ,@body))
(defun now (later) (funcall later))

(defun example (a)
  (let ((b (read)))
    (later (setf b (g b a)))))

(let ((c (example 1))) 
   (print (list (now c) (now c))))


This kind of macro catching a closure is essential to UCW to give an
easy to use higher level language where you can attach to Web User
Interface items  expressions  that will be executed much later, after
the current page is sent back to the browser and the user clicks on
another link or button.

For example, one can write:

(let ((employee (find-employee name)))
   (<ucw:form
       (<ucw:input :type "submit" :action (increase-salary employee 100.00)
                                  :value "Increase Salary")))

The employee is found from the name that comes from the current
request (URL), it's a lexical local variable.  The code generates an
HTML form with an HTML input button  that when clicked will provoke
the execution of a closure containing (increase-salary employee 100.00)
in its body.  In a web site, there may be thousands of these
closures.  Now imagine writting a class for everyone of them.
And imagine what you'd need to write to implement <ucw:form and
<ucw:input in C++.  Good luck!


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Small brave carnivores
Kill pine cones and mosquitoes
Fear vacuum cleaner
From: Sampo Smolander
Subject: Re: Please help to understand closures
Date: 
Message-ID: <d63c7k$aoo$1@oravannahka.helsinki.fi>
Pascal Bourguignon <···@informatimago.com> wrote:
> (defun g (a)
>    (let ((v (* 3 a)))
>      (lambda (b) (incf v b))))

> (let ((c (g 1))) (print (list (c 1) (c 0) (c 1))))

Maybe:

(let ((c (g 1))) (print (list (funcall c 1) (funcall c 0) (funcall c 1))))
From: Pascal Bourguignon
Subject: Re: Please help to understand closures
Date: 
Message-ID: <87ll6i9mik.fsf@thalassa.informatimago.com>
Sampo Smolander <·························@helsinki.fi> writes:

> Pascal Bourguignon <···@informatimago.com> wrote:
>> (defun g (a)
>>    (let ((v (* 3 a)))
>>      (lambda (b) (incf v b))))
>
>> (let ((c (g 1))) (print (list (c 1) (c 0) (c 1))))
>
> Maybe:
>
> (let ((c (g 1))) (print (list (funcall c 1) (funcall c 0) (funcall c 1))))

Yes, sorry, I've been doing a little scheme recently :-(


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Small brave carnivores
Kill pine cones and mosquitoes
Fear vacuum cleaner
From: V.Ch.
Subject: Re: Please help to understand closures
Date: 
Message-ID: <d6396j$304v$1@gavrilo.mtu.ru>
Pascal Bourguignon wrote:
> And then, when you introduce macros, try to write the equivalent in C++:
> 
> 
> (defmacro later (&body body) `(lambda () ,@body))
> (defun now (later) (funcall later))
> 
> (defun example (a)
>   (let ((b (read)))
>     (later (setf b (g b a)))))
> 
> (let ((c (example 1))) 
>    (print (list (now c) (now c))))

 From the first glance this code rather shows that lambda-s can be 
handy. If we had lambda expression in C++, I am sure the code in C++ 
wouldn't have been much more verbose. The closest C++ equivalent I can 
think of right now is just a functor with one parameter (which 
corresponds to b variable in your example).


> This kind of macro catching a closure is essential to UCW to give an
> easy to use higher level language where you can attach to Web User
> Interface items  expressions  that will be executed much later, after
> the current page is sent back to the browser and the user clicks on
> another link or button.
> 
> For example, one can write:
> 
> (let ((employee (find-employee name)))
>    (<ucw:form
>        (<ucw:input :type "submit" :action (increase-salary employee 100.00)
>                                   :value "Increase Salary")))
> 
> The employee is found from the name that comes from the current
> request (URL), it's a lexical local variable.  The code generates an
> HTML form with an HTML input button  that when clicked will provoke
> the execution of a closure containing (increase-salary employee 100.00)
> in its body.  In a web site, there may be thousands of these
> closures.  Now imagine writting a class for everyone of them.
> And imagine what you'd need to write to implement <ucw:form and
> <ucw:input in C++.  Good luck!

Well, I don't have an answer right now - I needed a visit to CLiki just 
to find out what UCW is ;). But again, I have a strong suspicion that 
given the ability to construct functions on the fly, it's not too hard 
to implement something similar in C++.
Probably, I will return to this later.
From: V.Ch.
Subject: Re: Please help to understand closures
Date: 
Message-ID: <d639a9$304v$2@gavrilo.mtu.ru>
V.Ch. wrote:
> The closest C++ equivalent I can 
> think of right now is just a functor with one parameter (which 
> corresponds to b variable in your example).

I meant a functor with one parameter in its constructor.
From: Wade Humeniuk
Subject: Re: Please help to understand closures
Date: 
Message-ID: <c6bhe.59366$HR1.16656@clgrps12>
V.Ch. wrote:
> Even after reading about closures in "ANSI Common Lisp", I still don't 
> quite understand them. More specifically, the way I understand them, 
> they don't look such a great thing as the author suggests.
> 
> I understand that a closure is a set of functions sharing a state.
> But in that case, it can be very easily achieved in such unglamorous and 
> totally uncool language as C++. Just create a class - all member 
> variables is your state, and public methods - your functions. And it 
> seems to be much more powerfull construction - you have more control 
> over the state, and you don't have to share the state between all you 
> functions.
> 

Closures are more than that.  They allow non-local transfer of control
of the execution stack.  This enables the implementation of the CL condition
system.

(defvar *closure* nil)

(defun c ()
   (funcall *closure* 10)
   20)

(defun b ()
   (unwind-protect
       (c)
     (format t "Unwinding B~%")))

(defun start ()
   (let ((*closure* (lambda (value) (return-from start value))))
     (b)
     nil))

CL-USER 1 > (start)
Unwinding B
10

CL-USER 2 >

In this case calling the closure in c unwinds the stack and returns
from start. b has an unwind-protect that is run when the non-local
transfer of control happens.  CL closures are part of a more
powerful and integrated system.

Wade
From: nsr
Subject: Re: Please help to understand closures
Date: 
Message-ID: <1116032693.209804.230860@g43g2000cwa.googlegroups.com>
Going thru the box-drawing exercises of ch3 of SICP really helps.

http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-21.html#%_sec_3.2

Now everytime I read/write code that deal with closure, my brain will
automatically draw those little box diagrams......
From: David Steuber
Subject: Re: Please help to understand closures
Date: 
Message-ID: <87psvup87s.fsf@david-steuber.com>
"V.Ch." <····@notreal.com> writes:

> Even after reading about closures in "ANSI Common Lisp", I still don't
> quite understand them. More specifically, the way I understand them,
> they don't look such a great thing as the author suggests.

A function whose definition captures variables in its enclosing
lexical environment is quite useful.  The addn example is simply a
trivial example.  I use a slightly less trivial closure in a project I
am working on in OpenMCL to map the call of a C callable function to a
specific CLOS object.  The closure is created by the following helper
function:

(defun make-event-target-callback (et)
  (let (fn-carbon-event-handler)
    (declare (special fn-carbon-event-handler))
    (ccl:defcallback fn-carbon-event-handler
        (:<e>vent<h>andler<c>all<r>ef next-handler :<e>vent<r>ef event (:* t) user-data :<oss>tatus)
      (let ((class (#_GetEventClass event))
            (kind  (#_GetEventKind  event)))
        (declare (dynamic-extent class kind))
        (debug-log "Callback CARBON-EVENT-HANDLER: event-handler-ref = ~S; Class: '~A' Kind: ~A~%"
                   (slot-value et 'event-handler-ref) (int32-to-string class) kind)
        (multiple-value-bind (r c)
            (ignore-errors
              (handle-event et class kind next-handler event user-data))
          (declare (dynamic-extent r c))
          (when c
            (debug-log "Condition signaled from CARBON-EVENT-HANDLER: < ~A >~%" c))
          (if r #$noErr #$eventNotHandledErr))))
    fn-carbon-event-handler))

It's really pretty nifty what happens when the callback function is
called.  C knows nothing about closures.  Yet OpenMCL is able to take
the call and make sure the correct value of et is available when
handle-event is called.

Without lexical closures, I would have to find some other way to fill
in the appropriate value for et.  In fact, an earlier iteration of the
code did just that.  The earlier version was also more fragile.  The
earlier version was much like using the C++ this pointer and passing
that around.  Yuck.

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
No excuses.  No apologies.  Just do it.
   --- Erik Naggum
From: Marcin 'Qrczak' Kowalczyk
Subject: Re: Please help to understand closures
Date: 
Message-ID: <87hdh62y11.fsf@qrnik.zagroda>
"V.Ch." <····@notreal.com> writes:

> I understand that a closure is a set of functions sharing a state.

A single function which has access to non-global state (which may be
shared with other functions).

> But in that case, it can be very easily achieved in such unglamorous
> and totally uncool language as C++. Just create a class - all member
> variables is your state, and public methods - your functions.

In addition to being verbose, the problem is that such emulation of a
closure in C++ has a type which is more specific than its interface
requires. Closures which execute different code have different types,
even if they all take parameters and return a result of the same type.

This can be solved in two ways:

1. By using parametric polymorphism (C++: template) in the code which
   uses the closure. This is fine if the closure is only used locally,
   but this is not enough if it's stored in a data structure. And it
   leads to machine code bloat.

2. By introducing a superclass with virtual methods and deriving all
   "closures" from it. This has several problems: it requires holding
   the closure by a pointer, with its memory management problems;
   it requires to agree about a set of classes to derive from -
   standard C++ library doesn't provide them; separate arities
   (numbers of parameters) require separately written classes;
   global functions aren't instances of these classes so they must be
   wrapped in order to be used as closures.

> And it seems to be much more powerfull construction - you have more
> control over the state, and you don't have to share the state
> between all you functions.

I don't understand that. Each closure holds precisely the state it
needs (which is referred to from its body).

> In a way, closures in Lisp look like static function variables in C++
> - the thing I normally try to avoid, because "globality" of such
> variables greatly limits the number of usage scenarios, e.g. just
> think about multithreading.

The point is that a closure has access to local variables from the
point of its definition. There are no static variables, no globals
needed. This is the difference between closures and function pointers.

-- 
   __("<         Marcin Kowalczyk
   \__/       ······@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
From: Sam Steingold
Subject: Re: Please help to understand closures
Date: 
Message-ID: <upsvryqrt.fsf@gnu.org>
> * V.Ch. <····@abgerny.pbz> [2005-05-14 00:38:44 +0400]:
>
> I understand that a closure is a set of functions sharing a state.
> But in that case, it can be very easily achieved in such unglamorous
> and totally uncool language as C++. Just create a class - all member
> variables is your state, and public methods - your functions. And it

can you create an ad-hoc class on the fly?

> seems to be much more powerfull construction - you have more control
> over the state, and you don't have to share the state between all you
> functions.

in my experience, a typical use of closures is this:

  (remove-if-not (lambda (key) (< min key max)) data-list :key #'key-func)

DATA-LIST is a list (or a vector) of objects
KEY-FUNC is a function that produces some numeric key for each
object in DATA-LIST (e.g., universal time stamp or ordinal number)
MIN and MAX are the minimum and maximum values for the key.

the above form will return a fresh list (or a vector) of all object in
DATA-LIST whose KEY lies between MIN and MAX.

note that MIN and MAX may be local variables, so the LAMBDA in that form
is a closure over them.

Of course the closure is not necessary in this specific simple case.
You could write a loop instead:

    (loop for object in data-list for key = (key-func object)
       when (< min key max) collect object)

(except that REMOVE-IF-NOT will take any sequence, not just a list).

you could use nested REMOVE:

  (remove min (remove max data-list :key #'key-func :test #'<)
          :key #'key-func :test #'>=)

except that this will produce an intermediate sequence, will call
KEY-FUNC twice (instead of once), and it is very easy to get the :test
arguments wrong.

my point is that closures are a great _usability_ tool, not just a
beautiful theoretical abstraction.
just use them - as you would use a function.

> In a way, closures in Lisp look like static function variables in C++
> - the thing I normally try to avoid, because "globality" of such
> variables greatly limits the number of usage scenarios, e.g. just
> think about multithreading.

except that the closures are not global.


-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.mideasttruth.com/> <http://ffii.org/>
<http://pmw.org.il/> <http://www.jihadwatch.org/>
Sex is like air.  It's only a big deal if you can't get any.
From: ·················@gmail.com
Subject: Re: Please help to understand closures
Date: 
Message-ID: <1116303786.209851.325380@g44g2000cwa.googlegroups.com>
I have been using closures for years without realizing the real reason
why they are so good. Finally, I have understood it. It was difficult,
since the advantage is not a feature that closures have, it is a
feature they do *not* have.

I mean inheritance.

You cannot inherits from closures. Now, if you have experience with
large
object systems you will have realized that a significant part of the
issues
in understanding and maintaining such systems comes from inheritance.
If class
X is part of a hierarchy with ancestors Y, Z and W, in order to
understand
what X does you have to understand Y, Z and W. Everything is coupled.

We all know that the right way to build things is from basic blocks
which are
completely isolated and self-consistent. You could do this with
self-consistent
classes thant do not inherit from each other. But if you have classes
and you
do not use inheritance, then classes are overkill and you are better of
using
closures directly.

So I am using more and more closures these days.


          Michele Simionato