Namespaces too looooooong

Hi,

What’s the best trick for avoiding RSI with nested modules? For example,

module This_is_ok
module This_is_already_a_chore
class Wow_I_have_no_feeling_left

   class << self
     def in_my_hands?
       ...
     end
   end
 end

end
end

require ‘this_is_ok/this_is_already_a_chore’

if
This_is_ok::This_is_already_a_chore::Wow_I_have_no_feeling_left.in_my_hands?
puts “There must be an easier way than all this typing???”
end

I’d really like to know, perhaps something akin to the Haskell import
syntax where a short name can be given for a module. I’ve found there to
be a real paucity of good examples of using modules to create
namespaces, and even less on what to do once you’ve gone to the trouble
of not crapping all over the global namespace, so any help will be much
appreciated by me, and probably future generations programming Ruby with
their shovel-like fingers on iPhones.

Regards,
Iain

On Aug 30, 2010, at 17:51 , Iain B. wrote:

What’s the best trick for avoiding RSI with nested modules? For example,

module This_is_ok
module This_is_already_a_chore
class Wow_I_have_no_feeling_left

don’t use them as much.

do the simplest thing that could possibly work. nothing more.

On 08/30/2010 05:51 PM, Iain B. wrote:

        ...

end
Use local vars or (scoped) contants?

like_putty =
This_is_ok::This_is_already_a_chore::Wow_I_have_no_feeling_left

if like_putty.in_my_hands?

end

Going back in time would be cool if it was in a time machine, but throwing out the good things learned over the
years about things in computing seems the wrong way to do it.

Is using deeply nested modules in such a way that a consumer of the
module would be expected to reach deeply into the nesting structure a
“good thing” though? It seems to me that deeply nested modules work
best where the deeper layers are used by the higher layers, not by a
external consumers.

On 31 Aug 2010, at 02:07, Joel VanderWerf wrote:

Use local vars or (scoped) contants?

Excellent, thanks. I didn’t realise they could just be stuck into vars.

a = This_is_ok
=> This_is_ok

b = a::This_is_already_a_chore
=> This_is_ok::This_is_already_a_chore
c = b::Wow_I_have_no_feeling_left
=> This_is_ok::This_is_already_a_chore::Wow_I_have_no_feeling_left

Brilliant. If the language designers can just nick the where clause
from Haskell then I think Ruby will be approaching terse perfection!

On 31 Aug 2010, at 02:04, Ryan D. wrote:

don’t use them as much.

Going back in time would be cool if it was in a time machine, but
throwing out the good things learned over the years about things in
computing seems the wrong way to do it. It’s why I don’t use PHP :wink:

Regards,
Iain

On 31 Aug 2010, at 03:29, Christopher D. wrote:

Going back in time would be cool if it was in a time machine, but throwing out the good things learned over the
years about things in computing seems the wrong way to do it.

Is using deeply nested modules in such a way that a consumer of the
module would be expected to reach deeply into the nesting structure a
“good thing” though? It seems to me that deeply nested modules work
best where the deeper layers are used by the higher layers, not by a
external consumers.

I completely agree. But, if you can find me a good article on how to use
nested modules as namespaces in a library, and how to refer to different
parts of the module from within and without, including writing tests for
it and how rake will interact with the changes, and includes all the
different ways it will affect require, while avoiding many more
articles that complain about libraries polluting the global namespace
and stomping all over each other then I’ll also agree not to look on
comments like “use them less” as an encouragement to be disorganised and
more as an invitation to use a facade :slight_smile:

Because I tried, and there’s bugger all out there. It’s no wonder
there’s been a problem with clashing because it appears that those who
know how to avoid it haven’t bothered to tell anyone else. That’s not
the best way to encourage best practice, IMO.

Regards,
Iain

Iain B. wrote:

On 31 Aug 2010, at 02:07, Joel VanderWerf wrote:

Use local vars or (scoped) contants?

Excellent, thanks. I didn’t realise they could just be stuck into vars.

Going back in time would be cool if it was in a time machine, but throwing out the good things learned over the years about things in computing seems the wrong way to do it. It’s why I don’t use PHP :wink:

Actually one of the few nice things about namespaces in PHP is the
ability to import namespaces/classes using an alias.

use \foovendor\system\Shell as Sh;

Sh::exec( ‘ls’ );

And I like the convention (not imposed by PHP) to use lowercase
names for namespaces. In the example above it is immediately clear
that “\foovendor\system” is a namespace and that “Shell” is a class.

BTW: Given the Ruby example in following

module A
module B
class X
end
end

it’s still not clear to me if I should refer to the X class as
A::b::C or as ::a::b::C to make it obvious that this refers to
A::b::C in the top-level scope (::slight_smile: and to avoid a lookup in the
local scope. (What are the best practices?)

My benchmarks show no significant performance improvement though
(whereas there is a noticable improvement in PHP).

Actually if you want the maximum performance out of PHP you end up
using fully qualified identifiers everywhere, e.g. \strlen instead
of strlen and \true instead of true (oh boy).

Philipp

On 08/31/2010 06:22 AM, Iain B. wrote:

modules work best where the deeper layers are used by the higher
encouragement to be disorganised and more as an invitation to use a
facade :slight_smile:

Well, there is always one thing that you can do to avoid too much
nesting:

module A
module B
class X
end
end

->

module A
end

module A::B
end

class A::b::X
end

There are however subtle namespacing implications so I generally avoid
this. :slight_smile:

The access problem for tests is usually solved by placing tests in the
same namespace as classes under test. Then you can apply the same
relative access path as for the code itself.

Because I tried, and there’s bugger all out there. It’s no wonder
there’s been a problem with clashing because it appears that those
who know how to avoid it haven’t bothered to tell anyone else. That’s
not the best way to encourage best practice, IMO.

Well, you should also consider that people might not have run into the
issue you have run into in the first place. So there was nothing bad
that they needed to learn how to avoid. :slight_smile:

Also, the general practice in Ruby seems to be to not nest too much
(Ruby programmers are quite lazy as far as I can see). I can’t remember
having seen more than three modules nested as namespaces - it’s
certainly quite rare. Also, we tend to use short names…

Maybe you do not need to throw out too many things but adjust what you
learned over the years to Ruby style. It is generally easier to go with
the flow than try to literally translate concepts from other programming
environments to the new language.

Kind regards

robert

Robert K. wrote:

2010/8/31 Philipp K. [email protected]:

Iain B. wrote:

Sh = ::FooVendor::System::Shell
Sh.exec ‘ls’

sh = ::FooVendor::System::Shell
sh.exec ‘ls’

Sure.
I guess I’ll do some benchmarks. :slight_smile:

A::b::C or as ::a::b::C to make it obvious that this refers to
A::b::C in the top-level scope (::slight_smile: and to avoid a lookup in the
local scope. (What are the best practices?)

Neither - you would reference via A::b::X or ::a::b::X. :slight_smile:

Oops. Typo.

closet and try to approach Ruby with less historic baggage. :slight_smile:
Yes, Ruby folks seem to prefer unprefixed identifiers.
The same thing is true for PHP developers.

But then again if a simple “::” prefix can make my code x % faster
by skipping unnecessary lookups in the local scope – well I guess
it depends on x whether I’m willing to trade conciseness for speed.

And apart from that I still think that fully-qualified, anchored
identifiers (“::…”) in a library can make that library more
robust (without affecting the consumers of that library) and less
prone to problems concerning namespace resolution which could
potentially be both hard to track down and boring.

That has nothing to do with porting the PHP way of thinking into
the Ruby world. :slight_smile:

Hardly anyone seems to care though.

Actually I suppose most developers don’t even make an “informed
decision” not to use anchored identifiers, and that worries me.

I guess all I want is to make an informed decision a la “anchored
identifiers don’t buy me that much and the extra robustness does
not compensate for the additional clutter in my code”.

My benchmarks show no significant performance improvement though
(whereas there is a noticable improvement in PHP).

Actually if you want the maximum performance out of PHP you end up
using fully qualified identifiers everywhere, e.g. \strlen instead
of strlen and \true instead of true (oh boy).

My goodness!

Crazy, right? It’s particularly strange since you can’t override
the special constants true, false and null in a namespace anyway.
And while we’re at it: true is faster than TRUE in PHP.

I don’t think I should optimize for speed at all costs but that’s a
good example of where optimization comes for free. It does not cost
anything to write true instead of TRUE.

And it does not cost much to replace strlen() by \strlen() in a
tight loop while in general avoiding the clutter that is introduced
by anchored names.

Philipp

2010/8/31 Philipp K. [email protected]:

ability to import namespaces/classes using an alias.

use \foovendor\system\Shell as Sh;

Sh::exec( ‘ls’ );

Well, you can do the same in Ruby. Either use a constant or a local
variable:

Sh = ::FooVendor::System::Shell
Sh.exec ‘ls’

sh = ::FooVendor::System::Shell
sh.exec ‘ls’

end

it’s still not clear to me if I should refer to the X class as
A::b::C or as ::a::b::C to make it obvious that this refers to
A::b::C in the top-level scope (::slight_smile: and to avoid a lookup in the
local scope. (What are the best practices?)

Neither - you would reference via A::b::X or ::a::b::X. :slight_smile:

Dunno whether there is a best practice. If you want to be on the
safe side when accessing classes and modules outside your current
module hierarchy then you must use the “::” prefix. If you have many
classes and modules in your namespace it’s probably best to anchor
lookups in the global namespace to avoid issues. Generally though
people seem to be using unprefixed names - especially for frequently
used classes like String and Hash.

What seems to be an issue for you (or for people coming from PHP) does
not seem to be an issue for most Ruby developers (at least if my
feeble memory of discussions here does not fail me). It’s
understandable but it might be easier to stuff PHP experience in the
closet and try to approach Ruby with less historic baggage. :slight_smile:

My benchmarks show no significant performance improvement though
(whereas there is a noticable improvement in PHP).

Actually if you want the maximum performance out of PHP you end up
using fully qualified identifiers everywhere, e.g. \strlen instead
of strlen and \true instead of true (oh boy).

My goodness! Another reason to abhor PHP. Please do not import any
bad practices from PHP to Ruby - at least not when writing libraries
that you intend to release into the public. :slight_smile:

Kind regards

robert

2010/8/31 Philipp K. [email protected]:

Sure.
I guess I’ll do some benchmarks. :slight_smile:

I don’t expect much differences. Please share the outcome of the
benchmark.

A::b::C or as ::a::b::C to make it obvious that this refers to
A::b::C in the top-level scope (::slight_smile: and to avoid a lookup in the
local scope. (What are the best practices?)

Neither - you would reference via A::b::X or ::a::b::X. :slight_smile:

Oops. Typo.

Hehe.

closet and try to approach Ruby with less historic baggage. :slight_smile:

Yes, Ruby folks seem to prefer unprefixed identifiers.
The same thing is true for PHP developers.

But then again if a simple “::” prefix can make my code x % faster
by skipping unnecessary lookups in the local scope – well I guess
it depends on x whether I’m willing to trade conciseness for speed.

A language that can be significantly sped up by doing this feels quite
broken to me.

And apart from that I still think that fully-qualified, anchored
identifiers (“::…”) in a library can make that library more
robust (without affecting the consumers of that library) and less
prone to problems concerning namespace resolution which could
potentially be both hard to track down and boring.

Right. At least in theory.

That has nothing to do with porting the PHP way of thinking into
the Ruby world. :slight_smile:

Hardly anyone seems to care though.

Probably because the bugs you mentioned above happen too infrequently
(or not at all) in practice. Ruby folks are usually very pragmatic
and use whatever works (although I would readily agree that this a)
isn’t always good and b) is an oversimplification).

Actually I suppose most developers don’t even make an “informed
decision” not to use anchored identifiers, and that worries me.

I guess all I want is to make an informed decision a la “anchored
identifiers don’t buy me that much and the extra robustness does
not compensate for the additional clutter in my code”.

If there is no experience you can build on you’ll have to gather it
yourself, I’m afraid. The good news is that you can advance the
community by sharing what you found.

My benchmarks show no significant performance improvement though
(whereas there is a noticable improvement in PHP).

Actually if you want the maximum performance out of PHP you end up
using fully qualified identifiers everywhere, e.g. \strlen instead
of strlen and \true instead of true (oh boy).

My goodness!

Crazy, right?

“Crazy” sounds about right - if not too mild.

Kind regards

robert

2010/8/31 Iain B. [email protected]:

On 31 Aug 2010, at 12:54, Robert K. wrote:

Probably because the bugs you mentioned above happen too infrequently
(or not at all) in practice.

I’d have to disagree. Like I said, when I was looking for best practice on the topic and couldn’t find it, I did find lots of people moaning about libraries breaking each other due to not bothering to wrap themselves in a namespace.

Please note that my statement referred to bugs caused by not anchoring
constant expressions in the global namespace - not about using or not
using namespaces in general!

I even found a gem someone had written a gem that fixes other gems’ namespacing. Now that sounds like something broken.

Completely agree: that’s ridiculous!

On 31 Aug 2010, at 09:25, Philipp K. wrote:

Actually one of the few nice things about namespaces in PHP is the
ability to import namespaces/classes using an alias.

Much as putting a namespace in a constant is much better than what I had before, I like the idea of as, or of alias extending to namespaces. It reads better, IMO.

Unfortunately for particular things you need a constant or variable -
otherwise lookups won’t work.

Kind regards

robert

On 31 Aug 2010, at 12:54, Robert K. wrote:

Probably because the bugs you mentioned above happen too infrequently
(or not at all) in practice.

I’d have to disagree. Like I said, when I was looking for best practice
on the topic and couldn’t find it, I did find lots of people moaning
about libraries breaking each other due to not bothering to wrap
themselves in a namespace.

I even found a gem someone had written a gem that fixes other gems’
namespacing. Now that sounds like something broken.

On 31 Aug 2010, at 09:25, Philipp K. wrote:

Actually one of the few nice things about namespaces in PHP is the
ability to import namespaces/classes using an alias.

Much as putting a namespace in a constant is much better than what I had
before, I like the idea of as, or of alias extending to namespaces.
It reads better, IMO.

Regards,
Iain

On Wed, Sep 1, 2010 at 11:39 AM, Philipp K. [email protected]
wrote:

I don’t expect much differences. Please share the outcome of the benchmark.

In my totally unscientific benchmarks I did not find any noticeable
divergence. It is certainly well below 1 %. Fine.

ruby 1.9.2p0 (2010-08-18 revision 29036) [i686-linux]

Thanks for sharing your findings! To make it “scientific” you could
also post the benchmark code. :slight_smile: Then everybody can judge for
themselves.

Just in case you were not aware there is a nice module Benchmark which
allows for easy benchmarking.

http://www.ruby-doc.org/stdlib/libdoc/benchmark/rdoc/classes/Benchmark.html
http://www.ruby-doc.org/stdlib/libdoc/benchmark/rdoc/index.html

if (false) Sh::exec(‘ls’);
(unnecessary autoload)
Ruby but for the time being the unnecessary autoload wins.
Well, if you alias a namespace that you never use then you have
created dead code already. Personally I find it preferable to not
encourage people to simply copy and paste code (even if it is a number
of namespace aliases) so I’d say it’s good the way it is. :slight_smile:

Kind regards

robert

Robert K. wrote:

2010/8/31 Philipp K. [email protected]:

Robert K. wrote:

2010/8/31 Philipp K. [email protected]:

sh = ::FooVendor::System::Shell
sh.exec ‘ls’

Sure.
I guess I’ll do some benchmarks. :slight_smile:

I don’t expect much differences. Please share the outcome of the benchmark.

In my totally unscientific benchmarks I did not find any noticeable
divergence. It is certainly well below 1 %. Fine.

ruby 1.9.2p0 (2010-08-18 revision 29036) [i686-linux]

However it occurred to me that there is a difference between
namespace aliases in PHP and the closest thing in Ruby (as
described above): Autoloading.

In Ruby the assignment to a constant or variable will not work
if the module/class has not been loaded (obviously) whereas in
PHP I can assign an alias and never use the class.

—PHP-----------------------------------------------------------
use \foovendor\system\Shell as Sh;
if (false) Sh::exec(‘ls’);
if (false) Sh::exec(‘ls’);

vs.

—Ruby----------------------------------------------------------
Sh = FooVendor::System::Shell
if false; Sh::exec(‘’); end
if false; Sh::exec(‘’); end

(unnecessary autoload)

vs.

—Ruby----------------------------------------------------------
if false; Sh = FooVendor::System::Shell; Sh::exec(‘’); end
if false; Sh = FooVendor::System::Shell; Sh::exec(‘’); end

(ugly)

Whatever. Maybe namespace aliasing could be a nice addition to
Ruby but for the time being the unnecessary autoload wins.

Philipp

On Wed, Sep 1, 2010 at 12:29 PM, Philipp K. [email protected]
wrote:

Robert K. schrieb (am 1.9.10 11:54):

On Wed, Sep 1, 2010 at 11:39 AM, Philipp K. [email protected] wrote:

Robert K. wrote:

if (today == ‘monday’ || entropy > 60)
Sh::exec( ‘run some cleanup tasks’ )
end

Or course you’re right. My bad.

Cheers

robert

PS: Benchmark looks good. Btw, you don’t need the space filling if
you invoke bm with an integer (label width).

On Aug 30, 2010, at 18:24 , Iain B. wrote:

On 31 Aug 2010, at 02:04, Ryan D. wrote:

don’t use [namespaces] as much.

Going back in time would be cool if it was in a time machine, but throwing out the good things learned over the years about things in computing seems the wrong way to do it. It’s why I don’t use PHP :wink:

someday grasshopper… someday…

(“as much” was the key there)

Robert K. schrieb (am 1.9.10 11:54):

Sh::exec( ‘ls’ );
I guess I’ll do some benchmarks. :slight_smile:
themselves.
Sure. Here you are:
—cut-------------------------------------------------------------
#!/usr/bin/env ruby

require ‘benchmark’

module Foo
module Sys
class Shell
def self.exec cmd
end
end
end
end

Sh2 = Foo::Sys::Shell

module SomewhereIn
module AnotherNestedModule

Sh1 = Foo::Sys::Shell
sh1 = Foo::Sys::Shell

n = 500000
Benchmark.bm { |b|
  b.report('idle   :'){n.times{                             }}
  b.report('abs    :'){n.times{   Foo::Sys::Shell::exec('') }}
  b.report('absfq  :'){n.times{ ::Foo::Sys::Shell::exec('') }}
  b.report('var    :'){n.times{               sh1::exec('') }}
  b.report('cnst   :'){n.times{               Sh1::exec('') }}
  b.report('cnstfq :'){n.times{             ::Sh2::exec('') }}
}

end
end
—cut-------------------------------------------------------------

if (false) Sh::exec(‘ls’);
(unnecessary autoload)
Whatever. Maybe namespace aliasing could be a nice addition to
Ruby but for the time being the unnecessary autoload wins.

Well, if you alias a namespace that you never use then you have
created dead code already.

Nope. The condition (false) in the examples above is rather
simplistic for the sake of clarity. But you can easily have a
conditional branch that is not dead code.

if (today == ‘monday’ || entropy > 60)
Sh::exec( ‘run some cleanup tasks’ )
end

Philipp