#55 enhancement
Juriy Zaytsev

Enumerable to accept string as an iterator

Reported by Juriy Zaytsev | April 26th, 2008 @ 05:43 PM

The proposed patch allows to optionally pass string as an iterator (instead of a function)

[1,2,3].map(' return value + 1'); // => [2,3,4]

The idea is simple:

1) String.prototype is extended with #toIterator method:

  toIterator: function() {
    return new Function('value, index, source', this);
  }

2) Enumerable module is extended with "normalize" function:

  normalize: function(iterator) {
    if (iterator)
      return iterator.toIterator ? iterator.toIterator() : iterator;
    return Prototype.K;
  }

3) Enumerable method "normalizes" passed iterator:

  any: function(iterator, context) {
    iterator = this.normalize(iterator);
    ...
  }

Comments and changes to this ticket

  • Juriy Zaytsev

    Juriy Zaytsev April 26th, 2008 @ 05:50 PM

      • → State changed from “new” to “enhancement”
  • John-David Dalton

    John-David Dalton April 26th, 2008 @ 09:07 PM

    what about being more granular and having a String#toFunction()

  • Juriy Zaytsev

    Juriy Zaytsev April 26th, 2008 @ 09:59 PM

    Because I don't see other use cases besides using string as an iterator. toFunction is pretty easy to implement and do you really think it's worth adding another String.prototype method (if toIterator is enough) ? : )

    String.prototype.toFunction = function(){
      return new Function(arguments[0], this);
    }
    
    ' return x + y '.toFunction('x, y');
    
    // creates
    function (x,y) {
      return x + y;
    }
    
  • Josh Strater

    Josh Strater April 30th, 2008 @ 10:12 PM

    Oliver Steele's Functional Javascript library offers automatic conversion of strings to functions, and not just for iterators. For arguments, one can either use Haskell-style parameter lists or implicit parameters. The syntax also allows for more of a pointfree style. For example:

    map('1+', [1,2,3]) → [2, 3, 4]
    

    It's actually pretty clever.

    Anyway, if this is the kind of feature that Prototype wants to include, Steele's library would seem to be a good starting point.

  • Juriy Zaytsev

    Juriy Zaytsev May 1st, 2008 @ 05:22 AM

    Josh,

    I'm a big fan of Oliver's "Functional".

    The idea, though, was to provide support for a minimal "sugar" - to keep backwards compatibility and not to cripple performance much.

    If we drop explicit "return" from the iterator-string, the syntax becomes quite concise (too concise?):

    [1,2,3].map('value + 1'); // => [2,3,4]
    
    $R(1,10).findAll('value < 5'); // => [1,2,3,4]
    

    The reason I made "return" explicit is to have support for multiple expressions:

    [1,2,3].map(' console.log(index, value); return value + 1; ');
    

    Dropping "value" would lead to some heavy parsing, and I'm worried about performance issues (though we would certainly need benchmarks for that).

    Feel free to submit patch/tests if you like.

    Best,

    kangax

  • Juriy Zaytsev

    Juriy Zaytsev May 1st, 2008 @ 05:32 AM

    Now that I think about it, "return" could be prepended only if it's not present in expression. That would be fast and concise:

    [1,2,3].map(' value + 1 '); // return is not present, prepend it
    [1,2,3].map(' console.log(index); return value + 1 '); // return is present, do nothing
    
  • matthuhiggins

    matthuhiggins May 1st, 2008 @ 06:22 AM

    For sortBy, max, min and perhaps some others, I would more commonly just want to pass in a property name or method to invoke.

    var friends = [{name: 'joe', age: 10}, {name: 'bob', age: 12}];
    
    var oldest = friends.max('age');
    var alphaSorted = friends.sortBy('name');
    

    The reason I bring this up is because you cannot easily support the suggested change in this ticket and the property name approach at the same time.

  • John-David Dalton

    John-David Dalton May 1st, 2008 @ 07:46 PM

    @matthuhiggins - Your suggestion leaves a lot of guessing on Prototype's part.

    I think if you follow Juriy's syntax you can accomplish the same thing.

    var friends = [{name: 'joe', age: 10}, {name: 'bob', age: 12}];
    
    var oldest = friends.max('value.age');
    var alphaSorted = friends.sortBy('value.name');
    

Please Login or create a free account to add a new comment.

You can update this ticket by sending an email to from your email client. (help)

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

The Prototype JavaScript library.

Shared Ticket Bins