Hacker News new | ask | show | jobs
by lg 5933 days ago
Would you prefer a *rest argument? An options hash is the best way to make your ruby API flexible.
1 comments

Plain old objects are the best way to make your API design flexible. You can't easily change the behavior of setting a key/value pair for an individual hash. Objects are designed to implement behavior, Hashs are meant to hold key value pairs.
Right, the keys/values need to have supporting logic. And yeah if you're sticking procs in a hash, just use an object; but if your object is just a bunch of fields, use a hash. And often that's all you need. I just want to override the marginWidth on this fooBar.

Remember you don't need to destructure the hash. You've got a local one initialized to sensible defaults, and you .merge! it with the param one, and then just use the hash values as your local vars.

If your object is a bunch of fields, you should still use an object. It might need behavior later.

I think the central issue is that there is too much friction to creating new classes in Ruby. It feels official and final. In Io, you just clone an existing object like you would send any other message.

There's also an embrace of YAGNI and "Do the simplest thing possible ..."

I'd rather start with a hash and then see if it later demands more, than start inventing objects that, based on existing use cases, need only be hashes or structs.

I'd also rather go through a number of pre-1.0 iterations to get real-world usage to shake out the painful API parts. Up until then I'm happy to break compatibility if experience says there's some bad code in there.

Monkeybars, for example, had some methods that began life using positional args, but they were changed to use hash values. I hated it.

Aside from the extra typing required for every call, with positional args I got used to reading code and seeing things in a fixed order, so when I had to use the method myself I knew exactly what needed to go where. (These methods had 2 arguments, with maybe an optional third or so.)

With the hash args the order could vary so I had to keep looking up what the possible argument key values could be.

(Thing about using hashes for args: with positional arguments you need only know what role an argument is playing in order to know what sort of value to pass in, but with a hash you have to know the exact key name. That ends up being more stuff to look up in the docs, especially if the API designer has a quirky way of naming things.)

You might think that at least for a code reader the use of hash keys would better document the call, but the method name and the names of items being passed in were almost always sufficient.

I suspect this particular change was a result of over-thinking these methods and expected usage instead of actually paying attention to what the code was doing right now, and how people were using it right now.

There are times when my gut tells me, "You know what's going to happen with this code later", and I try to take that into consideration, but (usually) simple wins for me.

With the hash args the order could vary so I had to keep looking up what the possible argument key values could be.

You can set slots on objects in any order that you want to:

    Foo.new.set_x(x).set_z(z) ...
That is insanely ugly. I will pass, thanks.
Can you recommend an Io book for me? I want to hunt down the author and try to encourage them to make their code more Rubyish. Because you know, that's helpful.
The book is opensource, why not submit a <strike>patch</strike> pull request. :)
In all seriousness, all it takes is some code examples that make me and a few others say "whoa, cool" and it'll make its way in.

If RBP becomes "Gregory Brown's Best Practices", it'll be epic fail. I am encouraging folks to prove whatever they can wrong in this book.