https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112019-07-02T13:31:32ZRuby Issue Tracking SystemRuby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=790342019-07-02T13:31:32Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>I agree. Even though we have to investigate how big the consequence of the change first.</p>
<p>Matz.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=790352019-07-02T14:14:33Zalanwu (Alan Wu)
<ul><li><strong>Subject</strong> changed from <i>Make Kernel#lambda always return lambda</i> to <i>Make it so Kernel#lambda always return a lambda</i></li></ul> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=790602019-07-02T20:49:17ZEregon (Benoit Daloze)
<ul></ul><p>I'm not sure changing this is good, because it can be very surprising for the code to change semantics dynamically.<br>
Also, should <code>proc(&lambda)</code> make a non-lambda Proc then? It would be inconsistent if not.</p>
<p>As I said in <a href="https://bugs.ruby-lang.org/issues/15620#note-2" class="external">https://bugs.ruby-lang.org/issues/15620#note-2</a>, the current rule is AFAIK only change the semantics if a block is directly given, because the programmer means to use those semantics then.<br>
If not, don't change the semantics as it would break the user (the Proc's code)'s intention.<br>
The only exception to this is <code>define_method</code> with a pre-existing <code>Proc</code>, which is very rare, and understandably needed because methods should check arguments strictly. (maybe we don't need that exception)</p>
<p>I believe <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Block argument usage affects lambda semantic (Closed)" href="https://bugs.ruby-lang.org/issues/15620">#15620</a> should be fixed on its own, it's a bug of the optimization.</p>
<p>Here is an example (a bit contrived, I'm tired):</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
<span class="n">early_check</span> <span class="o">=</span> <span class="no">Proc</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span>
<span class="c1"># everything here assumes it will always be proc/non-lambda semantics</span>
<span class="k">return</span> <span class="ss">:early_return</span> <span class="k">if</span> <span class="n">arg</span> <span class="o">></span> <span class="mi">3</span>
<span class="p">}</span>
<span class="c1"># Some way for some external code to access `early_check`</span>
<span class="n">early_check</span> <span class="o">=</span> <span class="k">yield</span> <span class="n">early_check</span>
<span class="n">early_check</span><span class="p">.</span><span class="nf">call</span>
<span class="ss">:method_return_value</span>
<span class="k">end</span>
<span class="nb">p</span> <span class="n">foo</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">pr</span><span class="o">|</span> <span class="nb">lambda</span><span class="p">(</span><span class="o">&</span><span class="n">pr</span><span class="p">)</span> <span class="p">}</span>
</code></pre>
<p>With current semantics, it returns <code>:early_return</code>.<br>
With the proposed change, it returns <code>:method_return_value</code>.<br>
That's very surprising, isn't it? The code clearly means it wants a non-local return to exit the method,<br>
and yet somehow it was transformed into a local lambda return!</p>
<p>I think such a surprising transformation of user code should happen as little as possible, so I'm against this proposal.</p>
<p>Maybe we should simply forbid calling <code>proc</code>/<code>lambda</code> without a literal block (i.e., with an explicit Proc like <code>lambda(&pr)</code>), since it doesn't do anything useful ?<br>
That would make more sense to me, and be in line with @ko1's recent changes to disallow things like <code>Proc.new</code>, etc without a block.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=790662019-07-03T01:59:36Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul><li><strong>Related to</strong> <i><a class="issue tracker-2 status-7 priority-4 priority-default closed" href="/issues/12957">Feature #12957</a>: A more OO way to create lambda Procs</i> added</li></ul> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=790682019-07-03T01:59:48Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul><li><strong>Related to</strong> <i><a class="issue tracker-2 status-2 priority-4 priority-default" href="/issues/7314">Feature #7314</a>: Convert Proc to Lambda doesn't work in MRI</i> added</li></ul> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=790692019-07-03T02:03:05Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul></ul><p>No. I'm against it. We have discussed this before multiple times. See the issues I linked just now.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=791892019-07-08T00:20:27Zalanwu (Alan Wu)
<ul></ul><p>The 2.4 spec is a bit problematic since it makes it impossible to forward a<br>
block to <code>Kernel#lambda</code> with a block pass. In the rest of the language<br>
forwarding a block has no effect on semantics compared to passing one<br>
literally. The idea of literal blocks being different from non-literal ones<br>
exists <em>only</em> in the case of <code>Kernel#lambda</code>.</p>
<p>A concept at odds with the rest of the language specific to one single method<br>
is sure to surprise. Special one-off concepts make the language harder to learn<br>
and add complications to implementaitons.</p>
<p>As others have pointed out, it's already possible to transform a proc into a<br>
lambda-proc via <code>define_method</code>. My proposal isn't adding anything new with<br>
regards to messing with the perscribed usage of code within blocks.</p>
<p>Transforming a proc into a lambda-proc is certainly a sharp tool. For me it<br>
falls in the same category as <code>instance_variable_set</code> and <code>const_set</code>. However,<br>
I think the situation in which it ends up being surprinsg is very rare.<br>
<code>return</code> within a <code>Proc.new do ...</code> comes up rarely as is.</p>
<p>Is "someone might misuse this in specific sutations" a good reason to keep an<br>
ad-hoc concept in the language? For me, no.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=791902019-07-08T00:35:08Zalanwu (Alan Wu)
<ul></ul><p>I would also like to note that if we revert back to the behavior in 2.4, code that relied on <code>lambda</code> without block will not have an easy upgrade path.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">make_a_lambda</span>
<span class="nb">lambda</span>
<span class="k">end</span>
</code></pre>
<p>is not equivalent to</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">make_a_lambda</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="nb">lambda</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>under 2.4 spec.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=792142019-07-08T13:49:19Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul></ul><p>"It's already broken, why not break it more" is not what I can follow.</p>
<p>Can I ask you why you need this feature? If this not more than a matter of consistency, I would like to second @eregon's proposal: lambdas without literal blocks to be prohibited at all.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=792432019-07-09T14:32:17Zalanwu (Alan Wu)
<ul></ul><blockquote>
<p>Can I ask you why you need this feature?</p>
</blockquote>
<p>I want to be able to forward a block to <code>Kernel#lambda</code>.</p>
<p><code>Kernel#lambda</code> is in a weird spot. Even though it's a method, making it behave like one has the unfortunate side-effect of allowing proc transformation.<br>
On the other hand, restricting it to just literal blocks is fairly magical and makes it just another way to do stabby lambda.<br>
It seems like there is no perfect solution here.<br>
I don't feel too strongly about my proposal. Banning block-pass to <code>Kernel#lambda</code> sounds good to me too if others are not comfortable with making proc-to-lambda transformation more accessible.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=792442019-07-09T14:38:03ZEregon (Benoit Daloze)
<ul></ul><p>alanwu (Alan Wu) wrote:</p>
<blockquote>
<p><code>Kernel#lambda</code> is in a weird spot. Even though it's a method, making it behave like one has the unfortunate side-effect of allowing proc transformation.</p>
</blockquote>
<p>Yes, the semantics of <code>Kernel#lambda</code> have always been a bit weird because no method should be allowed to convert a Proc to a lambda and inversely.<br>
And visually, <code>lambda { ... }</code> receives a block, which is a non-lambda Proc.</p>
<p>My point of view is <code>lambda</code> is a relic of the past, and we should use <code>-> { ... }</code> instead, which has clear semantics and obviously you can't pass a pre-existing block to it.<br>
Yes, I think we should raise <code>lambda(&existing_block)</code> as that can't behave intuitively (it seems either useless or confusing).</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=792732019-07-11T05:20:30Zakr (Akira Tanaka)akr@fsij.org
<ul></ul><p>I'm against it.</p>
<p>Changing lambda <-> proc can violate the intent of programmers who write a block.</p>
<p>It seems good to raise an exception at <code>lambda(&b)</code> where b is (non-lambda) proc.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=792852019-07-11T08:18:56Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>In my opinion, <code>lambda</code> should return <code>lambda</code> object as a principle. We need to keep the discussion.<br>
Maybe we can generate a delegating lambda object in this case.</p>
<p>Matz.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=792902019-07-11T10:00:39Zknu (Akinori MUSHA)knu@ruby-lang.org
<ul></ul><p>I don't think the lambda flag should be altered after the creation of a proc, because it's all up to the writer of a block how <code>return</code>/<code>break</code> etc. in it should work.</p>
<p>What about just deprecate <code>lambda</code> in the long run in favor of the lambda literal <code>->() {}</code>?</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=792962019-07-11T11:57:50Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>knu (Akinori MUSHA) wrote:</p>
<blockquote>
<p>I don't think the lambda flag should be altered after the creation of a proc, because it's all up to the writer of a block how <code>return</code>/<code>break</code> etc. in it should work.</p>
</blockquote>
<p>akr wrote similar opinion.</p>
<p>This same opinion would call for deprecation of <code>define_method(&block)</code>, which I believe would be a mistake.</p>
<p>I am assuming it is clear that <code>lambda(&block)</code> would never mutate <code>block</code> and return a new object that would be a lambda.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=793072019-07-11T16:27:57Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul></ul><p>Suppose we change the spec so that <code>lambda(&nonlambda)</code> generates a lambda.<br>
Suppose we have the following nonlambda proc:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mi">1</span><span class="p">:</span> <span class="n">foldr</span> <span class="o">=</span> <span class="nb">proc</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="p">,</span> <span class="o">*</span><span class="n">xs</span><span class="o">|</span>
<span class="mi">2</span><span class="p">:</span> <span class="n">foo</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">foldr</span><span class="o">.</span><span class="p">(</span><span class="n">xs</span><span class="p">))</span> <span class="k">if</span> <span class="n">x</span> <span class="o">||!</span> <span class="n">xs</span><span class="p">.</span><span class="nf">empty?</span>
<span class="mi">3</span><span class="p">:</span> <span class="k">end</span>
</code></pre>
<p>A straight-forward foldr implementation, with <code>foo</code> defined elsewhere.<br>
Now let's "convert" it into a lambda:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mi">4</span><span class="p">:</span> <span class="n">foldr</span> <span class="o">=</span> <span class="nb">lambda</span><span class="p">(</span><span class="o">&</span><span class="n">foldr</span><span class="p">)</span>
</code></pre>
<p>This magically breaks the program. The meaning of <code>|x, *xs|</code> changed.<br>
The problem I see is that the broken program would generate a backtrace like this:</p>
<pre><code>Traceback (most recent call last):
5444: from tmp.rb:2:in `block in <main>'
5443: from tmp.rb:2:in `block in <main>'
5442: from tmp.rb:2:in `block in <main>'
5441: from tmp.rb:2:in `block in <main>'
5440: from tmp.rb:2:in `block in <main>'
5439: from tmp.rb:2:in `block in <main>'
5438: from tmp.rb:2:in `block in <main>'
... 5433 levels...
4: from tmp.rb:2:in `block in <main>'
3: from tmp.rb:2:in `block in <main>'
2: from tmp.rb:2:in `block in <main>'
1: from tmp.rb:2:in `block in <main>'
tmp.rb:2:in `block in <main>': stack level too deep (SystemStackError)
</code></pre>
<p>There is <em>no</em> single bit of information that the prolem is caused by that lambda conversion.<br>
An end user has no other way than to blame tmp.rb:2 not tmp.rb:4, because the backtrace says so.</p>
<p>This is really bad. Think of for instance the block was from another library. The library authors suddenly get angry bug reports due to some random other guy turned their proc into lambda. This is nonsense.</p>
<p>Non-lambda to lambda conversion disturbs the boundary point of responsibility. Should not be allowed I believe.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=793362019-07-12T04:11:19Zalanwu (Alan Wu)
<ul></ul><p>The idea to generate a delegating lambda seems to side-step a lot of the issues posted here.<br>
For reference here are some quotes from the log in <a class="issue tracker-5 status-5 priority-4 priority-default closed" title="Misc: DevelopersMeeting20190711Japan (Closed)" href="https://bugs.ruby-lang.org/issues/15930">#15930</a> (courtesy of ko1):</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">b</span> <span class="o">=</span> <span class="nb">proc</span> <span class="p">{</span><span class="o">|</span><span class="n">x</span><span class="o">|</span> <span class="n">x</span> <span class="p">}</span>
<span class="nb">lambda</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">)</span> <span class="c1">#=> lambda {|x| b[x] }</span>
<span class="n">b</span> <span class="o">=</span> <span class="nb">proc</span> <span class="p">{</span><span class="o">|</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">k</span><span class="p">:</span><span class="mi">1</span><span class="o">|</span> <span class="n">x</span> <span class="p">}</span>
<span class="nb">lambda</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">)</span> <span class="c1">#=> lambda {|x, y, k:1| b[x, y, k:k] }</span>
</code></pre>
<p>This preserves the <code>return</code> semantics in the original proc. I would imagine it would also add an entry to the call stack.<br>
(side note, I think the default parameter evaluation has to be left to the original proc too since a <code>return</code> could be in there)</p>
<p>What do you folks think about this?</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=793412019-07-12T05:20:25Zakr (Akira Tanaka)akr@fsij.org
<ul><li><strong>Related to</strong> <i><a class="issue tracker-2 status-7 priority-4 priority-default closed" href="/issues/9777">Feature #9777</a>: Feature Proposal: Proc#to_lambda</i> added</li></ul> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=793432019-07-12T05:22:53Zakr (Akira Tanaka)akr@fsij.org
<ul><li><strong>Related to</strong> <i><a class="issue tracker-2 status-5 priority-4 priority-default closed" href="/issues/8693">Feature #8693</a>: lambda invoked by yield acts as a proc with respect to return</i> added</li></ul> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=793442019-07-12T05:31:50Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul></ul><p>Yes, I can compromise with delegation scheme, as long as it leaves its own frame in the call stack. An optional method for a proc to prevent such delegation is desirable but can be added later.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=793452019-07-12T05:43:23Zakr (Akira Tanaka)akr@fsij.org
<ul></ul><p>Eregon (Benoit Daloze) wrote:</p>
<blockquote>
<p>With current semantics, it returns <code>:early_return</code>.<br>
With the proposed change, it returns <code>:method_return_value</code>.<br>
That's very surprising, isn't it?</p>
</blockquote>
<p>I agree.</p>
<p>The lambda-ness of Proc object affects control flow: the behavior of "return" and "break".</p>
<p>If lambda(&b) changes the lambda-ness of b, two control flow can exist.<br>
I think no programmer want to consider two control flow when implementing one block.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=793502019-07-12T09:30:19ZEregon (Benoit Daloze)
<ul></ul><p>alanwu (Alan Wu) wrote:</p>
<blockquote>
<p>The idea to generate a delegating lambda seems to side-step a lot of the issues posted here.</p>
</blockquote>
<p>So then, would it be the same semantics as this?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">b</span> <span class="o">=</span> <span class="nb">proc</span> <span class="p">{</span><span class="o">|</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">k</span><span class="p">:</span><span class="mi">1</span><span class="o">|</span> <span class="n">x</span> <span class="p">}</span>
<span class="n">l</span> <span class="o">=</span> <span class="nb">lambda</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">kwargs</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="o">|</span> <span class="n">b</span><span class="p">.</span><span class="nf">call</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">kwargs</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span> <span class="p">}</span>
</code></pre>
<p>I think the lambda cannot have the same (in the code) arguments as the proc, otherwise <a href="https://bugs.ruby-lang.org/issues/15973#note-16" class="external">https://bugs.ruby-lang.org/issues/15973#note-16</a> would fail too.</p>
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/16806">@alanwu (Alan Wu)</a> Can you present use case(s) for turning procs into lambdas?<br>
So far I only see consistency but the delegating lambda is not that consistent with #lambda with a literal block.<br>
Without a good use-case, I think raising on #lambda without a literal block would be the safest and least surprising.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=794362019-07-15T09:19:53ZEregon (Benoit Daloze)
<ul><li><strong>Related to</strong> <i><a class="issue tracker-1 status-5 priority-4 priority-default closed" href="/issues/16004">Bug #16004</a>: Kernel#lambda captured with Kernel#method doesn't create lambdas</i> added</li></ul> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=796882019-07-17T21:20:16Zalanwu (Alan Wu)
<ul></ul><blockquote>
<p>Can you present use case(s) for turning procs into lambdas?</p>
</blockquote>
<p>One use case is reading the parameters of blocks as if they were written for a method definition: <a href="https://bugs.ruby-lang.org/issues/9777#note-11" class="external">https://bugs.ruby-lang.org/issues/9777#note-11</a><br>
Another one is getting lambda style parameter checking for the incoming block. msgpack-ruby does this through the CAPI: <a href="https://github.com/msgpack/msgpack-ruby/blob/b48f9580bfd33be6a86652f10a41bd691a7d0c91/ext/msgpack/unpacker_class.c#L367" class="external">https://github.com/msgpack/msgpack-ruby/blob/b48f9580bfd33be6a86652f10a41bd691a7d0c91/ext/msgpack/unpacker_class.c#L367</a></p>
<p>I asked for opinions about the delegation scheme because it seems like a good way to go if we <em>must</em> return a lambda. At the time I didn't make up my mind as to whether it would be a good idea to return one.<br>
I now believe that banning everything but the literal block form lambda is overall better. <code>lambda</code> being a method exposes it to many different ways of calling it, some of which don't have obvious semantics.<br>
We can pick a semantic for lambda(&thing), but there will always be some percentage of users that find the behavior surprising. We can minimizes surprises, but we can't eliminate it, as long<br>
as <code>lambda</code> is a method.</p>
<p>To illustrate, here are two more ways to call into <code>Kernel#lambda</code> that are hard to define good semantics for: <code>super</code> (zsuper) and <code>method(:lambda).call {}</code>. Right now zsuper creates a lambda while<br>
<code>method(:lambda).call {}</code> doesn't. I'm not sure what these should do and different people probably have different ideas.</p>
<p>I think <code>lambda</code> was supposed to be a psudo-keyword but implementing it as a method is unfortunately exposing it to a whole array of usages that were not considered.<br>
If we can promote it to a psudo-keyword, that would be best. Failing that, banning <code>lambda(&thing)</code> at least removes one source of surprise with clear messaging.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=800912019-07-26T17:53:28ZDan0042 (Daniel DeLorme)
<ul></ul><p>I think the delegating lambda idea doesn't really work. I mean, it doesn't <em>do</em> anything. You just get a lambda that behaves like a proc. It just changes the return value of <code>Proc#lambda?</code> which I don't think has any benefit by itself. In fact it might be counterproductive to hide the fact that this Proc object really behaves like a proc and not a lambda.</p>
<p>It seems the main use case for proc->lambda conversion is to validate the Proc defines the correct parameters? But I believe it's quite ok to let the writer of the Proc worry about that. And if you <em>really</em> want a lambda you should just enforce it.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="nb">lambda</span><span class="p">)</span>
<span class="nb">lambda</span><span class="p">.</span><span class="nf">lambda?</span> <span class="ow">or</span> <span class="k">raise</span> <span class="no">ArgumentError</span>
<span class="nb">lambda</span><span class="p">.</span><span class="nf">call</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">foo</span> <span class="o">-></span> <span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">do</span>
<span class="mi">42</span>
<span class="k">end</span>
<span class="c1">#=> ArgumentError (wrong number of arguments (given 3, expected 1))</span>
</code></pre>
<p>So I haven't yet seen a single good use case for this conversion, and I can't think of one despite trying. You'd need a situation where you want a Proc to have either proc or lambda behavior based on a condition. That's....</p>
<p>On the other hand there's a good case to make for just letting the programmer do what s/he wants. If you want to convert a proc into a lambda presumably you have a reason for doing so, and understand the consequences. The only real danger is if a proc was converted to a lambda <em>inadvertently</em> . But I can't come up with a realistic situation where this could occur. All the "surprising" examples I've seen are contrived and in fact not surprising at all. If a method expects a proc and you give it a lambda, that's no different than giving it an Integer or any other object that fails expectations. I honestly can't think of a situation where you'd want <code>lambda(&myproc)</code> to just pass through the proc unchanged; if you don't want to convert you'd just use <code>myproc</code> directly, right?</p>
<p>In the end it seems the only benefit of proc<->lambda conversion is for the sake of consistency of the <code>proc</code> and <code>lambda</code> methods? I guess that makes some sense, because this situation is definitely weird and surprising:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">lambda</span><span class="p">{</span> <span class="p">}</span> <span class="c1">#=> #<Proc:0x000055e295d1d648@(irb):1 (lambda)> </span>
<span class="k">class</span> <span class="nc">X</span><span class="p">;</span><span class="k">def</span> <span class="nf">lambda</span><span class="p">;</span><span class="k">super</span><span class="p">;</span><span class="k">end</span><span class="p">;</span><span class="k">end</span><span class="p">;</span> <span class="no">X</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">lambda</span><span class="p">{</span> <span class="p">}</span> <span class="c1">#=> #<Proc:0x000055e295d0b0d8@(irb):2 (lambda)></span>
<span class="nb">lambda</span><span class="p">(</span><span class="o">&</span><span class="nb">proc</span><span class="p">{</span> <span class="p">})</span> <span class="c1">#=> #<Proc:0x000055e295d08d88@(irb):3></span>
<span class="nb">method</span><span class="p">(</span><span class="ss">:lambda</span><span class="p">).</span><span class="nf">call</span><span class="p">{</span> <span class="p">}</span> <span class="c1">#=> #<Proc:0x000055e295d01da8@(irb):4></span>
<span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span><span class="nb">lambda</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span><span class="k">end</span><span class="p">;</span> <span class="n">foo</span><span class="p">{</span> <span class="p">}</span> <span class="c1">#=> #<Proc:0x000055e295cf4810@(irb):6 (lambda)></span>
</code></pre> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=802632019-07-30T08:08:29Zko1 (Koichi Sasada)
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Assigned</i></li><li><strong>Assignee</strong> set to <i>matz (Yukihiro Matsumoto)</i></li></ul><p>does anyone can write a discussion summary? :p</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=802822019-07-30T13:31:07Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>I agree with <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/271">@akr (Akira Tanaka)</a> here, as long as <code>lambda</code> with a block argument warns.<br>
We need to keep compatibility. But I think we should warn this inconsistent behavior.</p>
<p>Matz.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=802862019-07-30T16:32:11ZDan0042 (Daniel DeLorme)
<ul></ul><p>akr (Akira Tanaka) wrote:</p>
<blockquote>
<p>The lambda-ness of Proc object affects control flow: the behavior of "return" and "break".</p>
<p>If lambda(&b) changes the lambda-ness of b, two control flow can exist.<br>
I think no programmer want to consider two control flow when implementing one block.</p>
</blockquote>
<p>I think everyone can agree with that. The issue I guess is <strong>should it be allowed to define a lambda using block syntax</strong>, with the two main viewpoints being</p>
<p>A. <code>lambda()</code> and <code>define_method()</code> already allow this, so it's a well established pattern. So why not allow <code>my_anonymous_function_dsl{ }</code> ? In this case the one writing the block knows it's supposed to have lambda semantics. In 2.5 it became allowed in certain circumstances but that was apparently unintended (<a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Block argument usage affects lambda semantic (Closed)" href="https://bugs.ruby-lang.org/issues/15620">#15620</a>)? A search through major gems showed no incompatibilities. Numerous tickets through the years indicate current behavior is surprising to many.</p>
<p>B. <code>lambda()</code> and <code>define_method()</code> should never have allowed this; proc/lambda semantics should be defined <strong>lexically</strong>. Changing it dynamically is surprising. We can't break compatibility but we should not dig ourselves any deeper. Use <code>my_anonymous_function_dsl&->{ }</code> instead. It's a change in behavior so there may be incompatibility issues.</p>
<p>Does this seem like an accurate summary?</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=803962019-08-05T16:04:53ZDan0042 (Daniel DeLorme)
<ul></ul><p>This may be irrelevant but I would like to point out that proc->lambda conversion was supported in ruby 1.8</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">b</span> <span class="o">=</span> <span class="no">Proc</span><span class="p">.</span><span class="nf">new</span><span class="p">{</span> <span class="k">return</span> <span class="mi">42</span> <span class="p">}</span>
<span class="n">b</span><span class="p">.</span><span class="nf">call</span> <span class="c1">#=> LocalJumpError: unexpected return</span>
<span class="nb">lambda</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">).</span><span class="nf">call</span> <span class="c1">#=> 42</span>
</code></pre>
<p>I'm not sure if the change was intentional or not, but this feature request is really about restoring lost behavior, not introducing new one. :-)</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=803972019-08-05T17:08:55Zsawa (Tsuyoshi Sawada)
<ul><li><strong>Subject</strong> changed from <i>Make it so Kernel#lambda always return a lambda</i> to <i>Let Kernel#lambda always return a lambda</i></li><li><strong>Description</strong> updated (<a title="View differences" href="/journals/80397/diff?detail_id=54073">diff</a>)</li></ul> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=817792019-09-28T03:46:52Zalanwu (Alan Wu)
<ul></ul><p>I have updated my fix for [Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Block argument usage affects lambda semantic (Closed)" href="https://bugs.ruby-lang.org/issues/15620">#15620</a>] to also issue a warning in cases it<br>
returns the argument it receives without modification.</p>
<p>Since both 2.5.x and 2.6.x has [Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Block argument usage affects lambda semantic (Closed)" href="https://bugs.ruby-lang.org/issues/15620">#15620</a>], there may be code in the wild that<br>
depend on the unintended lambda conversion behavior. It might make sense to<br>
put the 2.4.x behavior back for 2.7.0-preview2 to find out whether it's an<br>
issue.</p>
<p><a href="https://github.com/ruby/ruby/pull/2289" class="external">https://github.com/ruby/ruby/pull/2289</a></p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=832902019-12-20T12:48:34ZEregon (Benoit Daloze)
<ul><li><strong>Related to</strong> <i><a class="issue tracker-1 status-5 priority-4 priority-default closed" href="/issues/15620">Bug #15620</a>: Block argument usage affects lambda semantic</i> added</li></ul> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=833182019-12-21T21:09:18ZEregon (Benoit Daloze)
<ul><li><strong>Target version</strong> set to <i>36</i></li></ul><p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/13">@matz (Yukihiro Matsumoto)</a> Is it OK to warn for this in the next Ruby version?</p>
<p>I think it's going to highlight wrong usages (good) and I would expect there are very few usages of <code>lambda(&existing_proc)</code>.</p>
<p>The warnings were implemented in <a href="https://github.com/ruby/ruby/pull/2289" class="external">https://github.com/ruby/ruby/pull/2289</a> by <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/16806">@alanwu (Alan Wu)</a> but <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/17">@ko1 (Koichi Sasada)</a> said we should postpone them as it's too late for 2.7:<br>
<a href="https://github.com/ruby/ruby/pull/2289#issuecomment-567820054" class="external">https://github.com/ruby/ruby/pull/2289#issuecomment-567820054</a></p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=833832019-12-24T17:35:12Zko1 (Koichi Sasada)
<ul></ul><p>This is one idea: how about to prohibit <code>lambda(&...)</code> method call? (block literal is always prohibited)</p>
<p>3.0: deprecation warning and show 3.1 will raise exception for <code>lambda(&...)</code><br>
3.1: raise exception for <code>lambda(&...)</code></p>
<p>same as <code>proc</code>.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=833842019-12-24T17:37:27Zko1 (Koichi Sasada)
<ul></ul><p>more aggressive proposal is obsolete <code>lambda</code> call, and use <code>-></code> (maybe it is too aggressive).</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=833912019-12-25T11:04:37ZEregon (Benoit Daloze)
<ul></ul><p>ko1 (Koichi Sasada) wrote:</p>
<blockquote>
<p>This is one idea: how about to prohibit <code>lambda(&...)</code> method call? (block literal is always prohibited)</p>
</blockquote>
<p>I think you mean non-literal block (<code>&</code>) becomes prohibited.</p>
<blockquote>
<p>3.0: deprecation warning and show 3.1 will raise exception for <code>lambda(&...)</code><br>
3.1: raise exception for <code>lambda(&...)</code></p>
<p>same as <code>proc</code>.</p>
</blockquote>
<p>And whether it's <code>lambda(&...)</code> or <code>lambda { }</code> is detected by the lambda method itself (like for the warning)?</p>
<p>That sounds good to me.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=833922019-12-25T11:13:00ZEregon (Benoit Daloze)
<ul></ul><p>ko1 (Koichi Sasada) wrote:</p>
<blockquote>
<p>more aggressive proposal is obsolete <code>lambda</code> call, and use <code>-></code> (maybe it is too aggressive).</p>
</blockquote>
<p>Sounds even better to me, but I guess that might be disruptive for everyone to adopt <code>-> {}</code> style.<br>
It would be interesting to see what matz thinks about this.</p>
<p><code>-></code> exists since at least 2.0, so it shouldn't be a compatibility issue to use it.</p>
<p>From the point of view of a Ruby VM, not having to handle <code>#lambda</code> magically changing the semantics of the passed block would be great,<br>
because it's really awkward and hard to check if the block is literal or not (considering <code>lambda</code> can be <code>alias</code>-ed).</p>
<p>It would also simplify the semantics for the user: <code>method_call { ... }</code> is always a non-lambda Proc, and <code>-> {}</code> is the only way for a lambda.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=833932019-12-25T11:15:48ZEregon (Benoit Daloze)
<ul></ul><p>On a related note I think we should also prohibit <code>define_method(&non_lambda)</code> because that confusingly treats the same block body differently (e.g., the same <code>return</code> in the code means something different).</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=833942019-12-25T11:20:12Zzverok (Victor Shepelev)zverok.offline@gmail.com
<ul></ul><blockquote>
<p>On a related note I think we should also prohibit <code>define_method(&non_lambda)</code> because that confusingly treats the same block body differently (e.g., the same return in the code means something different).</p>
</blockquote>
<p>Seem it will have an awful impact on any DSLs?..</p>
<p>Like</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">skip_if</span> <span class="p">{</span> <span class="o">|</span><span class="n">user</span><span class="o">|</span> <span class="n">user</span><span class="p">.</span><span class="nf">admin?</span> <span class="p">}</span>
<span class="c1"># ...implemented as</span>
<span class="k">def</span> <span class="nf">skip_if</span><span class="p">(</span><span class="o">&</span><span class="n">condition</span><span class="p">)</span>
<span class="n">define_method</span><span class="p">(</span><span class="ss">:skip?</span><span class="p">,</span> <span class="o">&</span><span class="n">condition</span><span class="p">)</span>
<span class="k">end</span>
</code></pre> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=833962019-12-25T11:51:07ZEregon (Benoit Daloze)
<ul></ul><p>zverok (Victor Shepelev) wrote:</p>
<blockquote>
<p>Seem it will have an awful impact on any DSLs?..</p>
</blockquote>
<p>Which is IMHO a perfect example of how dangerous that is.<br>
What if it's <code>skip_if { |user| return 42 }</code>?<br>
Do you expect that to return from the surrounding method or to return from the block?<br>
For any non-lambda Proc it should mean return from the surrounding method, <code>define_method</code> breaks that (by converting a proc to a lambda implictly).</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Assuming your definition of skip_if</span>
<span class="n">skip_if</span> <span class="p">{</span> <span class="o">|</span><span class="n">user</span><span class="o">|</span> <span class="k">return</span> <span class="mi">42</span> <span class="p">}</span> <span class="c1"># should return from the surrounding method but does not</span>
<span class="n">skip?</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># but it does not, it just returns from the block!</span>
<span class="nb">proc</span> <span class="p">{</span> <span class="o">|</span><span class="n">user</span><span class="o">|</span> <span class="k">return</span> <span class="mi">43</span> <span class="p">}.</span><span class="nf">call</span> <span class="c1"># returns from the surrounding method</span>
<span class="k">raise</span> <span class="s2">"unreachable"</span> <span class="c1"># never reached, as expected</span>
</code></pre>
<p>There is an easy workaround:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">skip_if</span><span class="p">(</span><span class="o">&</span><span class="n">condition</span><span class="p">)</span>
<span class="n">define_method</span><span class="p">(</span><span class="ss">:skip?</span><span class="p">,</span> <span class="o">-></span> <span class="o">*</span><span class="n">args</span> <span class="p">{</span> <span class="n">condition</span><span class="p">.</span><span class="nf">call</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span> <span class="p">})</span>
<span class="k">end</span>
</code></pre>
<p>With that <code>skip?(1)</code> returns from the surrounding method, as it should like every other literal block.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=834022019-12-25T19:34:08Zzverok (Victor Shepelev)zverok.offline@gmail.com
<ul></ul><p>Ugh, let me be a bit philosophical here (how many times I promised myself to not engage in discussions about Ruby's "spirit"? I've lost count.)</p>
<p>I understand the point you are speaking from (language implementer's background, who constantly fights with "dangerously illogical" parts), but for me, one of the key points of Ruby's attractiveness is how far it goes to reduce boilerplate in a logical and humane way. There is a non-neglectible gap between "human" consistency and "computer" (formal) consistency.</p>
<p>I am writing in Ruby for >15 years now (and teaching it for >5 years, and blah-blah-blah). I've implemented and used metric shit-ton of DSLs. So, for me and my intuition is experience, it is just this way:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">skip_if</span> <span class="p">{</span> <span class="o">|</span><span class="n">user</span><span class="o">|</span> <span class="k">return</span> <span class="mi">42</span> <span class="p">}</span>
</code></pre>
<p>...is something that will behave "unexpectedly"? Yes.<br>
Have I met a lot of cases when it was really written and shot somebody in the head? No.<br>
What if somebody really happens to meet with this case and is surprised? I believe they'll spend some time to wrap they head about it. That's a price we pay to have "complex language for writing simple code".</p>
<p>Now, when I see this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">skip_if</span><span class="p">(</span><span class="o">&</span><span class="n">condition</span><span class="p">)</span>
<span class="n">define_method</span><span class="p">(</span><span class="ss">:skip?</span><span class="p">,</span> <span class="o">&</span><span class="n">condition</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>...which "should" be "simply workarounded" to this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">skip_if</span><span class="p">(</span><span class="o">&</span><span class="n">condition</span><span class="p">)</span>
<span class="n">define_method</span><span class="p">(</span><span class="ss">:skip?</span><span class="p">,</span> <span class="o">-></span> <span class="o">*</span><span class="n">args</span> <span class="p">{</span> <span class="n">condition</span><span class="p">.</span><span class="nf">call</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span> <span class="p">})</span>
<span class="k">end</span>
</code></pre>
<p>...I see it as "your language implementation is really busy doing its important things. So it will not help you to write clean and obvious code. I (language implementation) see what you want to do (define methods implementation from a block in the variable), and I know how to fix it (block should be converted to lambda), but you (puny human) should do it with your own soft hands".</p>
<p>It <em>can and will</em> harm the will to write simple helping DSLs (which, one may argue, "is a good thing" anyways?..)</p>
<p>Why, then, bother with "all this proc vs lambda nonsense" (as some may, and do, argue)? All in all, "you don't need this complexity at all", right? Because</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">sources</span><span class="p">.</span><span class="nf">zip</span><span class="p">(</span><span class="n">targets</span><span class="p">).</span><span class="nf">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">src</span><span class="p">,</span> <span class="n">tgt</span><span class="o">|</span> <span class="n">tgt</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="n">src</span><span class="p">)</span> <span class="p">}</span>
</code></pre>
<p>...can be "easily workarounded" as this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">sources</span><span class="p">.</span><span class="nf">zip</span><span class="p">(</span><span class="n">targets</span><span class="p">).</span><span class="nf">map</span><span class="p">(</span><span class="o">-></span><span class="p">(</span><span class="n">arguments</span><span class="p">)</span> <span class="p">{</span> <span class="n">arguments</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nf">write</span><span class="p">(</span><span class="n">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="p">}</span> <span class="p">}</span>
</code></pre>
<p>...and everything suddenly becames more consistent and homogenous...</p>
<p>We can go this way really far, honestly :)</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=834232019-12-26T07:53:27Zko1 (Koichi Sasada)
<ul></ul><p>Ok, make a new ticket about define_method. How about lambda?</p>
<p>Koichi</p>
<blockquote>
<p>2019/12/26 4:34、<a href="mailto:zverok.offline@gmail.com" class="email">zverok.offline@gmail.com</a>のメール:</p>
<p>Issue <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Let Kernel#lambda always return a lambda (Closed)" href="https://bugs.ruby-lang.org/issues/15973">#15973</a> has been updated by zverok (Victor Shepelev).</p>
<p>Ugh, let me be a bit philosophical here (how many times I promised myself to not engage in discussions about Ruby's "spirit"? I've lost count.)</p>
<p>I understand the point you are speaking from (language implementer's background, who constantly fights with "dangerously illogical" parts), but for me, one of the key points of Ruby's attractiveness is how far it goes to reduce boilerplate in a logical and humane way. There is a non-neglectible gap between "human" consistency and "computer" (formal) consistency.</p>
<p>I am writing in Ruby for >15 years now (and teaching it for >5 years, and blah-blah-blah). I've implemented and used metric shit-ton of DSLs. So, for me and my intuition is experience, it is just this way:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">skip_if</span> <span class="p">{</span> <span class="o">|</span><span class="n">user</span><span class="o">|</span> <span class="k">return</span> <span class="mi">42</span> <span class="p">}</span>
</code></pre>
<p>...is something that will behave "unexpectedly"? Yes.<br>
Have I met a lot of cases when it was really written and shot somebody in the head? No.<br>
What if somebody really happens to meet with this case and is surprised? I believe they'll spend some time to wrap they head about it. That's a price we pay to have "complex language for writing simple code".</p>
<p>Now, when I see this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">skip_if</span><span class="p">(</span><span class="o">&</span><span class="n">condition</span><span class="p">)</span>
<span class="n">define_method</span><span class="p">(</span><span class="ss">:skip?</span><span class="p">,</span> <span class="o">&</span><span class="n">condition</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>...which "should" be "simply workarounded" to this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">skip_if</span><span class="p">(</span><span class="o">&</span><span class="n">condition</span><span class="p">)</span>
<span class="n">define_method</span><span class="p">(</span><span class="ss">:skip?</span><span class="p">,</span> <span class="o">-></span> <span class="o">*</span><span class="n">args</span> <span class="p">{</span> <span class="n">condition</span><span class="p">.</span><span class="nf">call</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span> <span class="p">})</span>
<span class="k">end</span>
</code></pre>
<p>...I see it as "your language implementation is really busy doing its important things. So it will not help you to write clean and obvious code. I (language implementation) see what you want to do (define methods implementation from a block in the variable), and I know how to fix it (block should be converted to lambda), but you (puny human) should do it with your own soft hands".</p>
<p>It <em>can and will</em> harm the will to write simple helping DSLs (which, one may argue, "is a good thing" anyways?..)</p>
<p>Why, then, bother with "all this proc vs lambda nonsense" (as some may, and do, argue)? All in all, "you don't need this complexity at all", right? Because</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">sources</span><span class="p">.</span><span class="nf">zip</span><span class="p">(</span><span class="n">targets</span><span class="p">).</span><span class="nf">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">src</span><span class="p">,</span> <span class="n">tgt</span><span class="o">|</span> <span class="n">tgt</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="n">src</span><span class="p">)</span> <span class="p">}</span>
</code></pre>
<p>...can be "easily workarounded" as this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">sources</span><span class="p">.</span><span class="nf">zip</span><span class="p">(</span><span class="n">targets</span><span class="p">).</span><span class="nf">map</span><span class="p">(</span><span class="o">-></span><span class="p">(</span><span class="n">arguments</span><span class="p">)</span> <span class="p">{</span> <span class="n">arguments</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nf">write</span><span class="p">(</span><span class="n">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="p">}</span> <span class="p">}</span>
</code></pre>
<p>...and everything suddenly becames more consistent and homogenous...</p>
<p>We can go this way really far, honestly :)</p>
<hr>
<p>Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Let Kernel#lambda always return a lambda (Closed)" href="https://bugs.ruby-lang.org/issues/15973">#15973</a>: Let Kernel#lambda always return a lambda<br>
<a href="https://bugs.ruby-lang.org/issues/15973#change-83402" class="external">https://bugs.ruby-lang.org/issues/15973#change-83402</a></p>
<ul>
<li>Author: alanwu (Alan Wu)</li>
<li>Status: Assigned</li>
<li>Priority: Normal</li>
<li>Assignee: matz (Yukihiro Matsumoto)</li>
<li>Target version: 2.8</li>
</ul>
<hr>
<p>When Kernel#lambda receives a Proc that is not a lambda,<br>
it returns it without modification. l propose to change <code>Kernel#lambda</code><br>
so it always returns a lambda.</p>
<p>Calling a method called lambda and having it do nothing in effect is<br>
not very intuitive.</p>
<p><a href="https://github.com/ruby/ruby/pull/2262" class="external">https://github.com/ruby/ruby/pull/2262</a></p>
<p>Judging from marcandre's investigation here: <a href="https://bugs.ruby-lang.org/issues/15620#note-1" class="external">https://bugs.ruby-lang.org/issues/15620#note-1</a>,<br>
changing the behavior should not cause much breakage, if any.</p>
<p>This also happens to fix [Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Block argument usage affects lambda semantic (Closed)" href="https://bugs.ruby-lang.org/issues/15620">#15620</a>]</p>
<p>--<br>
<a href="https://bugs.ruby-lang.org/" class="external">https://bugs.ruby-lang.org/</a></p>
</blockquote> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=834322019-12-26T20:46:54ZDan0042 (Daniel DeLorme)
<ul></ul><blockquote>
<p>one of the key points of Ruby's attractiveness is how far it goes to reduce boilerplate in a logical and humane way. There is a non-neglectible gap between "human" consistency and "computer" (formal) consistency.</p>
</blockquote>
<p>+1, very much. I'm glad there's still someone who cares about usefulness over <a href="https://www.google.com/search?q=ralph+waldo+emerson+quote+foolish+consistency" class="external">"consistency"</a></p>
<p>Converting a proc to a lambda is very useful for DSLs. And generally speaking it's empowering to programmers. Maybe a bit dangerous, but I can take care of myself. I really don't need or want to be "protected" from powerful yet "unexpected" behaviors. This ticket was about making <code>lambda</code> always return a lambda; at which point did it become about preventing this from happening?</p>
<p>I understand there's many who are emotionally invested into making ruby stricter and easier to implement/optimize, but at least there should be good alternatives for what the proc->lambda conversion allows.</p>
<p>For DSLs:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1">#a block is specified, and this DSL is documented to have lambda semantics, so we need to convert the proc to lambda</span>
<span class="n">register_lambda</span><span class="p">(</span><span class="ss">:xyz</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="o">|</span>
<span class="k">return</span> <span class="n">x</span><span class="o">+</span><span class="n">y</span><span class="o">+</span><span class="n">z</span>
<span class="k">end</span>
<span class="c1">#or a pretty syntax to pass a lambda as a block</span>
<span class="n">register_lambda</span><span class="p">(</span><span class="ss">:xyz</span><span class="p">)</span><span class="o">-></span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="p">)</span> <span class="k">do</span>
<span class="k">return</span> <span class="n">x</span><span class="o">+</span><span class="n">y</span><span class="o">+</span><span class="n">z</span>
<span class="k">end</span>
<span class="c1">#because this is ugly, honestly</span>
<span class="n">register_lambda</span><span class="p">(</span><span class="ss">:xyz</span><span class="p">,</span> <span class="o">&-></span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="p">)</span> <span class="k">do</span>
<span class="k">return</span> <span class="n">x</span><span class="o">+</span><span class="n">y</span><span class="o">+</span><span class="n">z</span>
<span class="k">end</span><span class="p">)</span>
</code></pre>
<p>Or what about:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">block</span> <span class="o">=</span> <span class="nb">proc</span><span class="p">{</span> <span class="o">|</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="o">=</span><span class="mi">1</span><span class="o">|</span> <span class="p">}</span>
<span class="n">block</span><span class="p">.</span><span class="nf">parameters</span> <span class="c1">#=> [[:opt, :x], [:opt, :y], [:opt, :z]]</span>
<span class="c1"># yes I know that all params are optional in a proc,</span>
<span class="c1"># but I wanted to know which have a default value and which don't</span>
<span class="nb">lambda</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">).</span><span class="nf">parameters</span> <span class="c1">#=> [[:req, :x], [:req, :y], [:opt, :z]]</span>
<span class="c1"># this tells me what I wanted to know in a simple and easy way</span>
</code></pre>
<p>Beyond the argument that this is dangerous (yes it is), there's also the fact that, used wisely, this is sometimes <strong>useful</strong>.</p>
<blockquote>
<p>it's really awkward and hard to check if the block is literal or not (considering lambda can be alias-ed).</p>
</blockquote>
<p>Then wouldn't it be really simple if all blocks were converted to lambdas regardless of being literal or not? KISS.</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=837612020-01-10T22:21:21ZEregon (Benoit Daloze)
<ul></ul><p>Yes, sorry I should not have mentioned <code>define_method</code> here, even though it's related it's not the main topic.<br>
I'll make a new issue for it (<a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: define_method(non_lambda) should not change the semantics of the given Proc (Rejected)" href="https://bugs.ruby-lang.org/issues/16499">#16499</a>).</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=837622020-01-10T22:36:38ZEregon (Benoit Daloze)
<ul><li><strong>Related to</strong> <i><a class="issue tracker-2 status-6 priority-4 priority-default closed" href="/issues/16499">Feature #16499</a>: define_method(non_lambda) should not change the semantics of the given Proc</i> added</li></ul> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=839172020-01-16T08:12:27Zko1 (Koichi Sasada)
<ul></ul><p>Quote from today's devmeeting.</p>
<p>Discussion:</p>
<ul>
<li>Proposing to deprecate <code>lambda(&block)</code> (<code>lambda</code> call with <code>Proc</code> object as block)</li>
<li>Benefits of obsoleting <code>lambda</code>?
<ul>
<li>Simplify for new Ruby developers. (no duplicated syntax.)</li>
<li>Suspend for short term (for years)</li>
</ul>
</li>
<li>Don't want more incompatibilities just after Ruby 2.7</li>
<li>Migration pass to deprecate <code>lambda(&block)</code>.
<ol>
<li>Print warning at 3.0. (No compatibility layer.)
<ul>
<li>“The lambda call is meaningless. Delete it.”</li>
<li>“Delete meaningless lambda”</li>
</ul>
</li>
<li>Raises error at 3.1 (or 3.2, ...)</li>
</ol>
</li>
</ul>
<p>Conclusion:</p>
<ul>
<li>
<code>lambda(&b)</code> will be prohibited.
<ul>
<li>Print warning at 3.0. (No compatibility layer.)</li>
<li>Raises error at 3.1 (or 3.2, ...)</li>
</ul>
</li>
</ul> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=860992020-06-11T14:31:10Zjeremyevans (Jeremy Evans)code@jeremyevans.net
<ul><li><strong>Status</strong> changed from <i>Assigned</i> to <i>Closed</i></li></ul><p>Applied in changeset <a class="changeset" title="Warn when passing a non-literal block to Kernel#lambda Implements [Feature #15973]" href="https://bugs.ruby-lang.org/projects/ruby-master/repository/git/revisions/2188d6d160d3ba82432c87277310a4d417e136d5">git|2188d6d160d3ba82432c87277310a4d417e136d5</a>.</p>
<hr>
<p>Warn when passing a non-literal block to Kernel#lambda</p>
<p>Implements [Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Let Kernel#lambda always return a lambda (Closed)" href="https://bugs.ruby-lang.org/issues/15973">#15973</a>]</p> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=877812020-09-29T03:37:27Zhsbt (Hiroshi SHIBATA)hsbt@ruby-lang.org
<ul><li><strong>Target version</strong> changed from <i>36</i> to <i>3.0</i></li></ul> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=888932020-12-03T02:46:07Zznz (Kazuhiro NISHIYAMA)
<ul><li><strong>Related to</strong> <i><a class="issue tracker-2 status-5 priority-4 priority-default closed" href="/issues/17361">Feature #17361</a>: lambda(&block) does not warn with lazy proc allocation</i> added</li></ul> Ruby master - Feature #15973: Let Kernel#lambda always return a lambdahttps://bugs.ruby-lang.org/issues/15973?journal_id=941342021-10-15T12:35:08ZEregon (Benoit Daloze)
<ul></ul><p>@jeremyevans added a test for this in <a href="https://github.com/ruby/ruby/commit/2188d6d160d3ba82432c87277310a4d417e136d5#diff-8b146f8f5073c5ee6526a128c3e9c05ae7a52d2cd496f601351470137f2a87a0" class="external">https://github.com/ruby/ruby/commit/2188d6d160d3ba82432c87277310a4d417e136d5#diff-8b146f8f5073c5ee6526a128c3e9c05ae7a52d2cd496f601351470137f2a87a0</a><br>
but it was removed by <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/4">@nobu (Nobuyoshi Nakada)</a> in <a href="https://github.com/ruby/ruby/commit/996af2ce086249e904b2ce95ab2fcd1de7d757be#diff-8b146f8f5073c5ee6526a128c3e9c05ae7a52d2cd496f601351470137f2a87a0" class="external">https://github.com/ruby/ruby/commit/996af2ce086249e904b2ce95ab2fcd1de7d757be#diff-8b146f8f5073c5ee6526a128c3e9c05ae7a52d2cd496f601351470137f2a87a0</a></p>
<p>And also this no longer warns, which sounds like a bug due to removing that test:</p>
<pre><code>$ ruby -v -w -e 'p Warning[:deprecated]; p lambda(&:symbol)'
ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux]
true
#<Proc:0x0000000001b07a38(&:symbol) (lambda)>
</code></pre>
<p>I guess maybe expected since Symbol#to_proc#lambda? is true (was false in 2.7)<br>
And in that logic <code>ruby -v -w -e 'p Warning[:deprecated]; p lambda(&lambda{})'</code> also doesn't warn.</p>
<p>This does warn as intended though, and we'll add a spec for it:</p>
<pre><code>$ ruby -v -w -e 'p Warning[:deprecated]; p lambda(&proc{})'
ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux]
true
-e:1: warning: lambda without a literal block is deprecated; use the proc without lambda instead
#<Proc:0x00000000020dfcf8 -e:1>
</code></pre>
<p>Found from <a href="https://github.com/oracle/truffleruby/pull/2500" class="external">https://github.com/oracle/truffleruby/pull/2500</a></p>