bob.age = 32 bob.age = Duck.new
Though he warns that this is just a "coffee-break implementation", the actual code is remarkably simple as well. I consider this to be a hallmark of Dave’s.
As anyone in the dynamic programming languages world knows, "type checking"(1) is a touchy and usually unproductive subject (RubyTypesAndClasses). The common complaint is that, without "type" information for method parameters, code is hard to understand and maintain. I don’t generally find this to be true for myself, but I can see and understand that sometimes it would be helpful to have some hints as to what kinds of objects a library author passes into certain method calls.
The simplest solution to this—which wouldn’t require a compromise of the design philosophy of the language—would be for all library authors to simply document their code, giving their users a hint as to what each method expects. We’ve all heard that one before. Even those of us with the best intentions do, on average, a poor job documenting our own code. Additionally, what’s obvious to me may not be obvious to you. So as a library author, I will probably either overdocument (waste my own time and clutter the code) or underdocument.
Taking a cue from Dave, I did my own coffee-break implementation(2) of a hack that would auto-document the class of parameters for a given set of methods. It’s implemented as a modification to rdoc. The idea is that you can "instrument" your code temporarily, run through a typical usage of it, and have Ruby keep track of—and save—class information for the method parameters of specified classes.
I’ve written a servlet (which I’ll talk about in more detail in a later post) that I would like to document via rdoc. Assuming the servlet is called "ContinuationServlet", I can auto-generate parameter class hints for this servlet by adding the following to my code:
require 'class_hints' wrap_methods(ContinuationServlet) ... (invoke webrick normally here) ... File.open("seasidehints.out", "w") do |file| file.write(Marshal::dump(Kernel::METHOD_PARAM_HINTS)) end
This will install a wrapper around every method of ContinuationServlet, which will save class information for each parameter in the nested hash, Kernel::METHOD_PARAM_HINTS. After having clicked around through the application with a web browser, we just dump this to disk as a marshalled Ruby object.
Next, we feed this hash to rdoc when we document:
rdoc --param-hint-file=seasidehints.out pm_seaside.rb
You can see the output here. For the lazy, documented methods now look something like this:
Full code listing:
Like Dave, I’m just throwing this up here for comment. I’m not sure anyone will find it useful, and the implementation is definitely a hack. But, it seems like something +like this+ might help to quiet some of the complaints that half the population seems to have about dynamically typed languages. And, for example, could FreeRIDE use a trick like this to provide intellisense-like hints in the IDE?
(1) The word "type" is frequently misused in the Ruby world to mean "class". Matz actually deprecated the #type message on Object to clarify that a Ruby object’s "type" is more focused on its capabilities than its class. Class is little more than a convenience mechanism.
(2) It was a pretty long coffee break :)