ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek
@ 2025-07-24  2:37 nuzair46 (Nuzair Rasheed) via ruby-core
  2025-07-24  2:47 ` [ruby-core:122848] " nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: nuzair46 (Nuzair Rasheed) via ruby-core @ 2025-07-24  2:37 UTC (permalink / raw)
  To: ruby-core; +Cc: nuzair46 (Nuzair Rasheed)

Issue #21520 has been reported by nuzair46 (Nuzair Rasheed).

----------------------------------------
Feature #21520: Feature Proposal: Enumerator::Lazy#peek
https://bugs.ruby-lang.org/issues/21520

* Author: nuzair46 (Nuzair Rasheed)
* Status: Open
----------------------------------------
# Abstract

Add a #peek method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background

Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal

Introduce Enumerator::Lazy#peek, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .peek { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```

This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases

• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:

```rb
data = (1..).lazy
            .peek { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
```
And return [2, 4, 6, 8, 10]

# Discussion

#peek is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #peek is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I would be glad to work on this and make a PR. Thank you.




-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:122848] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek
  2025-07-24  2:37 [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek nuzair46 (Nuzair Rasheed) via ruby-core
@ 2025-07-24  2:47 ` nuzair46 (Nuzair Rasheed) via ruby-core
  2025-07-24 14:07 ` [ruby-core:122855] " Dan0042 (Daniel DeLorme) via ruby-core
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: nuzair46 (Nuzair Rasheed) via ruby-core @ 2025-07-24  2:47 UTC (permalink / raw)
  To: ruby-core; +Cc: nuzair46 (Nuzair Rasheed)

Issue #21520 has been updated by nuzair46 (Nuzair Rasheed).


# Abstract
Add a #peek method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background
Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal
Introduce Enumerator::Lazy#peek, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .peek { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```
This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases
• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:
```rb
data = (1..).lazy
            .peek { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
...
got 10
```
And return [2, 4, 6, 8, 10]

# Discussion
#peek is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #peek is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I would be glad to work on this and make a PR. Thank you.

----------------------------------------
Feature #21520: Feature Proposal: Enumerator::Lazy#peek
https://bugs.ruby-lang.org/issues/21520#change-114137

* Author: nuzair46 (Nuzair Rasheed)
* Status: Open
----------------------------------------
# Abstract

Add a #peek method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background

Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal

Introduce Enumerator::Lazy#peek, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .peek { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```

This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases

• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:

```rb
data = (1..).lazy
            .peek { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
```
And return [2, 4, 6, 8, 10]

# Discussion

#peek is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #peek is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I would be glad to work on this and make a PR. Thank you.




-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:122855] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek
  2025-07-24  2:37 [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek nuzair46 (Nuzair Rasheed) via ruby-core
  2025-07-24  2:47 ` [ruby-core:122848] " nuzair46 (Nuzair Rasheed) via ruby-core
@ 2025-07-24 14:07 ` Dan0042 (Daniel DeLorme) via ruby-core
  2025-07-25  3:31 ` [ruby-core:122863] " nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Dan0042 (Daniel DeLorme) via ruby-core @ 2025-07-24 14:07 UTC (permalink / raw)
  To: ruby-core; +Cc: Dan0042 (Daniel DeLorme)

Issue #21520 has been updated by Dan0042 (Daniel DeLorme).


#peek already exists, and does something different.

I think #each should work in the way this proposal describes. I was a bit surprised that the code below resulted in an infinite loop rather than a lazy enumeration.
```ruby
(1..).lazy.each{ |x| puts x }.select(&:even?).first(3)
```

----------------------------------------
Feature #21520: Feature Proposal: Enumerator::Lazy#peek
https://bugs.ruby-lang.org/issues/21520#change-114146

* Author: nuzair46 (Nuzair Rasheed)
* Status: Open
----------------------------------------
# Abstract

Add a #peek method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background

Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal

Introduce Enumerator::Lazy#peek, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .peek { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```

This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases

• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:

```rb
data = (1..).lazy
            .peek { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
...
got 10
```
And return [2, 4, 6, 8, 10]

# Discussion

#peek is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #peek is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I would be glad to work on this and make a PR. Thank you.




-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:122863] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek
  2025-07-24  2:37 [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek nuzair46 (Nuzair Rasheed) via ruby-core
  2025-07-24  2:47 ` [ruby-core:122848] " nuzair46 (Nuzair Rasheed) via ruby-core
  2025-07-24 14:07 ` [ruby-core:122855] " Dan0042 (Daniel DeLorme) via ruby-core
@ 2025-07-25  3:31 ` nuzair46 (Nuzair Rasheed) via ruby-core
  2025-07-28  2:44 ` [ruby-core:122870] " nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: nuzair46 (Nuzair Rasheed) via ruby-core @ 2025-07-25  3:31 UTC (permalink / raw)
  To: ruby-core; +Cc: nuzair46 (Nuzair Rasheed)

Issue #21520 has been updated by nuzair46 (Nuzair Rasheed).


Dan0042 (Daniel DeLorme) wrote in #note-2:
> #peek already exists, and does something different.

Hey, Enumerator#peek exists. but Enumerator::Lazy#peek does not.
Enumerator#peek [works differently](https://docs.ruby-lang.org/ja/latest/method/Enumerator/i/peek.html) than this suggestion. 
So maybe the naming will be confusing.

----------------------------------------
Feature #21520: Feature Proposal: Enumerator::Lazy#peek
https://bugs.ruby-lang.org/issues/21520#change-114155

* Author: nuzair46 (Nuzair Rasheed)
* Status: Open
----------------------------------------
# Abstract

Add a #peek method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background

Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal

Introduce Enumerator::Lazy#peek, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .peek { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```

This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases

• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:

```rb
data = (1..).lazy
            .peek { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
...
got 10
```
And return [2, 4, 6, 8, 10]

# Discussion

#peek is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #peek is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I would be glad to work on this and make a PR. Thank you.




-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:122870] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek
  2025-07-24  2:37 [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (2 preceding siblings ...)
  2025-07-25  3:31 ` [ruby-core:122863] " nuzair46 (Nuzair Rasheed) via ruby-core
@ 2025-07-28  2:44 ` nuzair46 (Nuzair Rasheed) via ruby-core
  2025-07-29  7:02 ` [ruby-core:122880] " nobu (Nobuyoshi Nakada) via ruby-core
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: nuzair46 (Nuzair Rasheed) via ruby-core @ 2025-07-28  2:44 UTC (permalink / raw)
  To: ruby-core; +Cc: nuzair46 (Nuzair Rasheed)

Issue #21520 has been updated by nuzair46 (Nuzair Rasheed).


nuzair46 (Nuzair Rasheed) wrote in #note-3:
> Enumerator#peek [works differently](https://docs.ruby-lang.org/ja/latest/method/Enumerator/i/peek.html) than this suggestion. 
> So maybe the naming will be confusing.

Running the whole CI, I see the collision with Enumerator#peek.
So I think the name should be changed to avoid confusion and collision.
Im thinking `spy` or `tap_each`


----------------------------------------
Feature #21520: Feature Proposal: Enumerator::Lazy#peek
https://bugs.ruby-lang.org/issues/21520#change-114171

* Author: nuzair46 (Nuzair Rasheed)
* Status: Open
----------------------------------------
# Abstract

Add a #peek method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background

Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal

Introduce Enumerator::Lazy#peek, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .peek { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```

This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases

• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:

```rb
data = (1..).lazy
            .peek { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
...
got 10
```
And return [2, 4, 6, 8, 10]

# Discussion

#peek is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #peek is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I have a draft PR for the implementation ready https://github.com/ruby/ruby/pull/14024



-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:122880] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek
  2025-07-24  2:37 [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (3 preceding siblings ...)
  2025-07-28  2:44 ` [ruby-core:122870] " nuzair46 (Nuzair Rasheed) via ruby-core
@ 2025-07-29  7:02 ` nobu (Nobuyoshi Nakada) via ruby-core
  2025-07-30  5:42 ` [ruby-core:122882] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#lazy_each nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: nobu (Nobuyoshi Nakada) via ruby-core @ 2025-07-29  7:02 UTC (permalink / raw)
  To: ruby-core; +Cc: nobu (Nobuyoshi Nakada)

Issue #21520 has been updated by nobu (Nobuyoshi Nakada).


Or `lazy_each`?

----------------------------------------
Feature #21520: Feature Proposal: Enumerator::Lazy#peek
https://bugs.ruby-lang.org/issues/21520#change-114183

* Author: nuzair46 (Nuzair Rasheed)
* Status: Open
----------------------------------------
# Abstract

Add a #peek method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background

Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal

Introduce Enumerator::Lazy#peek, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .peek { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```

This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases

• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:

```rb
data = (1..).lazy
            .peek { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
...
got 10
```
And return [2, 4, 6, 8, 10]

# Discussion

#peek is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #peek is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I have a draft PR for the implementation ready https://github.com/ruby/ruby/pull/14024



-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:122882] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#lazy_each
  2025-07-24  2:37 [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (4 preceding siblings ...)
  2025-07-29  7:02 ` [ruby-core:122880] " nobu (Nobuyoshi Nakada) via ruby-core
@ 2025-07-30  5:42 ` nuzair46 (Nuzair Rasheed) via ruby-core
  2025-08-05  2:30 ` [ruby-core:122913] " nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: nuzair46 (Nuzair Rasheed) via ruby-core @ 2025-07-30  5:42 UTC (permalink / raw)
  To: ruby-core; +Cc: nuzair46 (Nuzair Rasheed)

Issue #21520 has been updated by nuzair46 (Nuzair Rasheed).

Subject changed from Feature Proposal: Enumerator::Lazy#peek to Feature Proposal: Enumerator::Lazy#lazy_each
Description updated

updated to `lazy_each`

----------------------------------------
Feature #21520: Feature Proposal: Enumerator::Lazy#lazy_each
https://bugs.ruby-lang.org/issues/21520#change-114186

* Author: nuzair46 (Nuzair Rasheed)
* Status: Open
----------------------------------------
# Abstract

Add a #lazy_each method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background

Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal

Introduce Enumerator::Lazy#lazy_each, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .lazy_each { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```

This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases

• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:

```rb
data = (1..).lazy
            .lazy_each { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
...
got 10
```
And return [2, 4, 6, 8, 10]

# Discussion

#lazy_each is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #lazy_each is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I have a draft PR for the implementation ready https://github.com/ruby/ruby/pull/14024



-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:122913] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#lazy_each
  2025-07-24  2:37 [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (5 preceding siblings ...)
  2025-07-30  5:42 ` [ruby-core:122882] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#lazy_each nuzair46 (Nuzair Rasheed) via ruby-core
@ 2025-08-05  2:30 ` nuzair46 (Nuzair Rasheed) via ruby-core
  2025-08-21  8:15 ` [ruby-core:123002] " nobu (Nobuyoshi Nakada) via ruby-core
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: nuzair46 (Nuzair Rasheed) via ruby-core @ 2025-08-05  2:30 UTC (permalink / raw)
  To: ruby-core; +Cc: nuzair46 (Nuzair Rasheed)

Issue #21520 has been updated by nuzair46 (Nuzair Rasheed).


The PR is open for review https://github.com/ruby/ruby/pull/14024

----------------------------------------
Feature #21520: Feature Proposal: Enumerator::Lazy#lazy_each
https://bugs.ruby-lang.org/issues/21520#change-114217

* Author: nuzair46 (Nuzair Rasheed)
* Status: Open
----------------------------------------
# Abstract

Add a #lazy_each method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background

Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal

Introduce Enumerator::Lazy#lazy_each, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .lazy_each { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```

This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases

• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:

```rb
data = (1..).lazy
            .lazy_each { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
...
got 10
```
And return [2, 4, 6, 8, 10]

# Discussion

#lazy_each is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #lazy_each is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I have a draft PR for the implementation ready https://github.com/ruby/ruby/pull/14024



-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:123002] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#lazy_each
  2025-07-24  2:37 [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (6 preceding siblings ...)
  2025-08-05  2:30 ` [ruby-core:122913] " nuzair46 (Nuzair Rasheed) via ruby-core
@ 2025-08-21  8:15 ` nobu (Nobuyoshi Nakada) via ruby-core
  2025-08-21  8:28 ` [ruby-core:123004] " nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: nobu (Nobuyoshi Nakada) via ruby-core @ 2025-08-21  8:15 UTC (permalink / raw)
  To: ruby-core; +Cc: nobu (Nobuyoshi Nakada)

Issue #21520 has been updated by nobu (Nobuyoshi Nakada).


A couple days ago, another name came to me: `tee`.

----------------------------------------
Feature #21520: Feature Proposal: Enumerator::Lazy#lazy_each
https://bugs.ruby-lang.org/issues/21520#change-114304

* Author: nuzair46 (Nuzair Rasheed)
* Status: Open
----------------------------------------
# Abstract

Add a #lazy_each method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background

Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal

Introduce Enumerator::Lazy#lazy_each, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .lazy_each { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```

This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases

• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:

```rb
data = (1..).lazy
            .lazy_each { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
...
got 10
```
And return [2, 4, 6, 8, 10]

# Discussion

#lazy_each is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #lazy_each is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I have a draft PR for the implementation ready https://github.com/ruby/ruby/pull/14024



-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:123004] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#lazy_each
  2025-07-24  2:37 [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (7 preceding siblings ...)
  2025-08-21  8:15 ` [ruby-core:123002] " nobu (Nobuyoshi Nakada) via ruby-core
@ 2025-08-21  8:28 ` nuzair46 (Nuzair Rasheed) via ruby-core
  2025-08-21  9:16 ` [ruby-core:123008] " matz (Yukihiro Matsumoto) via ruby-core
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: nuzair46 (Nuzair Rasheed) via ruby-core @ 2025-08-21  8:28 UTC (permalink / raw)
  To: ruby-core; +Cc: nuzair46 (Nuzair Rasheed)

Issue #21520 has been updated by nuzair46 (Nuzair Rasheed).


nobu (Nobuyoshi Nakada) wrote in #note-9:
> A couple days ago, another name came to me: `tee`.

Thanks, `tee` is a great fit. It’s short and feels very Unix-y. I will make changes to the PR and the proposal soon.

----------------------------------------
Feature #21520: Feature Proposal: Enumerator::Lazy#lazy_each
https://bugs.ruby-lang.org/issues/21520#change-114306

* Author: nuzair46 (Nuzair Rasheed)
* Status: Open
----------------------------------------
# Abstract

Add a #lazy_each method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background

Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal

Introduce Enumerator::Lazy#lazy_each, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .lazy_each { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```

This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases

• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:

```rb
data = (1..).lazy
            .lazy_each { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
...
got 10
```
And return [2, 4, 6, 8, 10]

# Discussion

#lazy_each is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #lazy_each is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I have a draft PR for the implementation ready https://github.com/ruby/ruby/pull/14024



-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:123008] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#lazy_each
  2025-07-24  2:37 [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (8 preceding siblings ...)
  2025-08-21  8:28 ` [ruby-core:123004] " nuzair46 (Nuzair Rasheed) via ruby-core
@ 2025-08-21  9:16 ` matz (Yukihiro Matsumoto) via ruby-core
  2025-08-21  9:30 ` [ruby-core:123012] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#tee nuzair46 (Nuzair Rasheed) via ruby-core
  2026-02-17  5:12 ` [ruby-core:124842] " nuzair46 (Nuzair Rasheed) via ruby-core
  11 siblings, 0 replies; 13+ messages in thread
From: matz (Yukihiro Matsumoto) via ruby-core @ 2025-08-21  9:16 UTC (permalink / raw)
  To: ruby-core; +Cc: matz (Yukihiro Matsumoto)

Issue #21520 has been updated by matz (Yukihiro Matsumoto).


I don't think `lazy_each` is a good name. We just wanted to peek the element in the stream, being lazy or not. In that sense, `tee` is better, if you are familiar with UNIX (like me).

Matz.


----------------------------------------
Feature #21520: Feature Proposal: Enumerator::Lazy#lazy_each
https://bugs.ruby-lang.org/issues/21520#change-114310

* Author: nuzair46 (Nuzair Rasheed)
* Status: Open
----------------------------------------
# Abstract

Add a #lazy_each method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background

Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal

Introduce Enumerator::Lazy#lazy_each, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .lazy_each { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```

This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases

• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:

```rb
data = (1..).lazy
            .lazy_each { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
...
got 10
```
And return [2, 4, 6, 8, 10]

# Discussion

#lazy_each is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #lazy_each is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I have a draft PR for the implementation ready https://github.com/ruby/ruby/pull/14024



-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:123012] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#tee
  2025-07-24  2:37 [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (9 preceding siblings ...)
  2025-08-21  9:16 ` [ruby-core:123008] " matz (Yukihiro Matsumoto) via ruby-core
@ 2025-08-21  9:30 ` nuzair46 (Nuzair Rasheed) via ruby-core
  2026-02-17  5:12 ` [ruby-core:124842] " nuzair46 (Nuzair Rasheed) via ruby-core
  11 siblings, 0 replies; 13+ messages in thread
From: nuzair46 (Nuzair Rasheed) via ruby-core @ 2025-08-21  9:30 UTC (permalink / raw)
  To: ruby-core; +Cc: nuzair46 (Nuzair Rasheed)

Issue #21520 has been updated by nuzair46 (Nuzair Rasheed).


matz (Yukihiro Matsumoto) wrote in #note-11:
> I don't think `lazy_each` is a good name. We just wanted to peek the element in the stream, being lazy or not. In that sense, `tee` is better, if you are familiar with UNIX (like me).
> 
> Matz.

Thanks Matz. I have updated the PR and proposal with the name #tee for the method. 

----------------------------------------
Feature #21520: Feature Proposal: Enumerator::Lazy#tee
https://bugs.ruby-lang.org/issues/21520#change-114316

* Author: nuzair46 (Nuzair Rasheed)
* Status: Open
----------------------------------------
# Abstract

Add a #tee method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background

Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal

Introduce Enumerator::Lazy#tee, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .tee { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```

This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases

• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:

```rb
data = (1..).lazy
            .tee { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
...
got 10
```
And return [2, 4, 6, 8, 10]

# Discussion

#tee is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #tee is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I have a draft PR for the implementation ready https://github.com/ruby/ruby/pull/14024



-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:124842] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#tee
  2025-07-24  2:37 [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek nuzair46 (Nuzair Rasheed) via ruby-core
                   ` (10 preceding siblings ...)
  2025-08-21  9:30 ` [ruby-core:123012] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#tee nuzair46 (Nuzair Rasheed) via ruby-core
@ 2026-02-17  5:12 ` nuzair46 (Nuzair Rasheed) via ruby-core
  11 siblings, 0 replies; 13+ messages in thread
From: nuzair46 (Nuzair Rasheed) via ruby-core @ 2026-02-17  5:12 UTC (permalink / raw)
  To: ruby-core; +Cc: nuzair46 (Nuzair Rasheed)

Issue #21520 has been updated by nuzair46 (Nuzair Rasheed).


Just checking in on this feature. Is there anything missing from the current implementation that would help move it forward?

----------------------------------------
Feature #21520: Feature Proposal: Enumerator::Lazy#tee
https://bugs.ruby-lang.org/issues/21520#change-116496

* Author: nuzair46 (Nuzair Rasheed)
* Status: Open
----------------------------------------
# Abstract

Add a #tee method to Enumerator::Lazy that allows observing each element in a lazy enumeration pipeline without modifying or consuming the stream.

# Background

Ruby provides Enumerator::Lazy for efficient lazy stream processing. However, unlike languages such as Java, it lacks a clean way to inspect intermediate elements during lazy evaluation.

Currently, developers must misuse .map for side effects, example:
```rb
(1..).lazy.map { |x| puts x; x }.select(&:even?).first(3)
```
This is semantically incorrect and confusing, since .map implies transformation, not observation.

# Proposal

Introduce Enumerator::Lazy#tee, which yields each item to a block and returns the item unmodified, similar to Object#tap, but in a lazy stream:
```rb
(1..).lazy
     .tee { |x| puts "saw: #{x}" }
     .select(&:even?)
     .first(3)
```

This would be equivalent to:
```rb
lazy.map { |x| block.call(x); x }
```
but with improved semantic clarity.

# Use cases

• Debugging lazy enumerators without breaking the chain
• Logging or instrumentation in pipelines
• Educational / demo use for showing lazy evaluation step-by-step
• Cleaner replacement for map { puts x; x } hacks

Example:

```rb
data = (1..).lazy
            .tee { |x| puts "got #{x}" }
            .select(&:even?)
            .first(5)
```
result:
```rb
got 1
got 2
got 3
got 4
got 5
...
got 10
```
And return [2, 4, 6, 8, 10]

# Discussion

#tee is a minimal, non-breaking addition that improves clarity and idiomatic usage of Enumerator::Lazy. It avoids abusing .map for observation and is familiar to developers from other languages. #tee is also not needed for other enumerators where .tap or .each can do the job.

It mirrors Java’s .stream().peek(...) and makes Ruby’s lazy enumeration more expressive and readable.

# See also
• [Java Stream.peek](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-)

I have a draft PR for the implementation ready https://github.com/ruby/ruby/pull/14024



-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-02-17  5:12 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-24  2:37 [ruby-core:122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek nuzair46 (Nuzair Rasheed) via ruby-core
2025-07-24  2:47 ` [ruby-core:122848] " nuzair46 (Nuzair Rasheed) via ruby-core
2025-07-24 14:07 ` [ruby-core:122855] " Dan0042 (Daniel DeLorme) via ruby-core
2025-07-25  3:31 ` [ruby-core:122863] " nuzair46 (Nuzair Rasheed) via ruby-core
2025-07-28  2:44 ` [ruby-core:122870] " nuzair46 (Nuzair Rasheed) via ruby-core
2025-07-29  7:02 ` [ruby-core:122880] " nobu (Nobuyoshi Nakada) via ruby-core
2025-07-30  5:42 ` [ruby-core:122882] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#lazy_each nuzair46 (Nuzair Rasheed) via ruby-core
2025-08-05  2:30 ` [ruby-core:122913] " nuzair46 (Nuzair Rasheed) via ruby-core
2025-08-21  8:15 ` [ruby-core:123002] " nobu (Nobuyoshi Nakada) via ruby-core
2025-08-21  8:28 ` [ruby-core:123004] " nuzair46 (Nuzair Rasheed) via ruby-core
2025-08-21  9:16 ` [ruby-core:123008] " matz (Yukihiro Matsumoto) via ruby-core
2025-08-21  9:30 ` [ruby-core:123012] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#tee nuzair46 (Nuzair Rasheed) via ruby-core
2026-02-17  5:12 ` [ruby-core:124842] " nuzair46 (Nuzair Rasheed) via ruby-core

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).