Nat Pryce wrote:

> In Ruby, if I want to load a class Foo::Bar::SomeClass, I have to both
> require the file that the class is packaged in, *and* import the module
> that
> it is defined in.  In Java, I just import the module and the class loader
> locates the file and loads the class.  How classes are organised as files
> or other storage media is not exposed in client code.

This is picking nits.  my.package.and.Class may not have slashes in it, but 
it is still a filesystem path.  And for the record, I almost never import a 
module to use a class; I do one require, and then access the classes via 
the Package::Class scheme.  This would, of course, become more difficult if 
we started having long path names, as are common in Java.  In any case, 
your base argument seems to be that you have two disjoint paths to classes 
in Ruby, and only one in Java, and I agree that this is a valid complaint.

> A Java class loader has complete freedom to translate a fully specified
> class name (e.g. including the package prefix) into whatever storage
> location it wants.   The implementation of the system class loader in

As I said, you can override "require" in Ruby just as easily (and probably 
easier) as rewriting the ClassLoader in Java.  You can overload require to 
load classes from over a socket connection.  I maintain there isn't any 
inherant advantage to Java's ClassLoader or the mechanism by which Java 
resolves class names into objects.

> physical storage. If I move a Java class from one JAR file to another, I
> don't have
> to change any client code.  However, if I move a Ruby class definition
> from one .rb file to another, I have to change all client code that uses
> that class. Therefore Ruby couples client code more tightly to the modules
> that it uses than does Java.

Ah.  I see.  I think this is an unfair comparison.  How often do you define 
multiple classes in one source file in Java?  Most people do it very 
rarely.  Ruby makes it easier to put multiple classes in a single file, but 
if you're going to compare the systems, you should use the same basic 
organizational model.

> Yes, you could.  That doesn't help reduce the coupling caused by depending
> on both the class name *and* the physical storage though.

Sure.  Consider:

def load_class_hash
        # Find all classes in all .rb files in $: and stick their names into
        # a hash file.  Also query some servers that have archives of Ruby
        # sources, and get a list of all of the classes they know about.
        # Stick this hashtable in some global variable, and redefine this method
        # to do nothing.
end

def decrypt( name )
        name.gsub( /::/, "/" )
end

def require( name, auto_import=false )
        name = decrypt( name )
        load_class_hash()
        # Now access the hash to find the location of the file that contains
        # the requested class, and read the stream.  Evaluate the stream,
        # thereby loading that class.  For kicks, allow auto-importing:
        class_def = @@__class__hash__[name].readlines()
        class_eval class_def
        class_eval "import #{name}" if auto_import
end

require "REXML::Document"

You can make your class names whatever you want, and you've effectively 
turned Ruby's "require" into Java's ClassLoader by forcing the paths and 
names of the require to match the paths and names of the packages and 
classes.  I'm oversimplifying, and you'll probably have some issues with 
breaking recursive requires that don't use your fancy-pants nameing 
mechanism, but these issues can be worked around.


-- 
--- SER