https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17097754782019-10-15T15:51:59ZRuby Issue Tracking SystemRuby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=820482019-10-15T15:51:59ZEregon (Benoit Daloze)
<ul><li><strong>Related to</strong> <i><a class="issue tracker-5 status-1 priority-4 priority-default" href="/issues/16157">Misc #16157</a>: What is the correct and *portable* way to do generic delegation?</i> added</li></ul> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=820492019-10-15T15:53:00ZEregon (Benoit Daloze)
<ul></ul><p><code>...</code> has been proposed a few times as well, I'm not sure if there is a ticket for 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="o">...</span><span class="p">)</span>
<span class="vi">@bar</span><span class="p">.</span><span class="nf">foo</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
</code></pre> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=820522019-10-15T17:20:21Zshevegen (Robert A. Heiler)shevegen@gmail.com
<ul></ul><p>Hmm. I have not decided whether I like the proposal or not; I guess I am mostly<br>
neutral, but with a slight tendency towards not being in favour of it. But leaving<br>
this aside, I think there are perhaps a few points of note.</p>
<ol>
<li>
<p>Part of this proposal reminds me of delegate/delegation, e. g. delegating calls<br>
from one object to another - a bit like the Forwardable module may do. So a small<br>
issuer may be for other ruby users to understand the difference(s), towards the<br>
proposal here, and the forwardable module.</p>
</li>
<li>
<p>I think the core idea behind the proposal is primarily to save some keys, which<br>
on the one hand may be nice; on the other hand .... hmmm. To me personally, I do<br>
not understand why * would or could be used/retrofitted into meaning to "just<br>
pass all arguments". You also wrote that you are fine with other syntax; I<br>
believe that it may be better to see whether we could come up with another<br>
syntax altogether that still is short, could be used here, without adding a new<br>
meaning to *.</p>
</li>
</ol>
<p>Benoit mentioned that there were other tickets for use of (...); I am not sure<br>
if there are other tickets for this specifically, but I recall having read that<br>
in other tickets, perhaps even proposed by matz (I don't remember, sorry).</p>
<p>I think using (...) would be a bit better than using/retrofitting *, even<br>
though * uses fewer characters. I am not a huge fan of (...) either though,<br>
but I do not dispute that it can be, in principle, useful. (Actually I just<br>
noticed that the link Benoit used pointed to your own suggestion. :D)</p>
<p>Personally I think getting the syntax "right" would be best. I am not sure<br>
how useful it would be, or how often it could be used; that might also have<br>
to be kept in mind. The recent python 3.8.0 release, for example, there<br>
was quite some discussion here and there about how useful or often used<br>
some of these features are. IMO whenever possible, the more people who CAN<br>
use a feature, and who also WILL use a feature, the better - so getting the<br>
syntax "right" here would be important.</p>
<p>I don't have a good proposal myself though.</p>
<p>I'll use a verbose dummy-example:</p>
<pre><code>def foo(*bar)
@some_other_object.foo(yield_arguments)
</code></pre>
<p>That's way too verbose, but I guess it may illustrate the goal of<br>
wanting to "yield the arguments onto that method". Actually we may<br>
have that already? Or perhaps not ... we have <strong>method</strong> ... perhaps<br>
we may need <strong>arguments</strong> too and then some syntactic sugar for<br>
it. It also reminds me a bit of "yield" and &proc - but anyway,<br>
IMO syntax matters. .foo(...) is a bit better than .foo(*) IMO,<br>
but not perfect. It may be difficult to get "great" results with<br>
very short syntax alone, withouting losing meaning.</p>
<blockquote>
<p>And we'd even be future-proof if an eventual FOURTH kind of<br>
parameter is introduced!!!!</p>
</blockquote>
<p>I don't think this is a good argument ;) because IF this were a<br>
problem, one could always suggest a proposal to see a change.</p>
<p>You can even find old joke-proposals such as:</p>
<pre><code>def foo
def bar
def ble
enddd
</code></pre>
<p>Or something like that. :P (Although I do have to admit that using several "end"<br>
can be a bit tedious; I just think that was a joke proposal since ... who in his<br>
sane mind wants to just spam the character "d", to mean end-of-scope, as several<br>
"end" would mean. Mandatory indent is also not that great either; I hate that I<br>
can't just copy/paste into the interactive python interpreter. IRB's behaviour is<br>
so much nicer and more convenient here.)</p>
<blockquote>
<p>If rubyists must be told they have to change their forwarding code in 2.7<br>
(due to keyword arguments), the pill might be easier to swallow if the change<br>
is a reduction rather than an increase in verbosity.</p>
</blockquote>
<p>Well. I think matz said that this may be the only (or perhaps just one of the<br>
very few) changes between 2.x and 3.0, possibly the biggest one. I don't know<br>
the status about frozen Strings, but there are always those who like changes,<br>
and those who don't. Giving people time to prepare to switch is, IMO, always<br>
a good thing; it helps reduce problems in the long run. I don't think people<br>
are THAT opposed to change. But to come back to your comment - I don't think<br>
that the changes in regards to keyword arguments, should be connected to any<br>
syntax proposal in regards to delegation, for several reason. One is that I<br>
think they are not really that much connected; but also because the change in<br>
regards to keywords came, at the least partially, because it was confusing<br>
to many people. Matz even made jokes about it during some presentations.</p>
<p>I personally use oldschool hash options usually, barely any keyword arguments,<br>
so I am not affected really either way. Perhaps it would also be interesting<br>
to see what Jeremy thinks about syntax shortcuts/proposal in this regard,<br>
not solely confined to (*) or (...) but just in general.</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=820722019-10-16T10:33:54ZEregon (Benoit Daloze)
<ul></ul><p>Things to consider:</p>
<ul>
<li>Is <code>*</code> or <code>...</code> an expression? What does <code>def m(...); a = ...; p a; end; m(1, a: 2) {}</code> print?</li>
<li>Do we want to support required arguments before? It would be useful for <code>method_missing</code>:</li>
</ul>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">name</span><span class="p">.</span><span class="nf">to_s</span><span class="p">.</span><span class="nf">end_with?</span><span class="p">(</span><span class="s1">'!'</span><span class="p">)</span>
<span class="k">super</span>
<span class="k">else</span>
<span class="vi">@target</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=820742019-10-16T13:05:37ZDan0042 (Daniel DeLorme)
<ul></ul><blockquote>
<ul>
<li>Is <code>*</code> or <code>...</code> an expression? What does <code>def m(...); a = ...; p a; end; m(1, a: 2) {}</code> print?</li>
</ul>
</blockquote>
<p>I would tend to say <code>a = ...</code> is a syntax error; my intention was to use this only in the argument list of a method call, with an implementation similar to <code>super</code> without parentheses.</p>
<blockquote>
<ul>
<li>Do we want to support required arguments before? It would be useful for <code>method_missing</code>
</li>
</ul>
</blockquote>
<p>Then rather than "forward everything" the meaning would be more like "capture all extra arguments". That means we could have <code>foo(a, *)</code> or <code>foo(a, k:, *)</code> or <code>foo(a, k:, *, &b)</code> ... imho this is too complicated and it's better to just use the regular syntax at that point.</p>
<p>But it's true that often we want to operate on the arguments before forwarding, so I think maybe an asymmetric syntax like this would work best?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="o">*</span><span class="p">)</span> <span class="c1">#currently valid syntax</span>
<span class="k">if</span> <span class="nb">name</span><span class="p">.</span><span class="nf">to_s</span><span class="p">.</span><span class="nf">end_with?</span><span class="p">(</span><span class="s1">'!'</span><span class="p">)</span>
<span class="k">super</span>
<span class="k">else</span>
<span class="vi">@target</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="o">***</span><span class="p">)</span> <span class="c1">#forward everything, including name</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=820752019-10-16T13:17:03Zzverok (Victor Shepelev)zverok.offline@gmail.com
<ul></ul><blockquote>
<p>But it's true that often we want to operate on the arguments before forwarding, so I think maybe an asymmetric syntax like this would work best?</p>
</blockquote>
<p>BTW, that's very valid point — similar problem was discussed here: <a href="https://bugs.ruby-lang.org/issues/15049#change-73845" class="external">https://bugs.ruby-lang.org/issues/15049#change-73845</a>: There was a request for "all current method arguments list" API, and examples there were related to delegation, too. Quoting from there (my code example and comment)</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="n">path</span><span class="p">:,</span> <span class="ss">accept: :json</span><span class="p">,</span> <span class="ss">headers: </span><span class="p">{},</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
<span class="n">_request</span><span class="p">(</span><span class="ss">method: :get</span><span class="p">,</span> <span class="n">__all</span> <span class="n">the</span> <span class="n">rest</span> <span class="n">of</span> <span class="n">what</span> <span class="n">have</span> <span class="n">passed</span> <span class="n">to</span> <span class="n">this</span> <span class="n">method___</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">post</span><span class="p">(</span><span class="n">path</span><span class="p">:,</span> <span class="n">body</span><span class="p">:,</span> <span class="ss">accept: :json</span><span class="p">,</span> <span class="ss">headers: </span><span class="p">{},</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
<span class="n">_request</span><span class="p">(</span><span class="ss">method: :post</span><span class="p">,</span> <span class="n">__all</span> <span class="n">the</span> <span class="n">rest</span> <span class="n">of</span> <span class="n">what</span> <span class="n">have</span> <span class="n">passed</span> <span class="n">to</span> <span class="n">this</span> <span class="n">method___</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># ...and so on</span>
</code></pre>
<blockquote>
<p>Two of currently available options:</p>
</blockquote>
<blockquote>
<ol>
<li>Accept just **arguments, and make checking what was mandatory, what should have default value and so on manually (also making auto-generated docs less expressive)</li>
<li>Accept everything as in my example, and then just do <code>_request(method: :get, path: path, body: body, accept: accept, headers: headers, **options)</code> ...that looks not DRY at all.</li>
</ol>
</blockquote>
<p>The solution proposed there was something like</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="n">path</span><span class="p">:,</span> <span class="ss">accept: :json</span><span class="p">,</span> <span class="ss">headers: </span><span class="p">{},</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
<span class="n">_request</span><span class="p">(</span><span class="ss">method: :get</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="c1"># pass ALL arguments</span>
<span class="k">end</span>
</code></pre>
<p>...but following your suggestiong, it could've been</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="n">path</span><span class="p">:,</span> <span class="ss">accept: :json</span><span class="p">,</span> <span class="ss">headers: </span><span class="p">{},</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
<span class="n">_request</span><span class="p">(</span><span class="ss">method: :get</span><span class="p">,</span> <span class="o">***</span><span class="p">)</span> <span class="c1"># pass ALL arguments</span>
<span class="k">end</span>
</code></pre>
<p>...which is kinda nice.</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=820782019-10-16T16:55:36Zjeremyevans0 (Jeremy Evans)merch-redmine@jeremyevans.net
<ul></ul><p>The disadvantage I see to this proposal is increased complexity. Both internal complexity in the implementation, and also more complexity for the user, as this adds more syntax Ruby programmers need to understand. However, I think the increased complexity for the user is probably offset by the fact that the <code>...</code> syntax is simpler than <code>*a, **kw, &b</code> and probably more understandable for new Ruby programmers.</p>
<p>The main advantage I see to this proposal is potentially better performance (in CRuby). Currently, delegating using:</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="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">o</span><span class="p">,</span> <span class="o">&</span><span class="n">b</span><span class="p">)</span>
<span class="vi">@bar</span><span class="p">.</span><span class="nf">foo</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">o</span><span class="p">,</span> <span class="o">&</span><span class="n">b</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>Causes an array allocation and multiple hash allocations for the delegation itself. Theoretically, delegating using:</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="o">...</span><span class="p">)</span>
<span class="vi">@bar</span><span class="p">.</span><span class="nf">foo</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>should not cause any allocations for the delegation itself.</p>
<p>In terms of <code>*</code> vs. <code>...</code>, I would go with <code>...</code>. <code>@bar.foo(*)</code> doesn't imply to me that it would pass keyword arguments or a block, as <code>@bar.foo(*a)</code> wouldn't pass keyword arguments or a block.</p>
<p>I think there are some questions that need to be answered, if we decide to do this.</p>
<p>First, do we allow any other arguments in the method definition? If so, do we only allow mandatory positional arguments? Do we support optional positional arguments? I think it wouldn't make sense to support rest, keyword, or block arguments. Supporting mandatory positional arguments makes this more flexible and usable in more places, but also increases complexity.</p>
<p>Second, where we do allow <code>...</code> when calling? Is this allowed and does is pass arguments from <code>foo</code> to <code>@bar.foo</code>?:</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="o">...</span><span class="p">)</span>
<span class="n">synchronize</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="o">|</span>
<span class="vi">@bar</span><span class="p">.</span><span class="nf">foo</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Does this code pass arguments that <code>synchronize</code> yields to <code>@bar.foo</code>:</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="o">...</span><span class="p">)</span>
<span class="n">synchronize</span> <span class="k">do</span> <span class="o">|...|</span>
<span class="vi">@bar</span><span class="p">.</span><span class="nf">foo</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Is this a <code>SyntaxError</code>?:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="k">def</span> <span class="nf">foo</span>
<span class="vi">@bar</span><span class="p">.</span><span class="nf">foo</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>What about:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="no">PR</span> <span class="o">=</span> <span class="nb">proc</span> <span class="k">do</span>
<span class="vi">@bar</span><span class="p">.</span><span class="nf">foo</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">instance_exec</span><span class="p">(</span><span class="o">&</span><span class="no">PR</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>If <code>...</code> can be implemented such that it improves performance over <code>*a, **kw, &b</code> (in CRuby), I think it may be worth adding. Otherwise, I don't think this is worth adding.</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=820792019-10-16T17:32:34ZDan0042 (Daniel DeLorme)
<ul></ul><p>Given the very interesting use case that zverok presented, I'm leaning more in favor of a lexically-scoped "operator" that doesn't need to be present in the method signature. So no invocation via block, just like <code>super</code>. Actually, the more it behaves similary to <code>super</code>, the easier it is to explain. So it would allow things like this:</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">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="n">d</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">e</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">f</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">g</span><span class="p">:</span><span class="mi">10</span><span class="p">,</span> <span class="n">h</span><span class="p">:</span><span class="mi">11</span><span class="p">,</span> <span class="n">i</span><span class="p">:</span><span class="mi">12</span><span class="p">,</span> <span class="n">j</span><span class="ss">:false</span><span class="p">)</span>
<span class="k">super</span><span class="p">(</span><span class="mi">42</span><span class="p">,</span> <span class="o">***</span><span class="p">)</span> <span class="ow">or</span> <span class="vi">@bar</span><span class="p">.</span><span class="nf">foo</span><span class="p">(</span><span class="mi">54</span><span class="p">,</span> <span class="o">***</span><span class="p">)</span>
<span class="c1">#here, `super(***)` would be equivalent to `super`</span>
<span class="k">end</span>
</code></pre>
<p>(I've become partial to <code>***</code> because it looks like a splat plus a double splat, which is kind of what this shorthand means... it's a <strong>hyper-splat</strong>!)</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=821802019-10-18T23:17:23Zioquatix (Samuel Williams)samuel@oriontransfer.net
<ul></ul><p>Here are some real world examples from my code:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">for</span><span class="p">(</span><span class="o">*</span><span class="n">arguments</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="nb">self</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">block</span><span class="p">,</span> <span class="o">*</span><span class="n">arguments</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># Nicer?</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">for</span><span class="p">(</span><span class="o">...</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="nb">self</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">block</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>Module to be prepended:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">Connection</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="o">*</span><span class="p">)</span>
<span class="k">super</span>
<span class="c1"># Other stuff</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># Nicer?</span>
<span class="k">module</span> <span class="nn">Connection</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">super</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="c1"># Other stuff</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Many repeated code:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">one</span><span class="p">(</span><span class="o">*</span><span class="n">arguments</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
<span class="n">append</span> <span class="no">One</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="o">*</span><span class="n">arguments</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">many</span><span class="p">(</span><span class="o">*</span><span class="n">arguments</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
<span class="n">append</span> <span class="no">Many</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="o">*</span><span class="n">arguments</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">split</span><span class="p">(</span><span class="o">*</span><span class="n">arguments</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
<span class="n">append</span> <span class="no">Split</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="o">*</span><span class="n">arguments</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># Nicer and more maintainable?</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">split</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">append</span> <span class="no">Split</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>There are many more but since this feature is exciting to me, I wanted to give some specific use cases so we can evaluate how they would benefit/change.</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=821812019-10-18T23:33:37Zjeremyevans0 (Jeremy Evans)merch-redmine@jeremyevans.net
<ul></ul><p>ioquatix (Samuel Williams) wrote:</p>
<blockquote>
<p>Here are some real world examples from my code:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">for</span><span class="p">(</span><span class="o">*</span><span class="n">arguments</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="nb">self</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">block</span><span class="p">,</span> <span class="o">*</span><span class="n">arguments</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># Nicer?</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">for</span><span class="p">(</span><span class="o">...</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="nb">self</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">block</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
</blockquote>
<p>From reading the last dev meeting log (under <code>Future work: lead argument handling is postponed</code>), this will not be supported, at least initially.</p>
<blockquote>
<p>Module to be prepended:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">Connection</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="o">*</span><span class="p">)</span>
<span class="k">super</span>
<span class="c1"># Other stuff</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># Nicer?</span>
<span class="k">module</span> <span class="nn">Connection</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">super</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="c1"># Other stuff</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
</blockquote>
<p>I think a bare <code>super</code> makes more sense than <code>super(...)</code>, and it is backwards compatible. However, in order to avoid keyword argument separation issues, if the super method accepts keyword arguments, you need to do <code>def initialize(*, **)</code> instead of <code>def initialize(*)</code> (<code>def initialize(...)</code> should also work).</p>
<blockquote>
<p>Many repeated code:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">split</span><span class="p">(</span><span class="o">*</span><span class="n">arguments</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
<span class="n">append</span> <span class="no">Split</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="o">*</span><span class="n">arguments</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># Nicer and more maintainable?</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">split</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">append</span> <span class="no">Split</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
</blockquote>
<p>Definitely looks nicer, so if you don't care about backwards compatibility, it seems like a good change.</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=821822019-10-19T02:56:37Zioquatix (Samuel Williams)samuel@oriontransfer.net
<ul></ul><p>The reason to support <code>...</code> with other args is something like this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Controller</span> <span class="o"><</span> <span class="no">Container</span><span class="o">::</span><span class="no">Controller</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="o">*</span><span class="n">arguments</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="vi">@command</span> <span class="o">=</span> <span class="n">command</span>
<span class="k">super</span><span class="p">(</span><span class="o">*</span><span class="n">arguments</span><span class="p">,</span> <span class="o">**</span><span class="n">options</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="c1"># Nicer?</span>
<span class="k">class</span> <span class="nc">Controller</span> <span class="o"><</span> <span class="no">Container</span><span class="o">::</span><span class="no">Controller</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
<span class="vi">@command</span> <span class="o">=</span> <span class="n">command</span>
<span class="k">super</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>I think <code>...</code> should be remainder of arguments that aren't explicitly consumed. Semantics might be a little bit more tricky to implement, but it makes a lot of sense to me and there are <em>many</em> places where such a syntax would make things not only clearer, but also faster by eliding allocations for <code>*arguments</code> and <code>**options</code>.</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=821892019-10-20T11:56:46Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<ul></ul><p>The parser itself was easy, but I'm wondering how ripper should treat it.</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=821912019-10-20T12:07:11Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<ul></ul><p>ioquatix (Samuel Williams) wrote:</p>
<blockquote>
<p>I think <code>...</code> should be remainder of arguments that aren't explicitly consumed.</p>
</blockquote>
<p>If it is the remainder, then it should be placed after all explicit arguments?</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">pre</span><span class="p">,</span> <span class="n">opt</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">,</span> <span class="o">*</span><span class="n">rest</span><span class="p">,</span> <span class="n">kw</span><span class="p">:,</span> <span class="o">&</span><span class="n">block</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
</code></pre> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=822132019-10-21T17:36:12Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Closed</i></li></ul><p>Applied in changeset <a class="changeset" title="Arguments forwarding [Feature #16253]" href="https://bugs.ruby-lang.org/projects/ruby-master/repository/git/revisions/62d43828770211470bcacb9e943876f981b5a1b4">git|62d43828770211470bcacb9e943876f981b5a1b4</a>.</p>
<hr>
<p>Arguments forwarding [Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Shorthand "forward everything" syntax (Closed)" href="https://bugs.ruby-lang.org/issues/16253">#16253</a>]</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=822482019-10-22T19:37:50Zbaweaver (Brandon Weaver)keystonelemur@gmail.com
<ul></ul><p>Going to do a writeup on this later tonight if anyone wants to proof-read it, it'll be interesting to see what the wider community thinks but I really like it.</p>
<p>Also really loving the attention to detail Jeremy's been giving lately, really helps to clear up details.</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=825892019-11-10T10:15:38ZEregon (Benoit Daloze)
<ul><li><strong>Related to</strong> <i><a class="issue tracker-2 status-1 priority-4 priority-default" href="/issues/16296">Feature #16296</a>: Alternative behavior for `...` in method body if `...` is not in method definition</i> added</li></ul> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=825922019-11-10T10:27:43ZEregon (Benoit Daloze)
<ul></ul><p>Note: this feature allows <code>def m(...)</code> but not <code>def m(meth, ...)</code> on current Ruby master.</p>
<p>I found that in some cases, the behavior is rather surprising as <code>...</code> can also be the beginless endless Range:</p>
<pre><code>$ ruby -e 'def m(...); p(...); end; m(1,2)'
1
2
$ ruby -e 'def m(...); p ...; end; m(1,2)'
^ nothing
$ ruby -e 'def m(...); p ...; end; p m(1,2)'
nil...nil
$ ruby -e 'def m(...); p(...[0]); end; m(1,2)'
...[0]
</code></pre>
<p>Can someone explain the second one?</p>
<p>I think we should clarify for this feature that <code>...</code> isn't an object or an expression, it's only valid as arguments passed to a method.</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=825932019-11-10T10:39:33Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul></ul><p>Eregon (Benoit Daloze) wrote:</p>
<blockquote>
<p>Note: this feature allows <code>def m(...)</code> but not <code>def m(meth, ...)</code> on current Ruby master.</p>
<p>I found that in some cases, the behavior is rather surprising as <code>...</code> can also be the beginless endless Range:</p>
<pre><code>$ ruby -e 'def m(...); p(...); end; m(1,2)'
1
2
$ ruby -e 'def m(...); p ...; end; m(1,2)'
^ nothing
$ ruby -e 'def m(...); p ...; end; p m(1,2)'
nil...nil
$ ruby -e 'def m(...); p(...[0]); end; m(1,2)'
...[0]
</code></pre>
<p>Can someone explain the second one?</p>
</blockquote>
<p>It is parsed as an endless range <code>((p)...)</code>.</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=826022019-11-10T21:23:34ZEregon (Benoit Daloze)
<ul><li><strong>Status</strong> changed from <i>Closed</i> to <i>Open</i></li></ul><p>Is it intentional that this ticket was closed but <code>def m(meth, ...)</code> is a SyntaxError?</p>
<p>I'm going to reopen this, because I think it is severely limited for delegation otherwise.<br>
For example, it can't be used in</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">name</span><span class="p">.</span><span class="nf">to_s</span><span class="p">.</span><span class="nf">end_with?</span><span class="p">(</span><span class="s1">'='</span><span class="p">)</span>
<span class="n">update</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
<span class="k">else</span>
<span class="c1"># ...</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Using a helper method would be one way, but it's quite ugly:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">first_arg</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span>
<span class="n">args</span><span class="p">.</span><span class="nf">first</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="nb">name</span> <span class="o">=</span> <span class="n">first_arg</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">name</span><span class="p">.</span><span class="nf">to_s</span><span class="p">.</span><span class="nf">end_with?</span><span class="p">(</span><span class="s1">'='</span><span class="p">)</span>
<span class="n">update</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">else</span>
<span class="c1"># ...</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>And would quickly become unfeasible if, for instance, the delegated method doesn't take the <code>name</code> argument, or not as first argument.</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=826032019-11-10T21:41:02Zjeremyevans0 (Jeremy Evans)merch-redmine@jeremyevans.net
<ul></ul><p>Eregon (Benoit Daloze) wrote:</p>
<blockquote>
<p>Is it intentional that this ticket was closed but <code>def m(meth, ...)</code> is a SyntaxError?</p>
</blockquote>
<p>This is expected at present. Lead argument handling will probably happen in the future. From the notes of the last dev meeting:</p>
<pre><code>Future work: lead argument handling is postponed
* lead arguments can be extracted
* lead arguments can be added
* def f(x, y, ...); g(1, 2, ...); end
</code></pre>
<p>It is true that this means the syntax only handles a subset of delegation methods. You can always do things the longer way if you need more control:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">ruby2_keywords</span> <span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">name</span><span class="p">.</span><span class="nf">to_s</span><span class="p">.</span><span class="nf">end_with?</span><span class="p">(</span><span class="s1">'='</span><span class="p">)</span>
<span class="n">update</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
<span class="k">else</span>
<span class="c1"># ...</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=826062019-11-10T22:57:08ZEregon (Benoit Daloze)
<ul></ul><p>jeremyevans0 (Jeremy Evans) wrote:</p>
<blockquote>
<p>It is true that this means the syntax only handles a subset of delegation methods. You can always do things the longer way if you need more control:</p>
</blockquote>
<p>Right, except if one wants that code to work on Ruby 2.7+.<br>
I think <code>...</code> could be part of how to do delegation right in the future, succinctly:<br>
<a href="https://eregon.me/blog/2019/11/10/the-delegation-challenge-of-ruby27.html" class="external">https://eregon.me/blog/2019/11/10/the-delegation-challenge-of-ruby27.html</a></p>
<p>I think leading required arguments are the most most needed in delegation.</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=826332019-11-12T08:05:33Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Closed</i></li></ul><p>Applied in changeset <a class="changeset" title="NEWS: Make it clear that delegation syntax `(...)` requires parentheses Ref [Feature #16253]" href="https://bugs.ruby-lang.org/projects/ruby-master/repository/git/revisions/d1ae2bc27fd4183e6abb9e83691e192bfe1e5316">git|d1ae2bc27fd4183e6abb9e83691e192bfe1e5316</a>.</p>
<hr>
<p>NEWS: Make it clear that delegation syntax <code>(...)</code> requires parentheses</p>
<p>Ref [Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Shorthand "forward everything" syntax (Closed)" href="https://bugs.ruby-lang.org/issues/16253">#16253</a>]</p> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=828262019-11-27T16:50:31ZEregon (Benoit Daloze)
<ul><li><strong>Related to</strong> <i><a class="issue tracker-2 status-5 priority-4 priority-default closed" href="/issues/16378">Feature #16378</a>: Support leading arguments together with ...</i> added</li></ul> Ruby master - Feature #16253: Shorthand "forward everything" syntaxhttps://bugs.ruby-lang.org/issues/16253?journal_id=828282019-11-27T16:51:15ZEregon (Benoit Daloze)
<ul></ul><p>I filed <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Support leading arguments together with ... (Closed)" href="https://bugs.ruby-lang.org/issues/16378">#16378</a> for supporting leading arguments with <code>...</code>.</p>