Splat is good for you

| | Comments (2)
A recent post on projectionist shows two code examples:
  def foo(*args)
    [args].flatten.map do |arg|
      # ...
    end
  end

  def foo(*args)
    Array(args).map do |arg|
      # ...
    end
  end
and argues their (ugly) necessity. I think both examples fail to hit the mark (or there is a typo?) as they've ensured the initial codition simply by using *args. Allowing them to state the problem in a straightforward fashion:
  def foo(*args)
    args.flatten.map do |arg| # if you are trying to combine a bunch of arrays
      # ...
    end
  end

  def foo(*args)
    args.map do |arg|
      # ...
    end
  end
which, is much more natural. If I had to guess, I'd say they meant to not put the splat in front of args. I find using splat to be a better fit.

2 Comments

Thanks for your feedback Ryan. I hadn't realize that splat's behavior covered all the desired cases. The class coercion methods are really ugly so I'm glad to avoid them with your proposed approach.

I've just remembered what the issue actually is. The problem was mistated in the over simplified example I used.

When passing an options hash in which a given option may have one or more value, which you eventually just want to iterate over, you have to always end up with a non-nested collection to iterate over even if only one value is passed.

Possible invocations include:

foo :bar => :baz

or

foo :bar => [:baz, :quux]

The incorrect approach I was seeing was:

def foo(options = {} [options[:bar]].flatten.map # ... # ... end end

When it could be better expressed as:

def foo(options = {}) [*options[:bar]].map # ... # ... end end

Leave a comment