On Apr 30, 2008, at 14:00 PM, Joe K wrote:
document
the ‘types’, seeing no purpose to restrict your definition of what’s
considered valid input. Surely if the object responds in all the
ways you
ask it to, it’s fit for the task?
Maybe I’m not in the correct mindset of dynamic programming. I’ve
always
found it difficult to remember return values/parameter-types (i.e.
classes)
for a large number of methods.
I find I have this problem less the more readable (as English) my code
is.
Compare:
h = Hash.new 0
ARGF.each_line do |l|
h[l] += 1
end
puts h.sort_by { |k,v| v }.first(10).map { |k,v| “#{v}\t#{k}” }
With:
counts = Hash.new 0
ARGF.each_line do |line|
counts[line] += 1
end
top = counts.sort_by { |_, count| count }.first 10
puts top.map { |line, count| “#{count}\t#{line}” }
In the first example looking at any individual call or expression
doesn’t tell you anything about any of the surrounding code. You have
to trace back and follow types around to understand it.
In the second example, the types are objects. If you look at just the
last line, you can understand what I intend without reading any of the
preceding lines.
Most of the expressiveness of the code sample above comes from Ruby’s
expressive and consistent core library, more so that choosing good
names. Unfortunately there are libraries that do not share the
consistency of the core library.
Don’t get me wrong, I would much rather use
Ruby at work than Java, but with a good IDE, Java’s entire API is
available
in pop-up windows AS YOU TYPE. While developing in ruby, I have
several
rdoc’s open in my web browser, files open in several terminal
windows, and
an IRB session open, all for reference purposes when I’m working with
unfamiliar APIs.
If an API is unfamiliar to me I’ll use gem server or ri for hints, but
once it becomes familiar I usually don’t need it anymore. If I always
have to refer to API documentation, it’s a sign of a poor API.
Surely if the object responds in all the ways you ask it to, it’s
fit for the task?
Consider the common case of something like DataStructure#remove().
Does
remove take an index or the object to be removed? Usually the API
developer
supports one use case or another but not both. You should not have
to read
the code to figure out which it is.
That API developer should be beaten with a stick. Matz programmed my
brain to expect this as the way to remove elements from a data
structure by object:
$ ri Hash#delete
------------------------------------------------------------ Hash#delete
hsh.delete(key) => value
$ ri Array#delete
----------------------------------------------------------- Array#delete
array.delete(obj) -> obj or nil
And this as the way to remove elements from a data structure by index:
$ ri Array#delete_at
-------------------------------------------------------- Array#delete_at
array.delete_at(index) -> obj or nil
I realize this was just an example, but APIs for third-party packages
should exclusively follow the core library’s examples. This makes it
easier for everyone to write code that they expect to work.
(When wrapping, say libxml, tk, etc., it is ok to exclusively follow
the wrapped library’s examples. Mixing is always bad.)