From: Evan Phoenix Date: 2007-10-13T04:08:11+09:00 Subject: Re: StringIO is not IO? On Oct 12, 2007, at 11:37 AM, Hongli Lai wrote: > Eric Mahurin wrote: >> Since StringIO doesn't use IO to base its implementation, it is >> not an IO. >> Why does it matter? If you use standard duck typing, it shouldn't. >> Class hierarchy doesn't matter with duck typing. Classes are just an >> implementation detail with duck typing. You are best off not looking >> #is_a?, #respond_to?, etc. Just assume the object can do the methods >> you'll be using and use. > > Well, some of my code can write its output to a file (specified by > a filename string) or to an IO object. So my code first checks > whether output.is_a?(IO), which is not the case. > > RMagick seems to do the same thing. I tried making RMagick write > its output to a StringIO, but that failed because it thought it > isn't an IO object. I spent quite some time on debugging these two > problems, and I guess that am not the first one. > > Finally, when one thinks about it logically, StringIO *should* be > an IO. There's even the word 'IO' in its class name. So why not do > an 'include IO' in StringIO? That would solve a lot of problems and > make the class hierarchy more logical. > StringIO is not a subclass of IO because it doesn't share anything with IO implementation wise. It simply provides the same interface as IO does. It's a technical problem for having it be a subclass as all IO objects have some kind of backing with the OS. What would the backing object with the OS be for StringIO? With every other IO object, on unices, it's a file descriptor. Lowlevel things in ruby that take an IO object (select, etc) do so because the require the ability to extract this backing object from the IO object and hand it to the OS. As for including IO, well you can't include a Class. If you want something akin to this check, create a module, say called IOLike. Include it in IO and StringIO, then do output.kind_of?(IOLike). Better would be to test for the interface you want, rather than the type though. So in your case, output.respond_to?(:write). - Evan Phoenix