Re: Thinking Aloud: Refactoring from nested loops to enumerators and lambda's

Robert Klemme <[email protected]> Tue, 2 Jul 2019 18:28:10 +0200
Newsgroups gmane.comp.lang.ruby.general
Message-ID <CAM9pMnOEuKfpTOAdsAXmi51GyWYaQk4crvb7oxav3-DvdprF=g@mail.gmail.com>
On Mon, Jul 1, 2019 at 9:44 AM Andy Jones <[email protected]>
wrote:

> I tend to think of loops -- at least loops with blocks -- as a code smell.
>

Why?


> So the first step for me is to make the body of each of those loops a
> function.


Do you mean this?

foo.each do |item|
  puts item
  # more
end

becomes

def nest(item)
  puts item
  # more
end

...

foo.each(&:nest)

or - more conventionally

foo.each {|item| nest(item)}

I would not do that as a general rule because now you distribute the logic
in two places which makes it more cumbersome to read. If the same logic is
used in different places then this might make sense (reuse).

Fun nitpick: technically a block is a function - albeit an anonymous one.
:-)


> After that, if you are finding that there are too many parameters being
> passed around, then that might be an indication that you the design is not
> optimal (only _might_).  For example, perhaps you could use a helper class
> that carries some of those parameters as persistent state.
>

I agree, it might indicate an issue how state and logic are distributed
across classes and methods.


> Then, too, if your loops have external side effects, that's another line
> of attack.  I kind of want each of my functions to have an external effect,
> or return a value, but definitely not both.
>

Sounds good - but I want to mull a bit more about this. The issue I have is
more a formal one: I have come to learn that strict rules are easily
phrased but usually sooner or later you hit an aspect of reality where you
either have to weaken the rule (e.g. allow exceptions) or bend to code in
"amazing" ways to adhere to the strict rule. Reality is so full of
surprises and we all love a simple rule - only more often than not they are
not compatible in my experience.

Of course
> ```
> Result = []
> func_x( stuff) do |a|
>   result << func_y( a)
> end
> result
> ```
>
> Is really `func_x(stuff).map(&:func_y)`, so there's that, too.
>

Another good point. #inject could also be used here.

Kind regards

robert

-- 
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can -
without end}
http://blog.rubybestpractices.com/


Unsubscribe: <mailto:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>