Namespaces, inverted

Discussion in 'Ruby' started by Guest, Dec 26, 2004.

  1. Guest

    Guest Guest

    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.

    E
     
    Guest, Dec 26, 2004
    #1
    1. Advertising

  2. 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
     
    Joel VanderWerf, Dec 28, 2004
    #2
    1. Advertising

  3. "Joel VanderWerf" <> schrieb im Newsbeitrag
    news:...
    > 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


    I don't like the idea of the as method as it cannot be used reasonable in
    other circumstances as module loading. The code really does not belong into
    class String IMHO.

    We have Kernel#load [1] with a similar functionality already. Currently it
    accepts an additional parameter to enforce wrapping of the file in an
    anonymous module. That could be extended to accept a module as well; that
    then would be the module used. Then we can do

    load "foo.rb" # not wrapped
    load "foo.rb" # wrapped in an anonymous module
    load "foo.rb", MyExternal # wrapped in MyExternal

    Additionally / Alternatively it could be useful to have a per module require
    like this:

    class Module
    def require(*files)
    # puts "loading in module #{self}: #{files.inspect}"
    @loaded ||= {}
    files.each do |f|
    unless @loaded[f]
    # real load code that wraps contents of f in self
    @loaded[f] = true
    end
    end
    end
    end

    Then we could do

    module Foo
    require "bar"
    end

    and even if we do the same later again, "bar" is only loaded once (see [2]).

    Sounds like an RCR candidate, doesn't it?

    Kind regards

    robert


    [1] http://www.ruby-doc.org/core/classes/Kernel.html#M001744

    [2] http://www.ruby-doc.org/core/classes/Kernel.html#M001745
     
    Robert Klemme, Dec 28, 2004
    #3
  4. Robert Klemme wrote:
    ...
    > We have Kernel#load [1] with a similar functionality already. Currently
    > it accepts an additional parameter to enforce wrapping of the file in an
    > anonymous module. That could be extended to accept a module as well;
    > that then would be the module used. Then we can do
    >
    > load "foo.rb" # not wrapped
    > load "foo.rb" # wrapped in an anonymous module
    > load "foo.rb", MyExternal # wrapped in MyExternal


    Wrapping is a nice idea (see raa:script for one approach), but the
    wrapped lib will break if it depends on modifying classes or modules in
    the global scope or defining global methods (the Complex example in my
    previous email).

    There is the idea the OP mentioned of parsing input files and rewriting
    them to be explicit about the scope of definitions, automating the
    kludgy hack I proposed for complex.rb. But that will break if the lib
    uses dynamic code generation.

    Maybe library writers should follow a standard of making their code
    explicit about namespaces:

    1. If you open and existing class, give an absolute path to it:

    class ::Integer

    rather than

    class Integer

    2. Global methods defs should be wrapped like this:

    class ::Object
    def global_meth ... end
    end

    3. References to constants (not just classes and modules) defined in the
    lib should be relative:

    class Foo
    end

    f = Foo.new

    and not absolute:

    f = ::Foo.new

    (although I can't imagine that many libs have this problem).

    4. Anything else to protect the lib from breakage when wrapping?
     
    Joel VanderWerf, Dec 28, 2004
    #4
  5. "Joel VanderWerf" <> schrieb im Newsbeitrag
    news:...
    > Robert Klemme wrote:
    > ..
    >> We have Kernel#load [1] with a similar functionality already. Currently
    >> it accepts an additional parameter to enforce wrapping of the file in an
    >> anonymous module. That could be extended to accept a module as well;
    >> that then would be the module used. Then we can do
    >>
    >> load "foo.rb" # not wrapped
    >> load "foo.rb" # wrapped in an anonymous module
    >> load "foo.rb", MyExternal # wrapped in MyExternal

    >
    > Wrapping is a nice idea (see raa:script for one approach), but the wrapped
    > lib will break if it depends on modifying classes or modules in the global
    > scope or defining global methods (the Complex example in my previous
    > email).
    >
    > There is the idea the OP mentioned of parsing input files and rewriting
    > them to be explicit about the scope of definitions, automating the kludgy
    > hack I proposed for complex.rb. But that will break if the lib uses
    > dynamic code generation.
    >
    > Maybe library writers should follow a standard of making their code
    > explicit about namespaces:
    >
    > 1. If you open and existing class, give an absolute path to it:
    >
    > class ::Integer
    >
    > rather than
    >
    > class Integer


    Totally agree. I guess this is seldom used these days.

    > 2. Global methods defs should be wrapped like this:
    >
    > class ::Object
    > def global_meth ... end
    > end


    That's really the same as case 1, isn't it?

    > 3. References to constants (not just classes and modules) defined in the
    > lib should be relative:
    >
    > class Foo
    > end
    >
    > f = Foo.new
    >
    > and not absolute:
    >
    > f = ::Foo.new
    >
    > (although I can't imagine that many libs have this problem).


    I think so, too.

    > 4. Anything else to protect the lib from breakage when wrapping?


    We would have to think about what happens if a wrapped module requires
    another module. If that other module is a standard module you'll certainly
    do not want it to be included in the wrapping namespace. If it belongs to
    the same lib, then of course you want it wrapped. So the crucial question
    is: how are these require's distinguished? I'm not 100% sure but I think a
    simple 'require "foo"' will look relative as well as in global directories -
    that might be a chance to distinguish...

    As much as I like the original idea of wrapping classes in namespaces (much
    the way that can be done with C++ because of #include) I believe this needs
    more thought.

    Kind regards

    robert
     
    Robert Klemme, Dec 30, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Manfred Balik

    Inverted Clock in ACEX1K

    Manfred Balik, Aug 29, 2003, in forum: VHDL
    Replies:
    1
    Views:
    1,321
    Marc Guardiani
    Aug 30, 2003
  2. Jon Maz
    Replies:
    3
    Views:
    1,688
    Jon Maz
    Feb 13, 2004
  3. Sakthi
    Replies:
    0
    Views:
    378
    Sakthi
    Sep 15, 2004
  4. Sakthi
    Replies:
    0
    Views:
    439
    Sakthi
    Sep 15, 2004
  5. AviraM
    Replies:
    2
    Views:
    6,505
    Manish Pandit
    Sep 28, 2006
Loading...

Share This Page