IWETHEY v. 0.3.0 | TODO
1,095 registered users | 0 active users | 0 LpH | Statistics
Login | Create New User
IWETHEY Banner

Welcome to IWETHEY!

New Anonymous functions and closures
I should have been saying "anonymous functions" because the sample code works without closures. But here's the quick overview.

When I talk about anonymous functions I just mean that you have functions that you know about by reference, not name. If the anonymous functions "close over" some private, local environment, they become closures. (More on what that means in a second.) Whether or not an anonymous functions become closures depends entirely on your language. They do in, say, JavaScript. They do not in C.

Now what happens in JavaScript (and most other modern languages with anonymous functions)? Well most variables are lexically scoped (lexical literally means "of the text"), the scope of the variable is defined by a block of text. So when the function that refers to that variable is returned elsewhere, from within that copy of the function that variable continues to have its old environment. You can have multiple copies of a function, each of which carries a different local environment. The function can use this local environment to keep track of what is happening. (Warning, JavaScript does this slightly differently than most others, I'll clarify that later.) [link|http://www.perlmonks.org/?node_id=50132|http://www.perlmonks.org/?node_id=50132] demonstrates one abuse of this in Perl - figure out how that code works and you definitely have the idea of closures down. (But usually you don't use them like that...)

By contrast what happens in, say, C or Emacs Lisp? You have anonymous functions. You can call them. But when you do, they've lost the local environment that they were created with.

Of the two approaches that were offered, Aristotle's needs closures to work - which stylesheet you're currently on is kept in private state in a closure. By contrast my approach didn't need closures, it only needed anonymous functions.




Now I gave a warning that JavaScript does things differently from most others? The difference is simple. Consider the following code in Perl:
\n# I'm trying to make this match the JavaScript\nsub curry_all {\n  my ($fn, @items) = @_'\n  my @curried;\n  for (my $i = 0; $i < @items; ++$i) {\n    my $item = $items[$i];\n    push @curried, sub {$fn->($item, @_)};\n  }\n  return @curried;\n}\n

And the apparent equivalent in JavaScript:
\n// This doesn't work very well..\nfunction curry_all (fn, items) {\n  var curried = [];\n  for (var i = 0; i < items.length; ++i) {\n    var item = items[i];\n    curried.push(function (other_arg) {fn(item, other_arg)});\n  }\n  return curried;\n}\n

In Perl the result is an array of functions with the different items pre-bound as the first argument. In JavaScript the result is an array of functions with the last item pre-bound as the first argument.

The reason why Perl (and most other languages) works how it does is that $item has a lexical scope of the one loop iteration, so each iteration through the loop gets a new $item variable, so each closure has a different copy of $item.

But in JavaScript for reasons that I do not understand, they stick their definition of a "local environment" on that invocation of the function. So even though item is a variable in the lexical scope of the loop inside the function, in JavaScript the created closures all see the same item variable, which has the last value assigned to it (from the last pass through the loop).

The fix in JavaScript looks like this:
\n// This works\nfunction curry_all (fn, items) {\n  var curried = [];\n  for (var i = 0; i < items.length; ++i)\n    curried.push(curry(fn, items[i]));\n  return curried;\n}\n\n// This really needs to be its own function\nfunction curry(fn, item) {\n  return function (other_arg) {fn(item, other_arg)};\n}\n


Cheers,
Ben

PS We say that you "curry" a function when you pre-bind variables. The term is named after Haskell Curry who demonstrated that in a language with functions as a datatype, anything that you can accomplish with functions that accept multiple arguments can be accomplished with currying. And the language Haskell is, of course, also named after him. (Haskell only has functions of a single variable, and implicitly curries everywhere.)
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
New Looks like it's treating 'i' as a reference
In the line curried.push(function (other_arg) {fn(item, other_arg)}); if item is passed by reference, is it possibly treating the fucntion also as a reference? That's strange. If it were simply a matter of the scope being to the function instead of the loop, I would expect all the copies of it to be the first value, not the last.


As for closures, it looks very much like creating an instance of an object. I did see in one of the docs trying to define them that closures are one way of doing OO in perl (though not the best way). I'm so used to seeing instance variables that I must have read five different examples before I understood what point they were trying to make.
===

Purveyor of Doc Hope's [link|http://DocHope.com|fresh-baked dog biscuits and pet treats].
[link|http://DocHope.com|http://DocHope.com]
New I said "invocation of the function" for a reason
In that example the closure in JavaScript is bound to an internal data structure representing the call to curry_all. Therefore all of the closures created on the same call to curry_all will see the same item variable. That variable has the last value that it was assigned, which is from the last time through the loop.

I only bring it up because I got bitten by it and it took me a while to figure out what was happening. (And then to find out that it is supposed to do that according to the spec.)

As for your closure-object comparison, there is at best limited validity to that. (Yes, I've seen the same point made. And argued against it as well before.) True, a closure can be thought of as an object with only one method and no class. However conceptually this is a useless way to think, closures aren't just somewhat useless objects minus infrastructures, they're a different programming building block. With closures it is trivial to create an OO system. With OO you can't re-create closures.

If you've never used them, the difference in how you think isn't easy to communicate. About the best that I can do is to say that objects make good nouns, closures make good verbs.

Cheers,
Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
New You're right about not getting it without using it
Because I haven't used closures, and I still don't "feel" the difference.

I guess all I'm really interested in knowing is whether this is something I should try to learn because it's a useful technique, or is it simply another way of doing something I'm already doing another way. I'll have to look at it some more when I've got more than five minutes at a time to think about it.
===

Purveyor of Doc Hope's [link|http://DocHope.com|fresh-baked dog biscuits and pet treats].
[link|http://DocHope.com|http://DocHope.com]
New I'm sure that you AREN'T using closures
It doesn't really resemble any other technique that I know of.

Cheers,
Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
     Interesting iterating in JavaScript trick - (ben_tilly) - (19)
         Ooooo. I like... -NT - (FuManChu)
         Very elegant. -NT - (static) - (17)
             I must be missing something - (drewk) - (16)
                 Very likely. - (static) - (4)
                     Define "streams or generators" - (drewk) - (3)
                         They are names of concepts, at least one analog you know - (ben_tilly) - (2)
                             Giggle - (pwhysall) - (1)
                                 Yes. And you're hoping that the promises are kept. :-) -NT - (ben_tilly)
                 There are several benefits - (ben_tilly) - (10)
                     Much better - (drewk) - (5)
                         Anonymous functions and closures - (ben_tilly) - (4)
                             Looks like it's treating 'i' as a reference - (drewk) - (3)
                                 I said "invocation of the function" for a reason - (ben_tilly) - (2)
                                     You're right about not getting it without using it - (drewk) - (1)
                                         I'm sure that you AREN'T using closures - (ben_tilly)
                     Can't make your example work - (drewk) - (2)
                         I think you're missing the 'anonymous' part. - (FuManChu) - (1)
                             Got it, example works now, woot -NT - (drewk)
                     I like this one better - (tuberculosis)

You entered famous last wordsburg territory thinking along that line.
77 ms