Project

General

Profile

Actions

Bug #21142

open

Lazy enumerator `.each_with_index` ignores `.take(0)` before it

Added by aaronkison (Aaron Kison) 23 days ago. Updated about 17 hours ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:121076]

Description

Minimum code to produce problem:

class Numbers; def each; 100.times { yield _1 }; end; include Enumerable; end

Numbers.new.lazy.take(0).each_with_index.map { _1 }.to_a

Output (at ruby 3.2.7, and 3.3.0):

[0, 1, ..., 99]

Expected output (and was as at ruby 3.1.4):

[]

It works when it opposite ordering: Numbers.new.lazy.each_with_index.take(0).map { _1 }.to_a.
I suspect it may be related to the change here https://github.com/ruby/ruby/pull/11868/files but I'm not familiar with any of that code. It seems like it replaces an allocated index with a counting index, which my hunch is it works for every value except for 0.

Updated by mame (Yusuke Endoh) about 24 hours ago

  • Assignee set to alanwu (Alan Wu)

Updated by alanwu (Alan Wu) about 17 hours ago · Edited

  • Assignee deleted (alanwu (Alan Wu))

The pull request you point to was released with 3.4, but the problem started with 3.2, so it's not due to the change in the pull request.

Updated by Hanmac (Hans Mackowiak) about 17 hours ago · Edited

You might want a different function.

Enumerable#each_with_index does reset the Enumerator, while Enumerator#with_index does not.

p 3.times.lazy.take(0).each_with_index.to_a #[[0, 0], [1, 1], [2, 2]]
p 3.times.lazy.take(0).with_index.to_a #[]

Edit: seems it isn't really correct, lazy.take(0) seems is different from lazy.take(1)

p 3.times.lazy.take(1).each_with_index.to_a #[[0, 0]]
p 3.times.lazy.take(1).with_index.to_a #[[0, 0]]

Maybe this part is the culprit?

lazy_take_precheck(VALUE proc_entry)
{
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
    return entry->memo != INT2FIX(0);
}
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0