Joel VanderWerf
12/28/2004 4:50:00 AM
eero.saynatkari@kolumbus.fi wrote:
> Apologies if this topic has already been beaten to death.
> Oh, and for the long-windedness.
>
> Using modules for namespaces is somewhat unwieldy. I'd call it one
> of the few evil parts of Ruby, although its implementation is
> understandable when viewed from an OO standpoint. It's just
> tiresome to A) invent and B) use unique namespaces in Ruby (and
> by 'unique' I mean FooSoft Inc. wrapping all their libraries inside a
> module FooSoft).
>
> Of the current commercial languages, the package system of Java is
> likely to be the best for flexibility and uniqueness, although it
> does suffer from verbosity--and I wouldn't mind seeing Haskell-style
> limited export capabilities, either. This, of course, should be
> possible to do in Ruby 'on top' of the current system.
>
> But why use unique namespaces? Modules are certainly useful for
> partitioning a project into its constituent parts, but unique
> namespaces are only useful in the context of that code being used
> by another party where it can prevent namespace clashes. This, of
> course, is highly site-dependent: it may not be necessary at all,
> they may already have a package with the same 'unique' namespace,
> they may not like the module name, etc. etc.
>
> Why not have the 'client' decide if and which namespace to assign
> to a foreign library? As in, if I want to use FooBar Inc.'s Math
> package, they need not wrap it in module FooBar, but can just ship
> it as Math. Then I just wrap it to Extern, my namespace for all
> third-party modules. In current Ruby, I suppose this can be achieved
> with something like (please correct if I'm wrong, this is off the top
> of my head):
> -----
>
> # Toplevel
> # This is just an aesthetically pleasing (?) implementation,
> # I'm not sure about using String for the ascribed purpose.
>
> def import file
> file[:module].module_eval(IO.readlines(file[:name]).join)
> end
>
> class String
> def as module
> {:name => self, :module => module}
> end
>
> # Convenience
> alias :in :as
> alias :into :as
> end
>
> # Usage
> import "foomath.rb".as Extern
>
> rand = Extern::Math.random()
>
> -----
> Or is that just counterintuitive? It would at least conceptually
> free the module construct from doing double duty as the namespace
> construct.
>
> The Ruby implementation is obviously somewhat slow but it could be
> written to use the same routines as require()/load() with the
> exception of doing the loading in the context of a given module. I
> think the above 'implementation' also handles altogether non-moduled
> files but I may be wrong in my it's-Sunday-morning-and-I'm-at-work
> stupor.
I like the idea very much, but there are some difficulties...
def import file
file[:module].module_eval(IO.readlines(file[:name]).join)
end
class String
def as mod
{:name => self, :module => mod}
end
end
module Extern; end
# It's a little awkward, but you gotta do this first, if
# you want to refer to the module as below.
libfile = "/usr/local/lib/ruby/1.8/complex.rb"
# One problem is the cumbersome path name to the library file.
import libfile.as(Extern)
# This fails because the library complex.rb tries to open an existing
# class, Numeric, and modify its contents. But instead it opens a new
# module, also called Numeric, that lives inside the wrapper. You can
# fix this in complex.rb (assuming you want to touch 3rd party code)
# by referring to the module as ::Numeric when you define it. But
# there's still a problem...
z = Extern::Complex(1,2)
# "undefined method `Complex' for Extern::Complex"
# This is due to the special effect of "def foo" at the top level in
# ruby--it defines an instance method of Object. But the effect within
# the wrapper module is very different. Again it's possible to modify
# the 3rd party code, as follows:
#
# class ::Object
# def Complex(a, b = 0)
# # ...
# end
# end