According to irb, >> StringIO.is_a?(IO) => false This seems illogical to me. Is this intentional? If so, why?
on 2007-10-12 20:06
on 2007-10-12 20:16
On 10/12/07, Hongli Lai <h.lai@chello.nl> wrote: > According to irb, > > >> StringIO.is_a?(IO) > => false > > This seems illogical to me. Is this intentional? If so, why? 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. Eric
on 2007-10-12 20:19
On 10/12/07, Hongli Lai <h.lai@chello.nl> wrote: > According to irb, > > >> StringIO.is_a?(IO) > => false > > This seems illogical to me. Is this intentional? If so, why? BTW, I asked this same question when I found StringIO. The answer enlightened me to the beauty of duck-typing.
on 2007-10-12 20:38
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.
on 2007-10-12 21:02
> > >> StringIO.is_a?(IO) > 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. This is actually the one case where duck typing burned me. In the spreadsheet library I was using IO#fileno, so that users could pass their own IO objects if they wanted. Well, it turned out some people were trying to stream the results to their web browsers using StringIO. Does StringIO respond to fileno? Yes. Does it work? No. It returns nil. Just thought I'd share that little anecdote with y'all. :) Regards, Dan This communication is the property of Qwest and may contain confidential or privileged information. Unauthorized use of this communication is strictly prohibited and may be unlawful. If you have received this communication in error, please immediately notify the sender by reply e-mail and destroy all copies of the communication and any attachments.
on 2007-10-12 21:10
On Oct 12, 2007, at 11:37 AM, Hongli Lai wrote: > a filename string) or to an IO object. So my code first checks > 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
on 2007-10-12 21:14
On Sat, Oct 13, 2007 at 03:37:36AM +0900, Hongli Lai wrote: > 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 So does RexML. You see same symptoms when you use open-uri, and then try to pass the returned "not quite IO" object to RexML. Its unfortunate the std libs aren't a better example of duck-typing. Search around, I think _why and a few other blogs have talked about how difficult it is to do streaming decoding of XML coming over HTTP with RexML because of this. I think the idiomatic ruby way would be for objects that are "like" an IO object to implement #to_io(), so libs could check for #to_io(). This would be analogous to #to_str(), etc. Sam
on 2007-10-12 21:17
On 10/12/07, Hongli Lai <h.lai@chello.nl> wrote: > filename string) or to an IO object. So my code first checks whether > output.is_a?(IO), which is not the case. I suggest that you either use another way to figure out how you should treat an argument (like number of arguments or a flag) or don't use "multi-methods" (split the single method into multiple so that you don't have to look at the "type" to determine what to do). Multi-methods really aren't a good thing in ruby and clash with the concept of duck-typing. > 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. It sounds like it has the same problem that your code does. If you don't do duck-typing you'll restrict flexibility. > 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. IO is a class. You can't include a class. Even if you could, you wouldn't want StringIO to have all of the data-structures needed to implement IO. To get what you want, you'd really IO to be based on an abstract class that had no implementation (like Fixnum and Bignum are based on Integer which has not implementation to be used directly). Again, your best bet is to just steer clear of #is_a?, #respond_to?, etc. If you want these to make multi-methods, just say no - use multiple methods instead. Of course the ruby core itself doesn't follow the duck typing philosophy all the time (actually most of the time it doesn't). Take Regexp for example. Regexp is completely tied to String. You can't make something that looks like a String (like say the opposite of StringIO - an IOString, or a rope - tree structure for a string) and have it work with Regexp.
on 2007-10-12 23:11
On 12/10/2007, Eric Mahurin <eric.mahurin@gmail.com> wrote: > > 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. > > I suggest that you either use another way to figure out how you should > treat an argument (like number of arguments or a flag) or don't use > "multi-methods" (split the single method into multiple so that you > don't have to look at the "type" to determine what to do). > Multi-methods really aren't a good thing in ruby and clash with the > concept of duck-typing. > I also hit this particular case. The question "Is it an IO or a filename?" can be solved by detecting the read/write method that would be used to get/store the data. If it's not there you can try and use the object as filename. But in general writing methods that do different things depending on the kind of data they receive is quite hard in ruby. Thanks Michal
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.