Nested class/module namespace

The new ability to declare a class nested in another module (or class)
without actually re-declaring the outer module is cool, BUT:

irb(main):001:0> module M
irb(main):002:1> CONST = “a"
irb(main):003:1> class C
irb(main):004:2> def m
irb(main):005:3> p CONST
irb(main):006:3> end
irb(main):007:2> end
irb(main):008:1> end
=> nil
irb(main):009:0> M::C::new.m
"a”
=> nil
irb(main):010:0> class M::C
irb(main):011:1> def m
irb(main):012:2> p CONST
irb(main):013:2> end
irb(main):014:1> end
=> nil
irb(main):016:0> M::C::new.m
NameError: uninitialized constant M::C::CONST
from (irb):12:in `m’
from (irb):16

Why does the second case fail? It makes me not want to use the second
version, since it means I have to fully-qualify all constants in the
enclosing namespace, instead of just using them as I usually do. I hope it’s
just a bug :-/.

Nathaniel

<:((><

Nathaniel Talbott wrote:

The new ability to declare a class nested in another module (or class)
without actually re-declaring the outer module is cool, BUT:
[…]
Why does the second case fail? It makes me not want to use the second
version, since it means I have to fully-qualify all constants in the
enclosing namespace, instead of just using them as I usually do. I hope it’s
just a bug :-/.

I can’t help thinking that it might be a feature, not a bug.

Class and module provide namespaces. In the old style, we could not help
but opening all the layers of modules (and thusly their namespaces) when
defining a class within them.

With the new style, we get a cleaner, neater and minimalistic namespace,
where we can include those namespaces we want. (With the exception of
nested classes, but a work-around for that only requires a little
refactoring).

So unless “class M::C” and friends is just meant to be syntactic sugar,
(phoey!) this might help us create cleaner code, IMHO. I wouldn’t write
it off as a bug just yet.

···


([ Kent Dahl ]/)_ ~ [ http://www.pvv.org/~kentda/ ]/~
))_student_/(( _d L b_/ (pre-) Master of Science in Technology )
( __õ|õ// ) )Industrial economics and technological management(
_
/ö____/ (_engineering.discipline=Computer::Technology)

Hi,

···

In message “Nested class/module namespace” on 03/08/12, “Nathaniel Talbott” nathaniel@NOSPAMtalbott.ws writes:

Why does the second case fail? It makes me not want to use the second
version, since it means I have to fully-qualify all constants in the
enclosing namespace, instead of just using them as I usually do. I hope it’s
just a bug :-/.

Unfortunately, it’s not. “class M::C” notation is not a syntax sugar
for 'module M; class C". It is something like “M::C = Class.new”, so
that the body of C definition is not nested in the M body.

						matz.

Kent Dahl wrote:

So unless “class M::C” and friends is just meant to be syntactic sugar,
(phoey!) this might help us create cleaner code, IMHO. I wouldn’t write
it off as a bug just yet.

I can’t help thinking that it might be a feature, not a bug.

Agreed!

Class and module provide namespaces. In the old style, we could not help
but opening all the layers of modules (and thusly their namespaces) when
defining a class within them.

With the new style, we get a cleaner, neater and minimalistic namespace,
where we can include those namespaces we want. (With the exception of
nested classes, but a work-around for that only requires a little
refactoring).

So unless “class M::C” and friends is just meant to be syntactic sugar,
(phoey!) this might help us create cleaner code, IMHO. I wouldn’t write
it off as a bug just yet.

The curren new (scoping) rule is simple and straight forward. I am afraid
that a ``resolution’s of this bug would complicate things without gaining
much (besides violating the POLS of people growing up with C,Java, etc.
style scoping rules - but Ruby has luckily always done this!)

/Christoph

Hi –

···

On Wed, 13 Aug 2003, Yukihiro Matsumoto wrote:

Hi,

In message “Nested class/module namespace” > on 03/08/12, “Nathaniel Talbott” nathaniel@NOSPAMtalbott.ws writes:

Why does the second case fail? It makes me not want to use the second
version, since it means I have to fully-qualify all constants in the
enclosing namespace, instead of just using them as I usually do. I hope it’s
just a bug :-/.

Unfortunately, it’s not. “class M::C” notation is not a syntax sugar
for 'module M; class C". It is something like “M::C = Class.new”, so
that the body of C definition is not nested in the M body.

At first glance this seems like a loss. Are there times when there’s
an advantage to having it work that way?

David


David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

I don’t understand the benefit… when I use classes and modules for
namespacing, I group related things under the same namespace, and it’s great
for those related things to be able to access one another without fully
qualifying names. For instance:

table.rb:

module SE
class Server
module DB
class Table

end
end
end
end

tc_table.rb:

module SE
class Server
module DB
class TC_Table < Test::Unit::TestCase
def test_stuff
t = Class::new(Table) do # Table is visible in the DB namespace

end

end
end
end
end
end

I’d love to change this to:

table.rb:

class SE::Server::DB::Table

end

tc_table.rb

class SE::Server::DB::TC_Table < Test::Unit::TestCase
def test_stuff
t = Class::new(Table) do # Can’t find Table!

end
end
end

In many cases this form of nesting will create more typing for me than the
normal form of nesting! OTOH, I haven’t ever had trouble with too much
namespace exposure except with top-level classes (like Queue) that cause
confusion when I forget to require something and they magically get used
instead of my classes without an (immediate) error. But this new form
doesn’t solve that problem, so I don’t see any benefit in how it behaves.

Can you give an example where this is beneficial?

Thanks,

Nathaniel

<:((><

···

Kent Dahl [mailto:kentda+news@stud.ntnu.no] wrote:

I can’t help thinking that it might be a feature, not a bug.

Class and module provide namespaces. In the old style, we
could not help but opening all the layers of modules (and
thusly their namespaces) when defining a class within them.

With the new style, we get a cleaner, neater and minimalistic
namespace, where we can include those namespaces we want.
(With the exception of nested classes, but a work-around for
that only requires a little refactoring).

So unless “class M::C” and friends is just meant to be
syntactic sugar, (phoey!) this might help us create cleaner
code, IMHO. I wouldn’t write it off as a bug just yet.

What is the motivation behind the current behavior? Is it that way because
of difficulty in implementing it differently, or for some other reason?

Thanks,

Nathaniel

<:((><

···

Yukihiro Matsumoto [mailto:matz@ruby-lang.org] wrote:

In message “Nested class/module namespace” > on 03/08/12, “Nathaniel Talbott” > nathaniel@NOSPAMtalbott.ws writes:

Why does the second case fail? It makes me not want to use
the second version, since it means I have to fully-qualify
all constants in the enclosing namespace, instead of just
using them as I usually do. I hope it’s just a bug :-/.

Unfortunately, it’s not. “class M::C” notation is not a
syntax sugar for 'module M; class C". It is something like
“M::C = Class.new”, so that the body of C definition is not
nested in the M body.

Unfortunately, it's not. "class M::C" notation is not a syntax sugar
for 'module M; class C". It is something like "M::C = Class.new", so
that the body of C definition is not nested in the M body.

Well, it has a little problem

If I read parse.y (cpath), this must work, no ?

svg% ruby -e 'class ::C; end'
-e:1: syntax error
class ::C; end
        ^
-e:1: syntax error
svg%

Guy Decoux

Nathaniel Talbott wrote:

In many cases this form of nesting will create more typing for me than the
normal form of nesting! OTOH, I haven’t ever had trouble with too much
namespace exposure except with top-level classes (like Queue) that cause
confusion when I forget to require something and they magically get used
instead of my classes without an (immediate) error. But this new form
doesn’t solve that problem, so I don’t see any benefit in how it behaves.

If this does not benefit you just don’t use the new feature. Remember the
protracted trouble with the scoping rules of Ruby’s class variables (it took
Matz a fairly long time to get things right). Ruby’s scoping are already
complicated enough (especially in combination with eval scope).

The feature you are requesting run IMHO squarely against the current
scoping rules and might push them over the edge (of being too
complicated) …

/Christoph

It makes sense to me.

You’re defining a new constant C in module M. You’re not in module M. If
you do:

module M; end
M::B = :foo
p M::B

This would be the same as doing:

module M; end
c = Class.new
M::C = c
p M::C

-austin

···

On Wed, 13 Aug 2003 08:08:19 +0900, Nathaniel Talbott wrote:

Yukihiro Matsumoto [mailto:matz@ruby-lang.org] wrote:

“Nathaniel Talbott”

Why does the second case fail? It makes me not want to use |the second
version, since it means I have to fully-qualify |all constants in the
enclosing namespace, instead of just |using them as I usually do. I
hope it’s just a bug :-/.
Unfortunately, it’s not. “class M::C” notation is not a syntax sugar
for 'module M; class C". It is something like “M::C = Class.new”, so
that the body of C definition is not nested in the M body.
What is the motivation behind the current behavior? Is it that way
because of difficulty in implementing it differently, or for some other
reason?


austin ziegler * austin@halostatue.ca * Toronto, ON, Canada
software designer * pragmatic programmer * 2003.08.12
* 21.59.17

Nathaniel Talbott wrote:

In many cases this form of nesting will create more typing for me than the
normal form of nesting!

Yes, in particular something like these three lines:

module Constants
end
include Fully::Qualified::ModuleName::Constants

…where the last line may be repeated. This is a cleaner separation of
namespaces anyway. The constants ultimately belong inside the classes
that use them, not in some arbitrary common ancestral namespace area
which saves you typing.

OTOH, I haven’t ever had trouble with too much
namespace exposure except with top-level classes (like Queue) that cause
confusion when I forget to require something and they magically get used
instead of my classes without an (immediate) error. But this new form
doesn’t solve that problem, so I don’t see any benefit in how it behaves.
Can you give an example where this is beneficial?

Replace top-level classes with constants (i.e. classes, constant
variables, modules etc) anywhere within the module hierachy, and you
have one example.

Granted, the average Ruby program isn’t of such a size that this becomes
much of an issue, but once someone writes a 10kLOC killer app in Ruby,
they will be thankful for proper namespace functionality.

If we can pop over to C++ land for a short while, the “module M;class
C;end;end” style opens a namespace scheme that is akin to “#include
<m.h>” within c.h. The new style “class M::C;include M::Constants;end”
has more in common with C++ “using namespace m;”. The latter is better
in the long run; only take in what you are sure you need.

···


([ Kent Dahl ]/)_ ~ [ Kent Dahl - Kent Dahl ]/~
))_student_/(( _d L b_/ (pre-) Master of Science in Technology )
( __õ|õ// ) )Industrial economics and technological management(
_
/ö____/ (_engineering.discipline=Computer::Technology)

i,

···

In message “Re: Nested class/module namespace” on 03/08/13, ts decoux@moulon.inra.fr writes:

Well, it has a little problem

If I read parse.y (cpath), this must work, no ?

But “::Foo = 42” is not allowed either.

						matz.

OK, I understand how it’s behaving… but why? What’s the benefit of it
behaving like that? What’s the downside of it behaving as nested classes do
now?

Nathaniel

<:((><

···

Austin Ziegler [mailto:austin@halostatue.ca] wrote:

It makes sense to me.

You’re defining a new constant C in module M. You’re not in
module M. If you do:

module M; end
M::B = :foo
p M::B

This would be the same as doing:

module M; end
c = Class.new
M::C = c
p M::C

If this does not benefit you just don’t use the new feature.

Well, I’d like the language to improve if possible… and it seems that the
new feature’s usefulness is not quite what it could be. If it can be
improved, I think that would be great, don’t you?

Remember the protracted trouble with the scoping rules of
Ruby’s class variables (it took Matz a fairly long time to
get things right). Ruby’s scoping are already complicated
enough (especially in combination with eval scope).

Really? I’ve never had any trouble with it. What causes you difficulty?

The feature you are requesting run IMHO squarely against the
current scoping rules and might push them over the edge (of being too
complicated) …

How can that be so, when there is already a construct that behaves exactly
like I want the new construct to behave? All I’m wondering is why the new
construct doesn’t behave like the old one… I still haven’t seen any
concrete examples of why the current behavior is good.

If the reason is implementation difficulty, I can understand that… but I
worry that the differences between

module M
class C
end
end

and

class M::C
end

will confuse many a newbie (and some oldies, too).

Can you help me understand why the current behavior is better?

Nathaniel

<:((><

···

Christoph R. [mailto:chr_news@gmx.net] wrote:

Hi –

Nathaniel Talbott wrote:

In many cases this form of nesting will create more typing for me than the
normal form of nesting! OTOH, I haven’t ever had trouble with too much
namespace exposure except with top-level classes (like Queue) that cause
confusion when I forget to require something and they magically get used
instead of my classes without an (immediate) error. But this new form
doesn’t solve that problem, so I don’t see any benefit in how it behaves.

If this does not benefit you just don’t use the new feature. Remember the
protracted trouble with the scoping rules of Ruby’s class variables (it took
Matz a fairly long time to get things right). Ruby’s scoping are already
complicated enough (especially in combination with eval scope).

(I’d still like to see an example of a case where benefit was
conferred :slight_smile: But anyway.)

The feature you are requesting run IMHO squarely against the current
scoping rules and might push them over the edge (of being too
complicated) …

In looking at the simplicity/complexity/consistency factors in this,
the question I keep coming back to is:

when ‘self’ is a module or class, what is the visibility of
constants defined in enclosing modules and/or classes?

What’s interesting is that even pre-1.8.0 there were at least two
answers to this, as illustrated here:

Answer 1 – nested ‘self’ sees most recently defined constants

at higher levels:

module M
X=1
class C
p self; p X # X is visible
end
end

Answer 2 – nested/inner ‘self’ does not see constants at

            higher levels:

M::C.class_eval { p self; p X } # X is not visible

END

Output =>
M::C
1
M::C
con.rb:9: uninitialized constant X (NameError)
from con.rb:9:in class_eval' from con.rb:9:in class_eval’
from con.rb:9

So whichever way the new A::b::C syntax worked, it would not be adding
to or subtracting from the overall complexity of scoping rules in
Ruby. It would simply be following one path rather than the other.

[Aside to Nathaniel: does that help at all? :-]

That alleviates my initial concern, which was that A::b::C was
introducing a whole new set of scoping rules along with the new
semantics. I admit I still raise an eyebrow at the fact that it
follows “Answer 2”, but at least it’s a matter of degree rather than
kind.

David

···

On Wed, 13 Aug 2003, Christoph R. wrote:


David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

But "::Foo = 42" is not allowed either.

Then was is this case ?

cpath : tCOLON3 cname
                    {
                        $$ = NEW_COLON3($2);
                    }

Guy Decoux

Nathaniel Talbott wrote:

In many cases this form of nesting will create more typing
for me than the normal form of nesting!

Yes, in particular something like these three lines:

module Constants
end
include Fully::Qualified::ModuleName::Constants

…where the last line may be repeated. This is a cleaner
separation of namespaces anyway. The constants ultimately
belong inside the classes that use them, not in some
arbitrary common ancestral namespace area which saves you
typing.

But that common ancestral namespace isn’t arbitrary (and it certainly isn’t
just to save me typing): it’s a logical separation of my code in to related
parts. If, when I’m doing that separation, I deem that two classes should go
in to the same module, it follows that those two pieces of code are closely
related enough to (a) not worry about namespace clashes, and (b) to need to
easily access one another’s namespace. Of course, I still have to qualify
somewhat:

module M
class C1
CONST
end
class C2
def m
p C1::CONST
end
end
end

I’ll admit that I still don’t understand what benefit this new behavior
adds, even if I were to separate out my constants in to their own
namespaces and include them. I see doing that as perhaps making this new
behavior bearable, but I don’t see any benefit in this new behavior when
working like that.

OTOH, I haven’t ever had trouble with too much
namespace exposure except with top-level classes (like Queue) that
cause confusion when I forget to require something and they
magically get used instead of my classes without an (immediate)
error. But this new form doesn’t solve that problem, so I don’t
see any benefit in how it behaves. Can you give an example where
this is beneficial?

Replace top-level classes with constants (i.e. classes, constant
variables, modules etc) anywhere within the module hierachy, and you
have one example.

Really?

module M
class C1
CONST
end
end

class C2
def m
p CONST
end
end

C2::new.m => NameError: uninitialized constant C2::CONST

Perhaps:

module M1
class C1
CONST = “a”
end
module M2
class C2
CONST = “b”
def m
p CONST
p C1::CONST
end
end
end
end

M1::M2::C2::new.m => “b”
“a”

That, too, seems to do what one would expect, though. Do you have an example
of namespace pollution?

Granted, the average Ruby program isn’t of such a size that
this becomes much of an issue, but once someone writes a
10kLOC killer app in Ruby, they will be thankful for proper
namespace functionality.

Call it personal bias, but whenever an argument is made that a problem will
only show up with a huge code base, I immediately question the validity of
the so-called “problem”. The truth is, until someone writes that 10kLOC
project, we don’t know. And this is not an issue I’ve heard is a problem for
any practicioners. As a matter of fact, as a practicioner working on a
fairly large Ruby app, I have no trouble with namespace pollution, and I do
get tired of typing “module x; class x; module x; module x; class x” ad
nauseum. I was hoping this new nesting would save me that, but it doesn’t
look like it will. C’est la vi.

If we can pop over to C++ land for a short while, the “module M;class
C;end;end” style opens a namespace scheme that is akin to “#include
<m.h>” within c.h. The new style “class M::C;include M::Constants;end”
has more in common with C++ “using namespace m;”. The latter is better
in the long run;

But I enjoy programming in Ruby and detest C++; why would I want Ruby to
emulate it? I guess, in summary, I like descendent code having easy access
to constants defined in its ancestors’ namespace. I don’t think it’s a
problem having this behavior (even in large projects), and I think it
provides a lot of benefits. Others are, of course, welcome to think
differently.

only take in what you are sure you need.

Perhaps this is where we diverge - I’d prefer to make programming easier now
(by perhaps having more than I need) rather than prematurely fix problems I
think I might have.

Nathaniel

<:((><

···

Kent Dahl [mailto:kentda+news@stud.ntnu.no] wrote:

It is good to know that it’s not completely new… I guess the current
behavior still bugs me because the first example above seems much more
common than the second example, and I’d expect this new construct to behave
like the more common construct, not the more obscure one. When I start
messing around with any of the eval’s, I’m not surprised when I’m bitten by
weird rules, scoping or not. When I use a new construct that looks almost
identical to something I’m already familiar with, I don’t expect to be
bitten by such things.

It violated my POLS, but then, I’m not matz :wink:

Nathaniel

<:((><

···

dblack@superlink.net [mailto:dblack@superlink.net] wrote:

In looking at the simplicity/complexity/consistency factors
in this, the question I keep coming back to is:

when ‘self’ is a module or class, what is the visibility of
constants defined in enclosing modules and/or classes?

What’s interesting is that even pre-1.8.0 there were at least
two answers to this, as illustrated here:

Answer 1 – nested ‘self’ sees most recently defined constants

at higher levels:

module M
X=1
class C
p self; p X # X is visible
end
end

Answer 2 – nested/inner ‘self’ does not see constants at

            higher levels:

M::C.class_eval { p self; p X } # X is not visible

END

Output =>
M::C
1
M::C
con.rb:9: uninitialized constant X (NameError)
from con.rb:9:in class_eval' from con.rb:9:in class_eval’
from con.rb:9

So whichever way the new A::b::C syntax worked, it would not
be adding to or subtracting from the overall complexity of
scoping rules in Ruby. It would simply be following one path
rather than the other.

[Aside to Nathaniel: does that help at all? :-]

[Nathaniel wrote:]
If the reason is implementation difficulty, I can understand that… but
I worry that the differences between

module M
class C
end
end

and

class M::C
end

will confuse many a newbie (and some oldies, too).

Can you help me understand why the current behavior is better?

Well put. I’ll throw my 10c in as well.

Ruby has a model where everything, including class and method definition,
happens at runtime. Thus you can have any code you like executed during
the definition of a class, e.g.

class Example
10.times { |i| puts i }
end

Another important part of Ruby’s model is that there is always a
variable called “self”, which forms part of the execution context of any
code. For instance:

class Example
def self.foo
-1
end
end

Example.foo # → -1

Now, “self” is the same thing in both the following cases:

module X
class Y
self # 1
end
end

class X::Y
self # 2
end

Finally, to the point.

Nathaniel has identified a difference between the two cases above when one
tries to access a constant, say X::C (which is not defined in the above
code).

If there is a difference, then there must be a difference in the
“execution context”. To my way of thinking, the only thing that should be
important in an execution context is the value of “self”. If that is not
the case, we need an explanation, and probably a justification. At the
moment, I think the elegance of Ruby is being stretched a bit.

Cheers,
Gavin

PS. Here’s some irb output to demonstrate the issue in case anyone needs
to see it again.

----------------- CASE 1 -----------------

module X
C = 5
class Y
puts C # prints “5”
end
end

----------------- CASE 2 -----------------

module M
C = 5
end

module M
class N
puts C # prints “5”
end
end

----------------- CASE 3 -----------------

module A
C = 5
end

class A::B
puts C # NameError: uninitialized constant A::b::C
end

------------------ END -----------------

Hi,

This would be the same as doing:

module M; end
c = Class.new
M::C = c
p M::C

OK, I understand how it’s behaving… but why? What’s the benefit of it
behaving like that? What’s the downside of it behaving as nested classes do
now?

Because it’s not nested at all. It is confusing for me, if it behaves
like nesting. Nested constant scope was introduced only for one
purpose.

module M
class C
C.foo # want to access C here.
end
end

In the cases like

class M::C
end

you don’t need dereferencing like above.

						matz.
···

In message “Re: Nested class/module namespace” on 03/08/13, “Nathaniel Talbott” nathaniel@NOSPAMtalbott.ws writes: