#79 bug
frank kootte

ObjectRange isn't inclusive when used on strings

Reported by frank kootte | May 6th, 2008 @ 12:39 PM | in 1.6.1

As mentioned on the api pages one should be carefull with the ObjectRange object considering strings.

Even though the behaviour should be considered undesirable.

$A($R('a','b')) -> delivers as expected, an array containing the values [ 'a', 'b']

$A($R('aa', 'bb')) -> delivers unexpected

one would expect an array containing all following values

['aa', 'ab', 'ba', 'bb' ].

as described in the api the objectrange iterates over all characters in the current table but the method does return an array not containing the value 'bb' which is the least i would expect as it does behave like that when working with a numeric range.

i've got some suggestions on how to handle this, so if any inspiration / information needed please email me.

Comments and changes to this ticket

  • Tobie Langel

    Tobie Langel May 6th, 2008 @ 01:24 PM

    • → State changed from “new” to “bug”
    • → Title changed from “ObjectRange returning unusable results” to “ObjectRange isn't inclusive when used on strings ”
  • John-David Dalton

    John-David Dalton May 6th, 2008 @ 02:29 PM

    frank kootte -> why not just post your patch to this ticket?

  • frank kootte

    frank kootte May 6th, 2008 @ 03:36 PM

    i've created a piece of code which indeed does as i suggested, but it is more "proof-of-concept" code then code which can be added to prototype, i will rewrite it to fit the prototype branch.

  • frank kootte

    frank kootte May 6th, 2008 @ 04:03 PM

    ok, some suggestions :

    • we only work with positive ranges, so if we encounter a negative one, we swap the start and the end.
    • we need to distinguish between numerical and string based ranges as the string range needs some recursive / while computation that the numeric range does not need
    • we only work with pure string or numerical ranges as it just akward to have a range that is from for example 'a1' -> 'dd', so we only work with 11 -> 99 || 'aa' -> 'zz'
    • we only work with string ranges where the start and end have the same length.

    does anybody have an objection against changes to be made based on these suggestions ?

  • Juriy Zaytsev

    Juriy Zaytsev May 6th, 2008 @ 11:10 PM

    I might be missing something but ObjectRange simply delegates iteration logic to #succ method of its "start" object. #succ method is currently defined for both - Number.prototype and String.prototype, so the behavior is indeed different. I also could not reproduce "inclusiveness" bug:

    $R('a', 'd').toArray(); // => ['a','b','c','d']
    $R('a', 'd', true).toArray(); // => ['a','b','c']
    

    The "expected outcome" is imo somewhat subjective in this case. Current implementation increments character based on its ASCII code, while you are proposing to output a collection of possible combinations (or is it permutations?).

    I think the proposed change could actually make more sense.

  • Juriy Zaytsev

    Juriy Zaytsev May 7th, 2008 @ 05:40 AM

    Ok, there is a bug (#succ keeps incrementing ASCII code and everything fails once 65535 is reached).

    I'll try to make a patch as soon as I can.

  • Juriy Zaytsev

    Juriy Zaytsev May 7th, 2008 @ 06:08 AM

    A patch that allows #succ to work with strings that have any number of characters

  • Juriy Zaytsev

    Juriy Zaytsev May 7th, 2008 @ 06:08 AM

    • → Milestone changed from “” to “1.6.1”
    • → Assigned user changed from “” to “Juriy Zaytsev”
  • frank kootte

    frank kootte May 7th, 2008 @ 09:12 AM

    You're correct about the problem when reaching the boundaries of the ASCII table, but i'm still in favor of changing the general behaviour of ranges with strings.

    When i want a range like the [a,b][a,b], i expect the following result.

    $R ('aa', 'bb') // -> ['aa', 'ab', 'ba', 'bb']
    

    but what ObjectRange returns is an huge array by iterating over the ASCII table until it will find 'b', but it will never get there.

    perhaps this term expected is not suitable, but i think the change i mentioned would give back more usable results.

  • frank kootte

    frank kootte May 7th, 2008 @ 10:20 AM

    I wrote a quick fix to show you my train of though, it's not completely like i want it, e.g. not all border exceptions are taken care of but it most surely does the trick.

    ObjectRange._each = function (iterator)
    {
        if(typeof (this.start) == 'string')
        {
        	var size = this.start.length;
        	
    		(function ( start, end, prefix  )
    		{
    			var length = start.length;
    				
    			for ( var index = 0; index < length; index++ )
    			{
    				var current = start [ index ];
    				var stop = end [ index ];
    					
    				while ( this.exclusive ? current.charCodeAt () < stop.charCodeAt () : current.charCodeAt () <= stop.charCodeAt () )
    				{					
    					if ( start [ index + 1 ] != undefined && end [ index + 1 ] != undefined )
    					{
    						arguments.callee ( start.slice ( 1 ), end.slice( 1 ), prefix + current );
    					}
    					else if ( ( prefix + current ).length == size )
    					{
    						iterator ( prefix + current );						
    					}
    					else
    					{
    						break;
    					}
    					
    					current = current.succ ();
    				}
    			}	
    		
    		}).bind(this)( this.start.toArray(), this.end.toArray(), '' );
        }
        else
        {
        	var value = this.start;
        	while (this.include(value)) 
        	{
          		iterator(value);
          		value = value.succ();
        	}
        }
      };
    
  • frank kootte

    frank kootte May 7th, 2008 @ 10:22 AM

    // replaced tabs with double spaced
    if(typeof (this.start) == 'string')
        {
          var size = this.start.length;
        	
    	  (function ( start, end, prefix  )
    	  {
    	   	var length = start.length;
    				
    		for ( var index = 0; index < length; index++ )
    		{
    		  var current = start [ index ];
    		  var stop = end [ index ];
    				
    		  while ( this.exclusive ? current.charCodeAt () < stop.charCodeAt () : current.charCodeAt () <= stop.charCodeAt () )
    		  {					
    		    if ( start [ index + 1 ] != undefined && end [ index + 1 ] != undefined )
    			{
    			  arguments.callee ( start.slice ( 1 ), end.slice( 1 ), prefix + current );
    			}
    			else if ( ( prefix + current ).length == size )
    			{
    			  iterator ( prefix + current );						
    			}
    			else
    			{
    			  break;
    			}
    					
    		    current = current.succ ();
    		  }
    		}	
    	  }).bind(this)( this.start.toArray(), this.end.toArray(), '' );
        }
        else
        {
          var value = this.start;
          while (this.include(value)) 
          {
            iterator(value);
          	value = value.succ();
          }
        }
    

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

Attachments