Skip to content

Enumerator::Lazy is missing a few methods, leading to different behavior from MRI #2273

@ivoanjo

Description

@ivoanjo

Hello there 👋

I was trying out the ddtrace gem specs with TruffleRuby, and ran into a failure in chunker_spec.rb.

This is caused by TruffleRuby not implementing the full set of methods on Enumerator::Lazy, which means that a few of the method implementations from Enumerable get used instead, which leads to lazy enumerables becoming non-lazy accidentally.

The specific example I ran into is the case of slice_before. Here's how it behaves on MRI:

[20] pry(main)> puts RUBY_DESCRIPTION
ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19]
=> nil
[21] pry(main)> [1, 2, 3].lazy.slice_before { |n| n > 2 }
=> #<Enumerator::Lazy: ...>

and here's how it behaves on TruffleRuby:

[16] pry(main)> puts RUBY_DESCRIPTION
truffleruby 21.0.0.2, like ruby 2.7.2, GraalVM CE Native [x86_64-darwin]
=> nil
[17] pry(main)> [1, 2, 3].lazy.slice_before { |n| n > 2 }
=> #<Enumerator: #<Enumerator::Generator:0x2618 @proc=#<Proc:0x2628 <internal:core> core/enumerable.rb:229>>:each>

Looking at the list of methods that Enumerator::Lazy has on MRI vs on TruffleRuby, it looks like this issue would apply to a few more:

[24] pry(main)> puts RUBY_DESCRIPTION
ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19]
=> nil
[25] pry(main)> example = [].lazy
=> #<Enumerator::Lazy: ...>
[26] pry(main)> ls example
Enumerable#methods:
  all?   cycle       each_slice  first     max      min_by     one?          sort     to_a
  any?   detect      entries     group_by  max_by   minmax     partition     sort_by  to_h
  chain  each_cons   find        include?  member?  minmax_by  reduce        sum      to_set
  count  each_entry  find_index  inject    min      none?      reverse_each  tally
Enumerator#methods:
  +     each_with_index   feed     next         peek         rewind  with_object
  each  each_with_object  inspect  next_values  peek_values  size
Enumerator::Lazy#methods:
  chunk           drop        filter      force   map          slice_before  to_enum
  chunk_while     drop_while  filter_map  grep    reject       slice_when    uniq
  collect         eager       find_all    grep_v  select       take          with_index
  collect_concat  enum_for    flat_map    lazy    slice_after  take_while    zip

vs TruffleRuby:

[18] pry(main)> puts RUBY_DESCRIPTION
truffleruby 21.0.0.2, like ruby 2.7.2, GraalVM CE Native [x86_64-darwin]
=> nil
[19] pry(main)> example = [].lazy
=> #<Enumerator::Lazy: #<Enumerator::Generator:0x26f8 @proc=#<Proc:0x2708 <internal:core> core/enumerator.rb:285>>:each>
[20] pry(main)> ls example
Enumerable#methods:
  all?         cycle       entries     force     max_by   minmax_by  reverse_each  sort_by  to_set
  any?         detect      filter_map  group_by  member?  none?      slice_after   sum
  chain        each_cons   find        include?  min      one?       slice_before  tally
  chunk_while  each_entry  find_index  inject    min_by   partition  slice_when    to_a
  count        each_slice  first       max       minmax   reduce     sort          to_h
Enumerator#methods:
  +     each_with_index   feed     next         peek         rewind  with_index
  each  each_with_object  inspect  next_values  peek_values  size    with_object
Enumerator::Lazy#methods:
  chunk           drop        enum_for  flat_map  lazy    select      to_enum
  collect         drop_while  filter    grep      map     take        uniq
  collect_concat  eager       find_all  grep_v    reject  take_while  zip

Let me know if I can provide any more information! :)

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions