https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112011-06-20T22:08:14ZRuby Issue Tracking SystemRuby master - Feature #4910: Classes as factorieshttps://bugs.ruby-lang.org/issues/4910?journal_id=181032011-06-20T22:08:14ZEregon (Benoit Daloze)
<ul></ul><p>Hello,</p>
<p>Robert Klemme wrote:</p>
<blockquote>
<p>I suggest to add these two to class Class:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Class</span>
<span class="k">alias</span> <span class="n">call</span> <span class="n">new</span>
<span class="k">def</span> <span class="nf">to_proc</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span>
<span class="nb">lambda</span> <span class="p">{</span><span class="o">|*</span><span class="n">a</span><span class="o">|</span> <span class="n">new</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)}</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
</blockquote>
<p>Did you want to mean:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">to_proc</span>
<span class="nb">lambda</span> <span class="p">{</span> <span class="o">|*</span><span class="n">args</span><span class="o">|</span> <span class="n">new</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span> <span class="p">}</span> <span class="c1"># or maybe lambda { |args| new(*args) }</span>
<span class="k">end</span>
</code></pre>
<p>?</p>
<p><code>#to_proc</code> is called with no arguments (<code>Symbol.instance_method(:to_proc).arity</code> # => 0).</p>
<blockquote>
<p>Then we can use class instances where blocks are needed and can easily use them as factory instances using the general contract of <code>#call</code> (see example attached).</p>
</blockquote>
<p>I don't really see the advantage of defining <code>#call</code>, you could use <code>#new </code>instead at line 16.<br>
If you want more flexibility, I believe it is fine to use a block.</p>
<p>But I like <code>Class#to_proc</code>, and it is indeed some kind of factory helper:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Pos</span> <span class="o">=</span> <span class="no">Struct</span><span class="p">.</span><span class="nf">new</span> <span class="ss">:x</span><span class="p">,</span><span class="ss">:y</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="mi">4</span><span class="p">]].</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="no">Pos</span><span class="p">)</span> <span class="c1"># => [#&lt;struct Pos x=1, y=2&gt;, #&lt;struct Pos x=3, y=4&gt;]</span>
<span class="c1"># instead of</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="mi">4</span><span class="p">]].</span><span class="nf">map</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="o">|</span> <span class="no">Pos</span><span class="p">.</span><span class="nf">new</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="p">}</span>
<span class="c1"># note neither #to_proc defined as "lambda { |*args| new(*args) }" nor map(&Pos.method(:new)) would work:</span>
<span class="c1"># ([#&lt;struct Pos x=[1, 2], y=nil&gt;,...])</span>
</code></pre>
<p>The obvious limitation being the lack of flexibility for common arguments (e.g.: y always the same). You would then have to use an explicit block.</p>
<p>I do not know if it is worth to add it for this specific case, but it can be nice.</p>
<p>I am also unsure if we need factories in Ruby (certainly not like in statically typed languages).</p> Ruby master - Feature #4910: Classes as factorieshttps://bugs.ruby-lang.org/issues/4910?journal_id=181062011-06-20T23:29:42Zrklemme (Robert Klemme)shortcutter@googlemail.com
<ul></ul><p>Benoit Daloze wrote:</p>
<blockquote>
<p>Hello,</p>
<p>Robert Klemme wrote:</p>
<blockquote>
<p>I suggest to add these two to class Class:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Class</span>
<span class="k">alias</span> <span class="n">call</span> <span class="n">new</span>
<span class="k">def</span> <span class="nf">to_proc</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span>
<span class="nb">lambda</span> <span class="p">{</span><span class="o">|*</span><span class="n">a</span><span class="o">|</span> <span class="n">new</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)}</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
</blockquote>
<p>Did you want to mean:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">to_proc</span>
<span class="nb">lambda</span> <span class="p">{</span> <span class="o">|*</span><span class="n">args</span><span class="o">|</span> <span class="n">new</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span> <span class="p">}</span> <span class="c1"># or maybe lambda { |args| new(*args) }</span>
<span class="k">end</span>
</code></pre>
<p>?</p>
<p><code>#to_proc</code> is called with no arguments (<code>Symbol.instance_method(:to_proc).arity</code> # => 0).</p>
</blockquote>
<p>No, it was meant exactly as stated. Advantage is that you can provide parameters to #new if needed while mapping the parameterless call of <code>to_proc</code> easily to the parameterless call of <code>Class#new</code>.</p>
<blockquote>
<blockquote>
<p>Then we can use class instances where blocks are needed and can easily use them as factory instances using the general contract of <code>#call</code> (see example attached).</p>
</blockquote>
<p>I don't really see the advantage of defining <code>#call</code>, you could use <code>#new</code> instead at line 16.<br>
If you want more flexibility, I believe it is fine to use a block.</p>
</blockquote>
<p>That's the exact point: by aliasing <code>#new</code> to <code>#call</code> we can pass in a lambda OR a class instance. The most general contract would then be '#call'able (i.e. an anonymous callback function) and as a shortcut we can pass in a class instance.</p>
<blockquote>
<p>But I like <code>Class#to_proc</code>, and it is indeed some kind of factory helper:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Pos</span> <span class="o">=</span> <span class="no">Struct</span><span class="p">.</span><span class="nf">new</span> <span class="ss">:x</span><span class="p">,</span><span class="ss">:y</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="mi">4</span><span class="p">]].</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="no">Pos</span><span class="p">)</span> <span class="c1"># => [#&lt;struct Pos x=1, y=2&gt;, #&lt;struct Pos x=3, y=4&gt;]</span>
<span class="c1"># instead of</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="mi">4</span><span class="p">]].</span><span class="nf">map</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="o">|</span> <span class="no">Pos</span><span class="p">.</span><span class="nf">new</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="p">}</span>
<span class="c1"># note neither #to_proc defined as "lambda { |*args| new(*args) }" nor map(&Pos.method(:new)) would work:</span>
<span class="c1"># ([#&lt;struct Pos x=[1, 2], y=nil&gt;,...])</span>
</code></pre>
<p>The obvious limitation being the lack of flexibility for common arguments (e.g.: y always the same). You would then have to use an explicit block.</p>
<p>I do not know if it is worth to add it for this specific case, but it can be nice.</p>
</blockquote>
<p>I had considered that case as well and felt it might not be as common as the case where we try to provide arguments. I do not have any statistics though and I hope for others shedding some more light what they deem more useful.</p>
<p>A variant would be</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Class</span>
<span class="k">def</span> <span class="nf">to_proc</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="n">args</span><span class="p">.</span><span class="nf">empty?</span>
<span class="nb">lambda</span> <span class="p">{</span><span class="o">|*</span><span class="n">a</span><span class="o">|</span> <span class="n">new</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">)}</span>
<span class="k">else</span>
<span class="nb">lambda</span> <span class="p">{</span><span class="o">|*</span><span class="n">a</span><span class="o">|</span> <span class="n">new</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)}</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>In other words: if arguments are passed to <code>to_proc</code> use them as sole method arguments for <code>#new</code>; if not, use whatever is passed to the proc (which would support your mapping example).</p>
<p>We could probably make things even more complex by appending <code>*a</code> to <code>*args</code> and truncating the list with the arity of <code>#new</code> at the time of invocation of the block (or, more efficient, time of call of <code>to_proc</code>).</p>
<blockquote>
<p>I am also unsure if we need factories in Ruby (certainly not like in statically typed languages).</p>
</blockquote>
<p>Any class in Ruby <em>is</em> a factory object already with method <code>#new</code> being the factory method.</p> Ruby master - Feature #4910: Classes as factorieshttps://bugs.ruby-lang.org/issues/4910?journal_id=181552011-06-23T02:12:20Zheadius (Charles Nutter)headius@headius.com
<ul></ul><p>I'm not sure I agree with adding <code>to_proc</code> to <code>Class</code> instances, since it seems questionable that <code>#new</code> is what you'd always want to be called. Dodging that debate for now, there is another way to get the result you seek:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Foo</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="vi">@i</span> <span class="o">=</span> <span class="n">i</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">50</span><span class="p">).</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="no">Foo</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:new</span><span class="p">))</span>
</code></pre>
<p>This is both more explicit and less magic. If there were syntax added to get method objects (without calling <code>#method</code>) it would be even cleaner.</p> Ruby master - Feature #4910: Classes as factorieshttps://bugs.ruby-lang.org/issues/4910?journal_id=181942011-06-24T00:25:57Zrklemme (Robert Klemme)shortcutter@googlemail.com
<ul></ul><p>Charles Nutter wrote:</p>
<blockquote>
<p>I'm not sure I agree with adding <code>to_proc</code> to <code>Class</code> instances, since it seems questionable that <code>#new</code> is what you'd always want to be called.</p>
</blockquote>
<p>Hmm, but what else? I think it is a reasonable default.</p>
<blockquote>
<p>Dodging that debate for now, there is another way to get the result you seek:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Foo</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="vi">@i</span> <span class="o">=</span> <span class="n">i</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">50</span><span class="p">).</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="no">Foo</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:new</span><span class="p">))</span>
</code></pre>
<p>This is both more explicit and less magic. If there were syntax added to get method objects (without calling <code>#method</code>) it would be even cleaner.</p>
</blockquote>
<p>That's true. Though in absence of that syntax I prefer <code>(1..50).map {|i| Foo.new i}</code> over your solution as it is equally explicit and even less magic - could even be shorter to type. :-) Actually only <code>(1..50).map(&Foo)</code> would be an alternative I would consider.</p>
<p>Cheers</p> Ruby master - Feature #4910: Classes as factorieshttps://bugs.ruby-lang.org/issues/4910?journal_id=251382012-03-25T16:28:41Zmame (Yusuke Endoh)mame@ruby-lang.org
<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> Ruby master - Feature #4910: Classes as factorieshttps://bugs.ruby-lang.org/issues/4910?journal_id=332412012-11-20T21:41:14Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul><li><strong>Target version</strong> set to <i>2.6</i></li></ul> Ruby master - Feature #4910: Classes as factorieshttps://bugs.ruby-lang.org/issues/4910?journal_id=686922017-12-25T18:15:00Znaruse (Yui NARUSE)naruse@airemix.jp
<ul><li><strong>Target version</strong> deleted (<del><i>2.6</i></del>)</li></ul> Ruby master - Feature #4910: Classes as factorieshttps://bugs.ruby-lang.org/issues/4910?journal_id=704852018-02-20T08:50:18Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<ul><li><strong>Description</strong> updated (<a title="View differences" href="/journals/70485/diff?detail_id=48352">diff</a>)</li></ul> Ruby master - Feature #4910: Classes as factorieshttps://bugs.ruby-lang.org/issues/4910?journal_id=705122018-02-21T05:13:25Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul><li><strong>Related to</strong> <i><a class="issue tracker-2 status-6 priority-4 priority-default closed" href="/issues/14498">Feature #14498</a>: Class#to_proc</i> added</li></ul> Ruby master - Feature #4910: Classes as factorieshttps://bugs.ruby-lang.org/issues/4910?journal_id=705142018-02-21T05:14:01Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul><li><strong>Status</strong> changed from <i>Assigned</i> to <i>Rejected</i></li></ul><p>It can lead to unreadable code.</p>
<p>Matz.</p>