Project

General

Profile

Actions

Feature #20182

closed

Rewrite Array#each in Ruby

Added by k0kubun (Takashi Kokubun) 4 months ago. Updated 4 months ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:116190]

Description

Proposal

Rewrite Array#each in Ruby https://github.com/ruby/ruby/pull/6687.

class Array
  def each
    unless block_given?
      return to_enum(:each) { self.length }
    end
    i = 0
    while i < self.length
      yield self[i]
      i = i.succ
    end
    self
  end
end

Purpose

Make it possible for YJIT to optimize ISEQs across Array#each.

Background

Whether JIT-compiled or not, calling Ruby from C is more expensive than calling Ruby from Ruby. It also prevents YJIT from making cross-ISEQ optimizations.

This is problematic especially for loop methods written in C like Array#each since the overhead is repeated at every iteration.

Discussions

There are a couple of things I'd like to discuss in this ticket:

  1. @Eregon (Benoit Daloze) has pointed out that there's a race condition in the above implementation. self[i] would yield nil if the element was removed by another thread or TracePoint after i < self.length. Is it Array#each's responsibility to atomically operate on elements, or are users supposed to avoid mutating the array in the middle of its loop?
  2. If Integer#<, Array#length, Integer#succ, or Array#[] is overridden in an incompatible way, the Ruby implementation may not work correctly. May I assume it's acceptable?
Actions

Also available in: Atom PDF

Like2
Like1Like1Like0Like0Like0Like0