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 Interesting iterating in JavaScript trick
[link|http://plasmasturm.org/log/217/|http://plasmasturm.org/log/217/]

Might be worth borrowing if you need it...

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 Ooooo. I like...
New Very elegant.

Is it enough to love
Is it enough to breathe
Somebody rip my heart out
And leave me here to bleed
 
Is it enough to die
Somebody save my life
I'd rather be Anything but Ordinary
Please

-- "Anything but Ordinary" by Avril Lavigne.

New I must be missing something
All I can guess is that the syntax this allows is more like some other language with which you're more familiar than javascript.

It's saves a couple of characters in the simple example, but at the expense of the extra parens on each use of the iterated variable thereafter. Plus it looks much less clear to me what's happening.

Like I said though, if this looks more like some other language's syntax, one I'm not familiar with, then I can understand. But I'm not getting the greatness.
===

Purveyor of Doc Hope's [link|http://DocHope.com|fresh-baked dog biscuits and pet treats].
[link|http://DocHope.com|http://DocHope.com]
New Very likely.
Like I keep saying, JavaScript is a fairly good language let down by the DOM. If the DOM objects exposed elements sensibly, you could use JavaScript's for( in ) syntax. But they don't. So most JS programmers are forced to use C-like for() loops on objects.

That guy's iterate() function is clever because it puts a somewhat less-fiddly interface around such a loop, using a little-exploited feature of JavaScript. This is useful in a website with lots of these sort of loops.

If you've done any programming with streams or generators, the improvement is obvious.

Wade.

Is it enough to love
Is it enough to breathe
Somebody rip my heart out
And leave me here to bleed
 
Is it enough to die
Somebody save my life
I'd rather be Anything but Ordinary
Please

-- "Anything but Ordinary" by Avril Lavigne.

New Define "streams or generators"
Are they names of concepts, or one language's name for a concept I might know under a different name? Or a name for something I didn't know there was a name for?[1]

[1] There's quite a few of those, it seems. I keep asking people to explain what they mean by something, and I end up saying, "Oh, of course I do that. It's just good practice. There's a name for that?"
===

Purveyor of Doc Hope's [link|http://DocHope.com|fresh-baked dog biscuits and pet treats].
[link|http://DocHope.com|http://DocHope.com]
New They are names of concepts, at least one analog you know
There is a fairly good introduction to them in Perl at [link|http://perl.plover.com/Stream/stream.html|http://perl.plover.c...tream/stream.html].

Put simply, a stream is an infinite stream of data from somewhere. Any amount of data you want, you have. You can implement one by having a list of data and then a function at the end that can generate as many more as you might want. Depending on who you talk to, that function might be called a promise or a generator. (The linked article calls them promises.)

The obvious analogy is a Unix pipeline. The difference is that streams and generators exist within your program, and not due to processes communicating. All of the things that you can do with pipelines translate fairly directly to streams. (And streams have other tricks as well, for instance it is easy to build a stream that merges two others, while it is hard to write that in a Unix pipleline.)

Obviously this is just a set of techniques. But it is a very powerful set of techniques to know about when you need it.

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 Giggle
So you could have code that's "on a promise", then?

</silly>


Peter
[link|http://www.ubuntulinux.org|Ubuntu Linux]
[link|http://www.kuro5hin.org|There is no K5 Cabal]
[link|http://guildenstern.dyndns.org|Home]
Use P2P for legitimate purposes!
New Yes. And you're hoping that the promises are kept. :-)
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 There are several benefits
Number 1 is the fact that one of the top (if not the top) source of programming bugs is off-by-one errors in writing C-style loops. This lets you get rid of that.

Secondly you get to eliminate some annoying synchronization. You only have to state the list to be iterated over once rather than twice (minimum).

The two drawbacks are what you note. However if you use it a lot, then the issue of, "WTF is happening?" fades - it becomes part of the syntax of the language that you're using. And the details fade into, "Oh yeah, I need parens here." Which is a mental adjustment that most of us can make fairly easily.

As for whether this is like other syntaxes, it is somewhat like for loops in many other languages. It is even something like JavaScript's for/in syntax, except that that does the wrong thing on arrays. OK, the resemblance isn't that close, but the "feel" is similar.

Another approach to the same issue goes like this (untested):
\n// This is the helper function\nfunction for_each (things, operation) {\n  for (var i = 0; i < things.length; ++i) {\n    operation(things[i]);\n  }\n}\n\n// And now you can do this:\nfor_each(document.styleSheets, function (sheet) {\n  if (sheet.href) {\n    do_something(sheet);\n  }\n}}\n

This approach is much clearer about what is going on. Logically the result is the same. However here there is no hiding the fact that you're using closures. There is a certain "shock" in that for some people.

It is a question of personal preference which you prefer. But using anything other than C-style loops is a win in terms of your error rate.

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 Much better
Now to test it. :-)

I see what you mean about the off-by-one. Now remind me what closures are?
===

Purveyor of Doc Hope's [link|http://DocHope.com|fresh-baked dog biscuits and pet treats].
[link|http://DocHope.com|http://DocHope.com]
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)
New Can't make your example work
First thing I noticed is it seems to be short one parenthesis, and has an extra closing brace. I've tried various combinations to fix it and can't get it working.

If I put a closing paren after function (test_element) I get a warning it's expecting a { at that point. Nothing else even looks right.

[link|http://dkime.com/js_iterator.php|Here's] my sample code. If anyone can figure this out several of us here will be very grateful.
===

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 think you're missing the 'anonymous' part.
\n1  function test_this() {\n2      for_each(document.js_test_form.elements,\n3               function (test_element) { alert (test_element.name); }\n4               )\n5  }


Notice how line 3 is both a complete function definition, and an argument being passed to the test_this function, inline.


The Sig:
"Despite the seemingly endless necessity for doing
so, it's actually not possible to reverse-engineer intended invariants
from staring at thousands of lines of code (not in C, and not in
Python code either)."

Tim Peters on python-dev
New Got it, example works now, woot
===

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 like this one better
as it more closely matches Smalltalk collection iteration - ie

collection do: [:each | "do something to an element" ]

which seems to translate as

for_each(collection, function(each) { "do something to an element" })

much cleaner I think. The pointed to example is too Java ugly as it forces the developer to set up the loop, it just changes the loop conditions ie

var it = iterator(collection);
var item;
while(item = it.next()) { "do something to item" }

Incidentally, I'd probably have the iterator "reload" when it hits the end - IOW, reset i to -1 before returning null so you could use it again.



"Whenever you find you are on the side of the majority, it is time to pause and reflect"   --Mark Twain

"The significant problems we face cannot be solved at the same level of thinking we were at when we created them."   --Albert Einstein

"This is still a dangerous world. It's a world of madmen and uncertainty and potential mental losses."   --George W. Bush
     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)

Powered by nothing at all!
135 ms