Namespaces too looooooong

I

Iain Barnett

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_hand=
s?
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=
 
R

Ryan Davis

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.
 
J

Joel VanderWerf

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

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
 
I

Iain Barnett

=20
Use local vars or (scoped) contants?

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

a =3D This_is_ok
=3D> This_is_ok

b =3D a::This_is_already_a_chore
=3D> This_is_ok::This_is_already_a_chore
c =3D b::Wow_I_have_no_feeling_left
=3D> 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!

=20
don't use them as much.
=20

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 ;)

Regards,
Iain=
 
C

Christopher Dicely

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

Iain Barnett

=20
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.
=20

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 :)

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
 
R

Robert Klemme

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 :)

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. :)

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. :)

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
 
P

Philipp Kempgen

Iain said:
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 ;)

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 :):) 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
 
R

Robert Klemme

ng out the good things learned over the years about things in computing see=
ms the wrong way to do it. It's why I don't use PHP ;)
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' );

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

Sh =3D ::FooVendor::System::Shell
Sh.exec 'ls'

sh =3D ::FooVendor::System::Shell
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
=A0 =A0 =A0 =A0module B
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0class X
=A0 =A0 =A0 =A0end
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 :):) 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. :)

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. :)
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. :)

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
P

Philipp Kempgen

Robert said:
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'

Sure.
I guess I'll do some benchmarks. :)
Neither - you would reference via A::B::X or ::A::B::X. :)

Oops. Typo.
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. :)

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. :)

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 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
 
R

Robert Klemme

wing out the good things learned over the years about things in computing s=
eems the wrong way to do it. It's why I don't use PHP ;)
Sure.
I guess I'll do some benchmarks. :)

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

Iain Barnett

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

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.


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=
 
R

Robert Klemme

2010/8/31 Iain Barnett said:
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!
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
 
P

Philipp Kempgen

Robert said:
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
 
R

Robert Klemme

Robert said:
I don't expect much differences. =A0Please share the outcome of the benc=
hmark.

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. :) 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
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 =3D FooVendor::System::Shell
if false; Sh::exec(''); end
if false; Sh::exec(''); end
-----------------------------------------------------------------
(unnecessary autoload)

vs.

---Ruby----------------------------------------------------------
if false; Sh =3D FooVendor::System::Shell; Sh::exec(''); end
if false; Sh =3D 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.

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. :)

Kind regards

robert


--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
P

Philipp Kempgen

Robert Klemme schrieb (am 1.9.10 11:54):
Robert said:
2010/8/31 Philipp Kempgen <[email protected]>:
Robert Klemme wrote:
2010/8/31 Philipp Kempgen <[email protected]>:
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' );

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'

Sure.
I guess I'll do some benchmarks. :)

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. :) Then everybody can judge for
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-------------------------------------------------------------
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
 
R

Robert Klemme

Robert Klemme schrieb (am 1.9.10 11:54):
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 =3D=3D 'monday' || entropy > 60)
=A0 =A0 =A0 =A0Sh::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).

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
R

Ryan Davis

On 31 Aug 2010, at 02:04, Ryan Davis wrote:
=20
don't use [namespaces] as much.
=20
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 ;)

someday grasshopper... someday...

("as much" was the key there)
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top