Re: Thinking Aloud: Refactoring from nested loops to enumerators and lambda's
Robert Klemme <[email protected]> Tue, 2 Jul 2019 18:46:58 +0200
| Newsgroups | gmane.comp.lang.ruby.general |
|---|---|
| Message-ID | <CAM9pMnNF+QXWm9Jek2dHenB6-NNqOszTKjRPZEMi00Z0oKJFEA@mail.gmail.com> |
On Mon, Jul 1, 2019 at 6:13 AM John Carter <[email protected]> wrote: > So I'm just thinking out aloud here. > > Being an Old School Programmer I tend to naturally to write ever more > deeply nested loops. > > I hate myself when I do this because it’s hard to test especially if > some of the loops have nasty external side effects, it’s hard to > reuse, it’s hard to refactor. > > So I’m trying two new patterns.... > > * Passing enumerators as parameters so I can pull out inner loops as > standalone functions without calling the entire function every time.. > > * Creating functions that return lambdas, so I can pass an inner loop > in as a parameter. > > Walk with me this is going to be long…. the example is a teaching > example / dojo exercise for myself, so excuse me it it slightly > contrived. > > (In the following, a line of ===== indicates the next, slightly > different version of the code) > > ========================================== > > Here is a typical chunk of my code… > > def nested( a, b, c) > > stuff_a = func_a(a) > stuff_b = func_b(b) > stuff_c = func_c(c) > result = {} > func_1( stuff_a) do |a1| > stuff_d = func_d( a1 + stuff_b) > func_2( stuff_d) do |a2| > stuff_e = func_e( a2 + stuff_c) > > func_3( stuff_e) do |a3| > > result[a3] = func_f( a3) > end > end > end > > result > end > I mulled a bit about this and here are a few unsorted and incomplete thoughts: * The pattern implies that func_1, func_2 and func_3 do an iteration internally. Why not extract the Enumerable directly and use that to make the iteration more visible? Alternatively, if these function filter you could write a getter that returns an Enumerator. * Why not just put the logic of the iteration and body in classes of stuff_a, stuff_d and stuff_e? * func_d and func_e might be better off having two arguments and doing addition internally. * I think I really agree to Brandon: without a more real example and without knowledge what all the methods actually do it is extremely difficult to come up with good suggestions. > It’s fairly clear but has a few gotchas. > > * It’s unclear which part of the code actually depends on which parameters. > * In this toy example, the function is small… but a Real Life nested > loop function like this can quickly grow hideously large. > But that is an issue in itself that points to issues with the design of the data structures or logic. > * As a “premature optimization” I have factored out subexpressions > that do not alter within the loops, resulting in large scopes for > variables that are only used inside the loops. > The method in this example is pretty short so I do not see an issue with that. In other cases that problem automatically goes away if you distribute the logic properly across multiple methods / functions. > * func_1(), func_2(), func_3() yield a stream of things….but a stream > of things should just be an enumerable! > Exactly, see above. Kind regards robert Unsubscribe: <mailto:[email protected]?subject=unsubscribe> <http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>