Jean Michel <jmichel / schur.institut.math.jussieu.fr> wrote: >Kevin Smith <sent / qualitycode.com> wrote: >>Since Ruby is dynamically typed, Strings and >>Files can behave the same (and thus be >>interchangable) even if they do not inherit from >>each other. >> >>For eample: >> >> stream.each_line do >> | line | >> puts ">" + line >> end >> >>This will work whether stream is a File or a >>String. If there are other operations that you >>would like String to support (like lineno or >>seek) you would just have to create a subclass of >>String that implements those methods. >I do not think this solves my problem. I will give the specific example >where I had the problem to show it: I have as an exercise written a >program to get an ID3V2 tag from a .mp3 file. I have defined a class >ID3V2tag and a method read_ID3V2tag in class IO which returns a new >object of class ID3V2tag (or nil if no such tag was found in the file). > > Now, I want to re-use my code to parse an ID3V3 tag sitting in a string >in memory. In C++, I can just make the string into an istringstream and >share the same code. I don't see how I can share the code between both >situations in ruby (of course there would be a way: put the code in >class String and read the file in memory; but this is not desirable with >multi-megabyte files!). It seems that I need a class in which both >strings and files can belong, but I cannot do it since neither String >nor IO is a module. What did I miss here? I think you haven't adequately explained to the Ruby developers what it is that you really want. What is missing from the discussion is a description of the specific API that is to be shared and what amount of code resuse one has in mind. In C++, there are really three kinds of code reuse: literal (object code) reuse -- via inheritance, semi-literal reuse -- via inheritance plus redefined virtual functions, and generic reuse of algorithms plus names -- via templates (freely generates different object code for different types). The C++ library code for iostreams is really the second type above, but the overriden virtual functions are hidden away from the programmer (underneath the covers, every iostream is basically a strstream with different virtual methods for what to do when the char or wchar buffer needs to be filled or emptied; obviously be shared; it's a great paradigm, because the code for serializing to and from this buffer can be shared and building strings out of character sequences can be literally shared. In Ruby, every method is dynamically dispatched, redefinable, looked up by name, and has weakly typed arguments, so the three types of reuse essentially collapse to one. But the fact that methods are weakly typed, doesn't mean that suitable implementations for each type are conjured from thin air, nor does it mean that every interesting point for customization inside of an interface has been exposed. All of that is really just to say that this a library issue and not a language issue. In this case, the methods for the Marshal module are pretty opaque, but it seems likely that you could define _dump and _load for your ID3V2tag class and achieve a suitable kind of code reuse through the fact that Marshal can work on IO objects and strings (at least that is my theoretical understanding based on the documentation). -= Josh