Mathieu Bouchard <matju / sympatico.ca> writes: Mathieu> Replying to all of you at once: [package versioning using a vanilla version file] I like this. Mathieu> On Fri, 11 May 2001, Sean Russell wrote: >> What do you think about a version which allows for intelligent >> loading, so that multiple versions of a module/library can exist >> on a platform at once? For example: [...] Where getAllVersions >> finds all files in the search path by the name >> #{file}(_(\d+(\.\d+)*))?\.rb, in order of the version numers. >> Ergo, we'll always get the newest compatible version of the >> library. Mathieu> This is a good idea; not sure how the particular Mathieu> implementation should work though: may involve one directory Mathieu> per package, if we don't want renaming files... However, a Mathieu> program that (indirectly) require several different versions Mathieu> of the same file or package would still not work, but I'm Mathieu> not sure something can be done about it. Hmm. I'm not sure anything too sensible can be done about that, either. Mathieu> On Fri, 11 May 2001, Colin Steele wrote: >> * creating impenetrable separation between interface and >> implementation Mathieu> I'm not sure what do you mean by "impenetrable". My thinking here revolves around putting myself into the shoes of a software vendor that wants to distribute a Ruby library. As such a vendor, I'd like a mechanism (other than saying it's a Bad Thing in the license) to strongly discourage the users of my library from poking around in its implementation. Why? Because to the extent that the implementation is exposed it *becomes* the interface, as far as the users of the library are concerned. They'll do "nasty" things that are fun and easy in Ruby, like move methods from one access protection level to another, poke around in my classes' instance variables, etc. The result is that it's nearly impossible for me to ship a bug fix or an upgrade. (This thinking may invoke issues of the ethics/morals of various software creation/distribution models. That chat will probably lead down the open source path. I propose we defer that for now, and stay open to the possibility that this sort of mechanism is useful for traditional software vendors, and may even be quite desirable for open source library developers, too.) The vendor really wants to hide the implementation behind a firewall. The API is "Give me an object supporting interface version X of this class." And what do you get? An *interface*, which is completely opaque. This allows me, the software vendor, to drop in a replacement implementation fixing bugs, etc., that supports the existing interface. Mathieu> I suppose we could (and should) have a separate version Mathieu> system for "compatibility", that is, a version system for Mathieu> "interface"; the other (regular) version system would be for Mathieu> implementation; however the kind of problem that crops up Mathieu> here is... bugs. Implementations have bugs, that is, failure Mathieu> to comply with a certain interface. I'm not sure what (and Mathieu> whether anything) should be done to handle bugs and bugfixes Mathieu> in relationship to this. It may be that these issues are orthogonal enough that they should get separate treatment... but I have the itchy feeling that there's too much overlap to invent separate mechanisms for them. >> Thankfully, some of the traditional problems are ones we don't >> have to deal with (yet?): * code incompatibility at the binary >> level One might argue that some of these issues aren't applicable >> to Ruby. (For instance, binary compatibility.) That's an open >> debate I think we should have. Mathieu> Binary compatibility is applicable to Ruby in the measure Mathieu> that the Ruby interpreter is written in C and the extension Mathieu> API to Ruby is designed for C and all it implies. All Mathieu> packages that contain .so/.dll files are potentially Mathieu> affected. Ah, yes. Quite right. >> However, I hope we don't lose sight of the fact that a) overall, >> library versioning is a critical need, and b) there are historical >> attempts to solve this problem in other contexts that may provide >> valuable lessons for us. Mathieu> May you provide more (historical) background on versioning Mathieu> with separation of interface and implementation? Sure. Much as I chafe against Microsoft, COM is one reasonable solution to many of these problems. (Although you can argue that Microsoft adopted COM to solve the very same "DLL Hell" problem that they created in the first place.) What's COM? In a nutshell, it's a reusable software component system. (Sounds good at first blush - in principal, like something one would want with Ruby.) In COM, you package up your class(es) in a "deployment unit" - a shared library. This physically decouples the client from your library. Then you separate interface from implementation, by modeling these two abstractions as separate entities. It also provides a mechanism to associate an interface with its implementation that doesn't reveal any implementation detail. This allows the implementor to modify implementations while holding the interface constant. Last, there's a client API for creating objects implementing a specified interface, and for coercing that object to other interfaces supported by the implementation. That's COM in a nutshell. It's a different way of thinking about this versioning issue. Instead of: require "somefile" { |v| v.version.between(1.2, 1.3) and v.author == "matju") } we'd be headed more in a more object- and interface-centric direction, like this (maybe?): require 'somepackage' version = Version.new('2.1') begin myFrob = SomePackage.frob(version) rescue UnsupportedInterface version -= '1.0' if version > '0.9' $stderr.puts('Upgrade SomePackage! Trying interface #{version}.') retry else $stderr.puts('SomePackage does not support any usable interfaces.') exit end end myFrob.doSomething('foo', 42) begin myFrob.doSomethingSpecial('bar', 84) # => raises UnsupportedInterface rescue UnsupportedInterface retry if myFrob.coerce('1.7.1') end So... what do you folks think? -- Colin Steele colin / webg2.com / www.colinsteele.org / www.rubycookbook.org From "The Hacker's Dictionary": doco: /do'koh/ [orig. in-house jargon at Symbolics] n. A documentation writer. See also {devo} and {mango}.