#55 enhancement
Juriy Zaytsev

Enumerable to accept string as an iterator

Reported by Juriy Zaytsev | April 26th, 2008 @ 07:49 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 @ 07:50 PM

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

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

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

  • Juriy Zaytsev

    Juriy Zaytsev April 26th, 2008 @ 11: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 May 1st, 2008 @ 12:12 AM

    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 @ 07: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 @ 07: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 @ 08: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 @ 09: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');
    
  • Tobie Langel

    Tobie Langel July 24th, 2009 @ 01:59 AM

    • Tag set to needs_tests, patched, section:lang

    [not-tagged:"lang" tagged:"section:lang" bulk edit command]

  • Tobie Langel

    Tobie Langel July 24th, 2009 @ 02:26 AM

    • Tag changed from needs_tests, patched, section:lang to missing:tests, patched, section:lang

    [not-tagged:"needs_tests" tagged:"missing:tests" bulk edit command]

  • Tobie Langel

    Tobie Langel July 24th, 2009 @ 03:36 AM

    • Tag changed from missing:tests, patched, section:lang to needs:tests, patched, section:lang

    [not-tagged:"missing:tests" tagged:"needs:tests" bulk edit command]

  • T.J. Crowder

    T.J. Crowder November 16th, 2009 @ 04:50 PM

    • Assigned user cleared.

    [responsible:none bulk edit command]

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

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

Attachments

Referenced by

Pages