From: kangax on
On 3/4/10 11:00 AM, Antony Scriven wrote:
> On Mar 4, 2:54 pm, kangax wrote:
>
> > On 3/4/10 9:14 AM, Jorge wrote:
> >
> > > Is it possible [to break out of a forEach()]?
> >
> > `throw` will take you out of it. But then you might want
> > a wrapper to handle it gracefully, and it all adds
> > complexity of course.
> >
> > Here's an untested example:
> >
> > Array.prototype.each = (function(){
> > var stopIterationError = { };
> > return function(callback, thisValue) {
> > try {
> > this.forEach(function() {
> > if (callback.apply(thisValue, arguments) === false) {
> > throw stopIterationError;
> > }
> > });
> > }
> > catch(err) {
> > if (err !== stopIterationError) {
> > throw err;
> > }
> > }
> > };
> >
> > })();
> >
> > [1,2,3].each(function(item, index){
> > console.log(arguments);
> > if (index == 1) return false;
> >
> > });
>
> Does it need to be that complex?

Not at all :)

>
> var LIB = (function(){
> Array.prototype.each = function(func, thisvalue){
> try{
> this.forEach(func, thisvalue);
> }catch(e){
> if(e !== LIB.stopEach){
> throw e;
> }
> }
> };
> return {stopEach: {}};
> }());
>
> [1,2,3].each(function(item, index){
> console.log(arguments);
> if (index == 1) throw LIB.stopEach;
> });
>
> IME this construct doesn't occur very often so I also think
> it helps to make the termination statement as obvious as
> possible. --Antony

You can do that too. In fact, that's what Prototype.js has been doing
for years
(<http://github.com/sstephenson/prototype/blob/master/src/lang/enumerable.js#L109>),
just more sloppily, throwing global `$break` object.

<digression>
In a retrospect, this whole idea of throwing wasn't that good. In most
common scenario, breaking out of the loop was actually _not_ worth
performance hit introduced by try/catch. And since `each` was used
everywhere throughout the library (even in places where plain `while`
would suffice), it's easy to imagine how it all hindered performance.
</digression>

`return false` idiom probably originates from intrinsic event handlers,
where it would prevent event's default action. IIRC, jQuery uses it in
its own `each` implementation. `return false` could also be easier to
use, as you don't need to remember the name of error object.

--
kangax
From: Antony Scriven on
On Mar 4, 5:21pm, kangax wrote:

> On 3/4/10 11:00 AM, Antony Scriven wrote:
>
> [...]
>
> > var LIB = (function(){
> > Array.prototype.each = function(func, thisvalue){
> > try{
> > this.forEach(func, thisvalue);
> > }catch(e){
> > if(e !== LIB.stopEach){
> > throw e;
> > }
> > }
> > };
> > return {stopEach: {}};
> > }());
> >
> > [...]
>
> [...]
>
> <digression>
> In a retrospect, this whole idea of throwing wasn't that
> good. In most common scenario, breaking out of the loop
> was actually _not_ worth performance hit introduced by
> try/catch. And since `each` was used everywhere
> throughout the library (even in places where plain
> `while` would suffice), it's easy to imagine how it all
> hindered performance.
> </digression>

Well, the try/catch is outside of the performance-critical
part of the loop (though nesting forEach() would clearly
change that). Though it will no doubt have an impact, I've
no idea how much of an impact it will have in actual
application code. I wouldn't be surprised if other things,
either inside or outside the library, had more of
a performance hit; I prefer to leave my imagination out of
profiling :-). Certainly I agree with you on principle
though.

In practice I don't see the point in altering the built-in
function since I've never needed to use forEach() in that
way. If I did have to, I'd wrap the specific forEach() in
try/catch by hand rather than make changes to the semantics
of the original. Either that or I'd make sure the contents
of the array is 'valid' in such a way that the forEach()
loop wouldn't need to be aborted.

> `return false` idiom probably originates from intrinsic
> event handlers, where it would prevent event's default
> action. IIRC, jQuery uses it in its own `each`
> implementation. `return false` could also be easier to
> use, as you don't need to remember the name of error
> object.

True. I guess I was talking more about reading someone
else's code rather than writing it. In our team I'm fairly
certain that using 'return false;' would cause more problems
of understanding than throwing an exception. --Antony
From: "Michael Haufe ("TNO")" on
On Mar 4, 8:14 am, Jorge <jo...(a)jorgechamorro.com> wrote:
> Is it possible ?

I don't believe there is a reason to. Alter your code.

myArray.filter(...).forEach(...);
From: Jorge on
On Mar 5, 7:02 am, "Michael Haufe (\"TNO\")"
<t...(a)thenewobjective.com> wrote:
> On Mar 4, 8:14 am, Jorge <jo...(a)jorgechamorro.com> wrote:
>
> > Is it possible ?
>
> I don't believe there is a reason to. Alter your code.

The reason is that what I'm doing may throw a runtime exception.

> myArray.filter(...).forEach(...);

The reason is not in the input. It's not something that I can know
beforehand if it's going to throw.
--
Jorge.