Note that there are some explanatory texts on larger screens.

plurals
  1. PORuby equivalent of C#'s 'yield' keyword, or, creating sequences without preallocating memory
    primarykey
    data
    text
    <p>In C#, you could do something like this:</p> <pre><code>public IEnumerable&lt;T&gt; GetItems&lt;T&gt;() { for (int i=0; i&lt;10000000; i++) { yield return i; } } </code></pre> <p>This returns an enumerable sequence of 10 million integers without ever allocating a collection in memory of that length.</p> <p>Is there a way of doing an equivalent thing in Ruby? The specific example I am trying to deal with is the flattening of a rectangular array into a sequence of values to be enumerated. The return value does not have to be an <code>Array</code> or <code>Set</code>, but rather some kind of sequence that can only be iterated/enumerated in order, not by index. Consequently, the entire sequence need not be allocated in memory concurrently. In .NET, this is <code>IEnumerable</code> and <code>IEnumerable&lt;T&gt;</code>.</p> <p>Any clarification on the terminology used here in the Ruby world would be helpful, as I am more familiar with .NET terminology.</p> <p><strong>EDIT</strong></p> <p>Perhaps my original question wasn't really clear enough -- I think the fact that <code>yield</code> has very different meanings in C# and Ruby is the cause of confusion here.</p> <p>I don't want a solution that requires my method to use a block. I want a solution that has an actual return value. A return value allows convenient processing of the sequence (filtering, projection, concatenation, zipping, etc).</p> <p>Here's a simple example of how I might use <code>get_items</code>:</p> <pre><code>things = obj.get_items.select { |i| !i.thing.nil? }.map { |i| i.thing } </code></pre> <p>In C#, any method returning <code>IEnumerable</code> that uses a <code>yield return</code> causes the compiler to generate a finite state machine behind the scenes that caters for this behaviour. I suspect something similar could be achieved using Ruby's continuations, but I haven't seen an example and am not quite clear myself on how this would be done.</p> <p>It does indeed seem possible that I might use <a href="http://ruby-doc.org/core/classes/Enumerable.html" rel="noreferrer"><code>Enumerable</code></a> to achieve this. A simple solution would be to us an <code>Array</code> (which includes module <code>Enumerable</code>), but I do not want to create an intermediate collection with N items in memory when it's possible to just provide them lazily and avoid any memory spike at all.</p> <p>If this still doesn't make sense, then consider the above code example. <code>get_items</code> returns an enumeration, upon which <code>select</code> is called. What is passed to <code>select</code> is an instance that knows how to provide the next item in the sequence whenever it is needed. Importantly, the whole collection of items hasn't been calculated yet. Only when <code>select</code> needs an item will it ask for it, and the latent code in <code>get_items</code> will kick into action and provide it. This <em>laziness</em> carries along the chain, such that <code>select</code> only draws the next item from the sequence when <code>map</code> asks for it. As such, a long chain of operations can be performed on one data item at a time. In fact, code structured in this way can even process an <em>infinite</em> sequence of values without any kinds of memory errors.</p> <p>So, this kind of laziness is easily coded in C#, and I don't know how to do it in Ruby.</p> <p>I hope that's clearer (I'll try to avoid writing questions at 3AM in future.)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload