--20cf307c9f28455ee104b25bd8a0
Content-Type: text/plain; charset=ISO-8859-1

I am nervous about list comprehensions because in almost all cases, when
you do something in Ruby, you do it by invoking a named method on an
object. It is clear by looking at a piece of code which named method will
be invoked. In Ruby 1.9, it is even trivial to learn the exact source
location of such a named method.

In contrast, list comprehensions introduce new syntax that invokes some
invisible protocol; understanding which methods are involved requires
figuring out where to look in the documentation.

Python uses protocols like this for *everything*, so list comprehensions
fit in well there. The only Ruby case I can think of that works like this
is the much maligned for/in syntax, which invokes #each under the hood.
Most people I know find this strange, I suspect because of its
inconsistency with the very strong rule that if a method is directly
invoked by some syntax, you can see it.

If you want to see where this protocol-oriented path leads us, check out
http://docs.python.org/reference/datamodel.html#special-method-names. I
much prefer Ruby's "if you want to do something, invoke a named method"
principle of uniform access[1].

[1] http://en.wikipedia.org/wiki/Uniform_access_principle

Yehuda Katz
(ph) 718.877.1325


On Tue, Nov 22, 2011 at 2:26 PM, Shugo Maeda <shugo / ruby-lang.org> wrote:

> Hi,
>
> 2011/11/23 Yehuda Katz <wycats / gmail.com>:
> > It is pretty common to want to map over an Enumerable, but only include
> the elements that match a particular filter. A common idiom is:
> >
> > enum.map { |i| i + 1 if i.even? }.compact
> >
> > It is of course also possible to do this with two calls:
> >
> > enum.select { |i| i.even? }.map { |i| i + 1 }
> >
> > Both cases are clumsy and require two iterations through the loop. I'd
> like to propose a combined method:
> >
> > enum.map_select { |i| i + 1 if i.even? }
> >
> > The only caveat is that it would be impossible to intentionally return
> nil here; suggestions welcome. The naming is also a strawman; feel free to
> propose something better.
>
> How about to add list comprehensions or Scala's for expressions instead?
> For example, enum.select { |i| i.even? }.map { |i| i + 1 } can be
> written as follows:
>
>  [ i + 1 for i in enum if i.even? ]
>
> # The syntax of list comprehensions needs more considerations.
>
> One benefit is that nested maps can be flattened by list comprehensions.
> For example, the following code:
>
>  pyths   [x, y, z] for z in [1..Float::INFINITY].defer
>                          x in [1..z].defer
>                          y in [x..z].defer
>                          if x**2 + y**2 z**2 ]
>  p pyths.take(3)
>
> is equivalent to the following code:
>
>  pyths  1..Float::INFINITY).defer.flat_map {|z|
>    (1..z).defer.flat_map {|x|
>      (x..z).defer.select {|y|
>        x**2 + y**2 z**2
>      }.map {|y|
>        [x, y, z]
>      }
>    }
>  }
>  p pyths.take(3)
>
> # Enumerable#defer is proposed in Feature #4890.
>
> BTW, now Ruby has map and reduce as aliases of collect and inject,
> but not filter as an alias of select.  Why not?
>
> --
> Shugo Maeda
>
>

--20cf307c9f28455ee104b25bd8a0
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

I am nervous about list comprehensions because in almost all cases, when you do something in Ruby, you do it by invoking a named method on an object. It is clear by looking at a piece of code which named method will be invoked. In Ruby 1.9, it is even trivial to learn the exact source location of such a named method.<div>

<br></div><div>In contrast, list comprehensions introduce new syntax that invokes some invisible protocol; understanding which methods are involved requires figuring out where to look in the documentation.</div><div><br>
</div>
<div>Python uses protocols like this for *everything*, so list comprehensions fit in well there. The only Ruby case I can think of that works like this is the much maligned for/in syntax, which invokes #each under the hood. Most people I know find this strange, I suspect because of its inconsistencyith the very strong rule that if a method is directly invoked by some syntax, you can see it.</div>

<div><br></div><div>If you want to see where this protocol-oriented path leads us, check outa href="http://docs.python.org/reference/datamodel.html#special-method-names">http://docs.python.org/reference/datamodel.html#special-method-names</a>. I much prefer Ruby&#39;s &quot;if you want to do something, invoke a named method&quot; principle of uniform access[1].</div>

<div><br></div><div>[1]a href="http://en.wikipedia.org/wiki/Uniform_access_principle">http://en.wikipedia.org/wiki/Uniform_access_principle</a></div><div><br clear="all">Yehuda Katz<br>(ph) 718.877.1325<br>
<br><br><div class="gmail_quote">On Tue, Nov 22, 2011 at 2:26 PM, Shugo Maeda <span dir="ltr">&lt;shugo / ruby-lang.org&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

Hi,<br>
<br>
2011/11/23 Yehuda Katz &lt;wycats / gmail.com&gt;:<br>
<div class="im">&gt; It is pretty common to want to map over an Enumerable, but only include the elements that match a particular filter. A common idiom is:<br>
&gt;<br>
&gt; enum.map { |i| i + 1 if i.even? }.compact<br>
&gt;<br>
&gt; It is of course also possible to do this with two calls:<br>
&gt;<br>
&gt; enum.select { |i| i.even? }.map { |i| i + 1 }<br>
&gt;<br>
&gt; Both cases are clumsy and require two iterations through the loop. I&#39;d like to propose a combined method:<br>
&gt;<br>
&gt; enum.map_select { |i| i + 1 if i.even? }<br>
&gt;<br>
&gt; The only caveat is that it would be impossible to intentionally returnil here; suggestions welcome. The naming is also a strawman; feel free toropose something better.<br>
<br>
</div>How about to add list comprehensions or Scala&#39;s for expressions instead?<br>
For example, enum.select { |i| i.even? }.map { |i| i + 1 } can be<br>
written as follows:<br>
<br>
      ݼ<br>
# The syntax of list comprehensions needs more considerations.<br>
<br>
One benefit is that nested maps can be flattened by list comprehensions.<br>
For example, the following code:<br>
<br>
      ۱ݮ
    ۱ݮ
    ݮ
      ݼ   娳<br>
is equivalent to the following code:<br>
<br>
   ٩
 1..z).defer.flat_map {|x|<br>
 x..z).defer.select {|y|<br>
  ª  
  ® 
    ݼ
  ¼
  ¼
  ¼
   娳<br>
# Enumerable#defer is proposed in Feature #4890.<br>
<br>
BTW, now Ruby has map and reduce as aliases of collect and inject,<br>
but not filter as an alias of select.   
<span class="HOEnZb"><font color="#888888"><br>
--<br>
Shugo Maeda<br>
<br>
</font></span></blockquote></div><br></div>

--20cf307c9f28455ee104b25bd8a0--