Concept overloading madness

May 09, 2007 14:30

I recently had cause to go delving into the documentation for Ruby's open() method. While I found the information I needed fairly quickly, I was appalled to discover that open() will happily open a pipe to a subprocess (if the path parameter starts with "|") and even fork your app (if the path parameter is "|-").

Perhaps I'm old fashioned and don't belong in the world of modern (and not-so-modern -- apparently Perl does this too) interpreted languages. The way I see it, open() should open a file. popen() lets you fork a subprocess. fork() should be there to let you fork. If I'm opening a user-provided filename, I don't want to have to worry about checking the filename for a bunch of magic characters that completely change the behaviour. If you require 'open-uri' you also get to open arbitrary URIs as if they were files. (This isn't as bad -- at least you need to explicitly require it. Unless one of the libraries you use does that behind the scenes.)

This "open anything that could possibly return a file-like object" idea is also a very leaky abstraction. Consider error conditions. Opening a local file will never die with "connection reset by peer" or "DNS lookup failed". However, the programmer now has to either deal with these or ensure that he never lets a non-local path slip through to open(). The alternative is to mask all these errors and return something generic. This is worse, since now the programmer can't behave differently on timeouts and missing files.

I can see the utility in having a method that will open anything you can throw at it. However, this should be explicit, such as open_anything() and perhaps a little more configurable. Perhaps it could check the path against a series of regexen and dispatch to lower level open_something() methods. Perhaps it could take a list of exception handlers to apply by default. At any rate, it certainly shouldn't fork.

programming

Previous post Next post
Up