https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17097754782021-12-02T18:45:02ZRuby Issue Tracking SystemRuby master - Feature #17721: Proc.new should be able to contruct a lambdahttps://bugs.ruby-lang.org/issues/17721?journal_id=950462021-12-02T18:45:02Zko1 (Koichi Sasada)
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Rejected</i></li></ul><p>could you make new ticket with more motivation/example/discussion?</p> Ruby master - Feature #17721: Proc.new should be able to contruct a lambdahttps://bugs.ruby-lang.org/issues/17721?journal_id=950502021-12-02T19:35:41Zbughit (bug hit)
<ul></ul><p>Why a new ticket? What's wrong with this one? If you wanted clarification you didn't have to close it, and even now you can still reopen.</p>
<p>As to the substance, if you want to transform an existing proc or lambda in a way that involves creating a new one and calling the original from it, it makes sense to end up with the same "type" you started with (proc or lambda). The simplest example is negation:</p>
<pre><code class="rb syntaxhl" data-language="rb">
<span class="k">class</span> <span class="nc">Proc</span>
<span class="k">def</span> <span class="nf">negate</span>
<span class="nb">self</span><span class="p">.</span><span class="nf">class</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span> <span class="o">|*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="o">|</span>
<span class="ow">not</span> <span class="nb">self</span><span class="o">.</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>The above will turn a lambda into a proc. Why shouldn't the Proc constructor be able to create a lambda? Lambdas should have probably been a sub-type, but as long as they share the same type and hence constructor, it seems almost an obligation for it to be able to construct either: <code>Proc.new(lambda: true)</code></p> Ruby master - Feature #17721: Proc.new should be able to contruct a lambdahttps://bugs.ruby-lang.org/issues/17721?journal_id=950712021-12-03T02:13:09Znaruse (Yui NARUSE)naruse@airemix.jp
<ul><li><strong>Status</strong> changed from <i>Rejected</i> to <i>Feedback</i></li></ul><p>A correct status of a ticket whose description doesn't have a use cases or user stories to discuss the validness of the request and the actual API design is "Feedback".e</p> Ruby master - Feature #17721: Proc.new should be able to contruct a lambdahttps://bugs.ruby-lang.org/issues/17721?journal_id=951102021-12-03T11:52:51ZEregon (Benoit Daloze)
<ul></ul><p>There is <code>Kernel.send(lambda ? :lambda : :proc) { ... }</code> if you really really need this.<br>
But it's probably slow and Ruby implementations have troubles to optimize this as they have no idea when parsing if the block is for a proc or lambda.</p>
<p>Of course the more sensible thing would be:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Proc</span>
<span class="k">def</span> <span class="nf">negate</span>
<span class="k">if</span> <span class="nb">lambda</span><span class="p">?</span>
<span class="nb">lambda</span> <span class="k">do</span> <span class="o">|*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="o">|</span>
<span class="ow">not</span> <span class="nb">self</span><span class="o">.</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">else</span>
<span class="nb">proc</span> <span class="k">do</span> <span class="o">|*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="o">|</span>
<span class="ow">not</span> <span class="nb">self</span><span class="o">.</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>That has a significant advantage that a given block only has proc or lambda semantics but not both (and so using e.g., <code>break</code> is possible).<br>
And also from looking at the backtrace you can know which it was.</p>
<p>I don't think it matters if <code>negate</code> e.g. always returns a lambda in this case (the caller can only observe the difference though <code>Proc#lambda?</code> and that shouldn't matter), so it should just be:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Proc</span>
<span class="k">def</span> <span class="nf">negate</span>
<span class="o">-></span> <span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span> <span class="k">do</span>
<span class="ow">not</span> <span class="nb">self</span><span class="o">.</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>As discussed extensively in related tickets, it's a very bad idea to convert from proc to lambda or vice-versa, but at least this issue only suggests a polymorphic create with a literal block.</p>
<p>So the important question here is why do you need to preserve whether the source Proc was a lambda or not?</p>