Subject: Re: [scala-user] for-loop vs for-yield loop?


On 2012-02-21 10:40 AM, Haoyi Li wrote:
I would say the semantics are pretty simple:

for(...){...} -> foreach
x = for(...){...} -> map

As a relative Scala neophyte I actually find this pretty easy to understand and tidier that needing 'yield' - but I am not language designer nor a compiler implementer, and I did not want to say anything earlier. Now that I see things stated this way it seems pretty simple to me. Am I missing something subtle?

If the compiler knows there is no result needed from the 'for(...){...}' then it knows it does not need to build a result and can optimize out that step.

Presumably if I were to say foo(for(...){...}) the compiler would go to the effort of trying to build a result.

Anyway, that's just my simple opinion.

On the other hand, I just rarely find myself using for(...){...} in Scala whereas I constantly use it in Java.


Especially considering in the status quo case, there are actually 4 different operations

for(...){...} -> foreach
x = for(...) yield {...} -> map
x = for(...){...} <- who ever does this?
for(...) yield {...} <- throwing away the list immediately; nobody does this either, even if it does the same thing

Apart from that, how different are an eager map and foreach? For example, in Python they are similar enough Dropbox apparently replaced all their inner loops with map() calls:

http://ontwik.com/python/pycon-2011-how-dropbox-did-it-and-how-python-helped/ at 22:45

I think cutting out:

- one language feature
- one keyword
- reduced verbosity (for for-comprehensions)
- removal of two unwanted constructs:

counts as simpler, especially since the expressiveness is the same!

I understand the fact that with-yield case maps to map() and no-yield case maps to foreach() is quite nice and elegant. However, I would argue that that is an implementation detail.

Unless there is some fundamental difference between map() and foreach() apart from the aggregation of a list, if you throw away the list, both are then exactly the same. The fact that there could be a transient list is then purely a performance detail, in no way affecting the semantics (meaning as "what it actually does", not "what function it maps to").

How clever the type-inferencer can be at optimizing away the unwanted lists then becomes, again, a performance detail. Remember this only applies to trailing performance-critical for-loops in implied-return-type function, which is a small fraction of all loops, and those can be (trivially) manually optimized anyway with a trailing () or by declaring the return type.

-Haoyi

On Tue, Feb 21, 2012 at 12:39 PM, rkuhn <google@xxxxxxxxxx <mailto:google@xxxxxxxxxx>> wrote:

One other aspect: how long will it take to explain what the
semantics are in both cases?

yield -> map
no yield -> foreach

whereas your proposal involves explaining all about type
inference, which is not even rigorously specified (okay, that
might not matter here). I prefer the simpler model anytime,
especially since the expressiveness is the same.

Regards,

Roland


(C)2011 mailinglist-archive.com