top | item 45764104

(no title)

tangus | 4 months ago

Looping in Ruby is the opposite of awful. You only have to define an `#each` method in your class and include the `Enumerable` module, and you get a plethora of composable methods to iterate and accumulate in every which way. I find it nothing short of brilliant.

discuss

order

bjoli|4 months ago

Yet, iterating over several collections and accumulating values is awkward.

It is not that it is easy to implement the iteration protocol, it is that the construct for looping universally sucks. Even the awful loop macro from common lisp runs laps around most other facilities. Racket's is even less powerful, but is miles better than what python offers.

Ruby can do some destructuring, but not enough to actually be useful.

tangus|4 months ago

It may be somewhat awkward; zipping collections to iterate over them in unison makes the first one (the sender) seem special, while it not necessarily is. And accumulating more than one value isn't always straightforward; you usually have to reduce explicitly. But it's so much better in the general case!

Like the example you showcase your macro with. In Ruby it would be:

    lst = [[1, 2], :dud, [3, 4], [5, 6]]
    lst.grep(Array).flatten.sum
    => 21
You can see what it does at a glance, you don't have to immerse yourself inside the directives to follow the logic. And when you can't do that, declaring iterators and accumulators outside a loop and then iterating and accumulating "by hand" yields code not so different than your more complex examples.

  def partition (arr)
    yes = []
    no = []
    arr.each do |elt|
      if yield elt
        yes << elt
      else
        no << elt
      end
    end
    [yes, no]
  end