Behavior when each is executed in the reverse order Range

When I turned each, I did nothing and did not get an error, and I was addicted to it because the processing continued as it was, so I made a memorandum.

Range instantiation

Instances can be created without problems in either case of start point <end point, start point> end point.

aaa = Range.new(1,5)
=> 1..5

bbb = 1..5
=> 1..5
ccc = Range.new(5,1)
=> 5..1

ddd = 5..1
=> 5..1

Range#each

Range # each behavior

The problem is when you turn each in the Range generated in reverse order.

aaa.each {|i| puts i}
1
2
3
4
5
=> 1..5
ccc.each {|i|puts i}
=> 5..1

Description of Range # each

According to Rurima, Range # each is iterated with succ. https://docs.ruby-lang.org/ja/latest/method/Range/i/each.html

Looking at the description of succ for Integer, it seems that it simply returns the next integer.

aaa.begin.class
=> Integer

https://docs.ruby-lang.org/ja/2.5.0/method/Integer/i/next.html

aaa.begin
=> 1
aaa.begin.succ
=> 2
ccc.begin
=> 5
ccc.begin.succ
=> 6

Implementation of Range # each

Probably static VALUE range_each (VALUE range) is called, and since the while condition is not satisfied after that, it seems that the processing is completed without looping even one lap.

https://github.com/ruby/ruby/blob/trunk/range.c#L833

static VALUE
range_each(VALUE range)
{
//...abridgement
	    if (!NIL_P(end))
		range_each_func(range, each_i, 0);
	    else
		for (;; beg = rb_funcallv(beg, id_succ, 0, 0))
		    rb_yield(beg);
//...abridgement
}

https://github.com/ruby/ruby/blob/trunk/range.c#L239

static void
range_each_func(VALUE range, int (*func)(VALUE, VALUE), VALUE arg)
{
    int c;
    VALUE b = RANGE_BEG(range);
    VALUE e = RANGE_END(range);
    VALUE v = b;

    if (EXCL(range)) {
	while (r_less(v, e) < 0) {
	    if ((*func)(v, arg)) break;
	    v = rb_funcallv(v, id_succ, 0, 0);
	}
    }
    else {
	while ((c = r_less(v, e)) <= 0) {
	    if ((*func)(v, arg)) break;
	    if (!c) break;
	    v = rb_funcallv(v, id_succ, 0, 0);
	}
    }
}

https://github.com/ruby/ruby/blob/trunk/range.c#L157

/* compares _a_ and _b_ and returns:
 * < 0: a < b
 * = 0: a = b
 * > 0: a > b or non-comparable
 */
static int
r_less(VALUE a, VALUE b)
{
    VALUE r = rb_funcall(a, id_cmp, 1, b);

    if (NIL_P(r))
	return INT_MAX;
    return rb_cmpint(r, a, b);
}

Recommended Posts

Behavior when each is executed in the reverse order Range
Behavior when wild card (**) is specified in ruby
When the project is not displayed in eclipse
Ebean.update () is not executed in the inherited model.
When Spring Batch is executed continuously in Oracle, ORA-08177
[Swift] Setting the behavior when the Share button is pressed
Until the code is executed
The behavior of Class # getClassLoader changes depending on whether it is executed in the IDE or jar.
How to output the value when there is an array in the array
How to write the view when Vue is introduced in Rails?
Order of processing in the program
Change the processing when the button on RecyclerView is pressed for each list
Error when the member of Entity class used in SpringWebFlux is final
[Ruby] How to prevent errors when nil is included in the operation
When the bean class name is duplicated
[Rails] Annotate is not executed when migrating
Spring Autowired is written in the constructor
Command when dependency is broken in Ubuntu 20.04
Precautions when specifying the URL in render
What is the main method in Java?
[swift] How to control the behavior when the back button of NavigationBar is pressed
Possibility when deploying to EC2 but nothing is displayed in the error log
How to set when "The constructor Empty () is not visible" occurs in junit