Attempted roadmap of future instance variables

Nathaniel Talbott wrote:

The core of the problem that class local instance variables
are trying to solve is variable shadowing (as Guy so
elegantly showed). The problem with making all variables
class local and using accessors, is that if I am shadowing an
instance variable, there is a good chance that I will shadow
the accessor as well. The superclass variable thus becomes
completely inaccessible:

pretend all instance variables are class local

class A
attr_accessor :a

 def initialize
   @a = 1
 end

end

class B < A
attr_accessor :a

 def initialize
   @a = 'a'
 end

end

There is no way for the subclass to access the superclass’s
instance variable @a now, and I don’t see a good work-around for this.

You can make the same argument in any situation like

class A
def meth

end
end

class B < A
def meth

End
end

Now there is no way that B-objects can access
A#meth.

Generally I am not too bother by this behavior*
however I’d be willing to use your argument as
an argument against “singleton class”
localness:-)

/Christoph

  • Okay, actually it makes me wander why I should
    worry about instance variables name clashes but
    should continue to live method name clashes?

Hmm… Well, you actually prove my point. Transaction::Simple is coming before
A in the first case, and after B in the second. Quite different form the
ordinary mixin-in. Yet you’ll have to excuse my while I scream
“Arrrrgggghhh!!!” b/c it is even more complex than I realized. So, yes, it is
techinaclly a mix-in per se, but since it is a mix-in on the sinlgeton and
not the class itself, it is more akin to a singleton. Or at least one would
think! But it seems it is actually more akin to just redefining/restating the
class:

module M
def happy; print “M”; super if defined?(super); end
end

class MC
def happy; print “M”; super if defined?(super); end
end

class S < MC
def happy; print “x”; super if defined?(super); end
end

class I
include M
def happy; print “x”; super if defined?(super); end
end

class E
def happy; print “x”; super if defined?(super); end
end

class C
def happy; print “x”; super if defined?(super); end
end

s = S.new

a = I.new

b = E.new
b.extend(M)

c = C.new
def c.happy; print “M”; super if defined?(super); end

print "superclass: "; s.happy
print “\t”, class << s; self; end.ancestors.inspect; puts

print " include: "; a.happy
print “\t”, class << a; self; end.ancestors.inspect; puts

print " extend: "; b.happy
print “\t”, class << b; self; end.ancestors.inspect; puts

print " singleton: "; c.happy
print “\t”, class << c; self; end.ancestors.inspect; puts

This produces:

superclass: xM [S, MC, Object, Kernel]
include: xM [I, M, Object, Kernel]
extend: M [M, E, Object, Kernel]
singleton: Mx [C, Object, Kernel]

Notice in the singleton that “M” is invisible, but it does in fact exist
anonymously before C.

I have to say, I’m actually very disturbed to see the x missing in the extend.
Where the heck did it go? Extending just redefined the happy method
altogether! That’s not something I would call “extend”.

T.

···

On Friday 05 December 2003 07:02 pm, Austin Ziegler wrote:

It is a mix-in.

class A; end
class B; include Transaction::Simple; end
x = A.new
y = B.new
x.extend(Transaction::Simple)
class << x; self; end.ancestors
=> [Transaction::Simple, A, Object, Kernel]
class << y; self; end.ancestors
=> [B, Transaction::Simple, Object, Kernel]

It’s just that #extend mixes into the object’s singleton class.

The core of the problem that class local instance variables are trying
to solve is variable shadowing (as Guy so elegantly showed). The
problem with making all variables class local and using accessors, is
that if I am shadowing an instance variable, there is a good chance
that I will shadow the accessor as well. The superclass variable thus
becomes completely inaccessible:

I see what you’re saying, but I would think you would know that you were doing
this if you were subclassing, just as you know it when you want to redefine a
method of the superclass.

pretend all instance variables are class local

class A
attr_accessor :a

 def initialize
   @a = 1
 end

end

class B < A
attr_accessor :a

 def initialize
   @a = 'a'
 end

end

There is no way for the subclass to access the superclass’s instance
variable @a now, and I don’t see a good work-around for this.

So it would seem to me, that in fact, this is an example of one actually
wanting to redefine the accessor to cut the scope off at the subclass, so
that @a of the superclass could no longer be accessed. A purposeful act.

I wonder if a better solution for the issue doesn’t lie in the idea of
namespaces. Basically, library writers want to be able to say that
@checkpoint is part of the Transaction::Simple namespace, and
occasionally library users want to say that they want to read or write
@checkpoint in the Transaction::Simple namespace. If there was a way to
explicitly limit the namespace of an instance variable to a given Class
or Module, and a way to access an instance variable in an explicit
Class or Module, that would be quite handy. The key is that all data
remains accessible all the time, to everyone. We just allow folks the
ability to shadow.

You can always just augment the superclass/module to give you the access you
need:

module Transaction::Simple
def simple_checkpoint
@checkpoint
end
end

T.

···

On Friday 05 December 2003 07:40 pm, Nathaniel Talbott wrote:

problem with making all variables class local and using accessors, is
that if I am shadowing an instance variable, there is a good chance
that I will shadow the accessor as well.

Well, yes and no.

If you define accessors probably you'll document these accessors and the
problem is solved by the documentation.

Guy Decoux

T. Onoma wrote:

A word of update on this idea. I have been writing my lastest code as if
this
were already fact, in order to get a realistic feel for what it would be
like. It works fine except for one signifficant age old problem: the
ambiguity between methods and local variables. Because instance variables
would be local to their class, one would then uses writer methods from
mixins
and subclasses and so forth. Unfortunately you always have to use self as
a
reciever on these to prevent them from being local variables. The age old
ambigutiy rears its head again. Quick ex-

class K
attr_writer :h
end
class Q < K
def hi(x)
self.h = “Hello, #{x}” # must use self
end
end

Honestly, I would prefer using % for local variables and kill this
ambiguity
once and for all!

This is main the reason why I think that instance variables
shouldn’t be local to singleton classes. To access instance
from the non-singleton super class you would need to write
an attribute accessor valid for all instances. In general
you would chose the accessibility to be private - as in

class A
def intialize
@foo = “foo”
end
private
attr_accessor :foo
end

a = A.new

def a.bar
# the syntactic hind that “foo” is not a local variable
# conflicts with the privacy of A#foo=
self.foo = “bar” # raises NoMethodError - private
end

The only way around this to not use a standard attribute writer

class A
def intialize
@foo = “foo”
end
private
attr_reader :foo
# need to use a javaish setter:-(
def set_foo(rhs)
@foo = rhs
end
end

a = A.new

def a.bar
set_foo(“bar”)
end

or use to a protected or public accessibility for A#foo=.

Another possibility - you can consider this to be RCR for
Rite (independently of the “class local variable stuff”) - is that
“private” methods should be callable if method receiver is an
explicit self (currently only implicit self’s are allowed).

class A
def bar
self.foo # this SHOULD NOT RAISE a NoMethodError
end
private
def foo; end
end

/Christoph

Oh, not that it matters but I got that wrong. Tied for first
with doing nothing. @_ way down at third :slight_smile:

David

···

On Sat, 6 Dec 2003, David A. Black wrote:

Hi –

On Sat, 6 Dec 2003, Christoph wrote:

Yukihiro Matsumoto wrote:

That would be interesting alternative idea. I think it’s
matter of how much compatibility we would preserve.

That is obviously your call to make. Personally I sort of prefer
Tom’s solution (it is David’s second choice if I remember
correctly).

Tied for second with doing nothing :slight_smile:


David A. Black
dblack@wobblini.net

David A. Black wrote:

Is this second ‘non’ perhaps not supposed to be there? If it
is supposed to be there, then can you give a couple of
examples to clarify what you mean? :slight_smile:

Probably I should have written “sometimes-non”:slight_smile:

“Tom complaint” example:

···

class A
def initialize
@var = id.to_s
end
def inspect
@var
end
private
def var
@var
end
def var=(rhs)
@var = rhs
end
end

p a = A.new # “12345678”

class << a
def inspect
“singleton a” + var
end
end

p a # “singleton a 12345678”


“Christoph complaint” example:

class A
def initialize
@var = id.to_s
end
def inspect
@var
end
end

p a = A.new # “12345678”

class << a
def inspect
"singleton a " + @var
end
end

p a # “singleton a 12345678”

/Christoph

In this case it is trivial to alias the super-class method if I need
continued access to the super-classes implementation. I don’t know of a
way that could be done for instance variables. More importantly,
though, I think instance variables are fundamentally a different
construct than methods. I’m having difficulty precisely delineating the
differences (internal vs. external?), but I just don’t think you can
compare the potential problems from method overriding with those of
instance variable shadowing. They certainly have commonalities, just as
apples and oranges are both fruit, but they have quite different cores.

I still think namespaces are a good place to look for the answer to
class local instance variables (and perhaps class local methods, too).

Nathaniel

<:((><

···

On Dec 5, 2003, at 14:18, Christoph wrote:

There is no way for the subclass to access the superclass’s
instance variable @a now, and I don’t see a good work-around for this.

You can make the same argument in any situation like

class A
def meth

end
end

class B < A
def meth

End
end

Now there is no way that B-objects can access
A#meth.

The core of the problem that class local instance variables are trying
to solve is variable shadowing (as Guy so elegantly showed). The
problem with making all variables class local and using accessors, is
that if I am shadowing an instance variable, there is a good chance
that I will shadow the accessor as well. The superclass variable thus
becomes completely inaccessible:

I see what you’re saying, but I would think you would know that you
were doing
this if you were subclassing, just as you know it when you want to
redefine a
method of the superclass.

Then why mess with class local instance variables at all? If I already
know that I’m shadowing, then obviously I would pick a different name
and NOT shadow. I think the issue is when one is using a library and
doesn’t know what instance variables it uses internally. I agree, it’s
a shaky premise that one would not know this (or figure it out real
fast), and thus I tend to think the premise that Ruby needs class local
variables is rather shaky itself. The only real reason for it is when a
library writer wants to be able to use a common variable name (like
@message or something) and doesn’t want to cause those using his
library name clashes (and doesn’t want to use ugly names like
@message.

pretend all instance variables are class local

class A
attr_accessor :a

 def initialize
   @a = 1
 end

end

class B < A
attr_accessor :a

 def initialize
   @a = 'a'
 end

end

There is no way for the subclass to access the superclass’s instance
variable @a now, and I don’t see a good work-around for this.

So it would seem to me, that in fact, this is an example of one
actually
wanting to redefine the accessor to cut the scope off at the subclass,
so
that @a of the superclass could no longer be accessed. A purposeful
act.

Er, no. Not purposeful at all. I just required class A from who knows
what library, and just want to subclass it and get going. I have no
earthly idea that it uses the @a instance variable, and @a is a great
variable name for the code I’m writing, so I use it, not realizing that
I’m shadowing A’s @a. Then, later, I realize that I need to access @a
in A, and that I have to rename my variable to do so (weren’t we doing
this to prevent having to rename due to name clashes?). Or, worse, A
depends on self.a referring to its version of @a, and thus is broken by
my re-defining of attr_accessor :a.

Ick.

I wonder if a better solution for the issue doesn’t lie in the idea of
namespaces. Basically, library writers want to be able to say that
@checkpoint is part of the Transaction::Simple namespace, and
occasionally library users want to say that they want to read or write
@checkpoint in the Transaction::Simple namespace. If there was a way
to
explicitly limit the namespace of an instance variable to a given
Class
or Module, and a way to access an instance variable in an explicit
Class or Module, that would be quite handy. The key is that all data
remains accessible all the time, to everyone. We just allow folks the
ability to shadow.

You can always just augment the superclass/module to give you the
access you
need:

module Transaction::Simple
def simple_checkpoint
@checkpoint
end
end

Maybe it’s just me, but I do NOT want to have to re-open a third-party
library to be able to access data that should be (and is, in current
Ruby) already accessible to me.

Nathaniel

<:((><

···

On Dec 5, 2003, at 14:47, T. Onoma wrote:

On Friday 05 December 2003 07:40 pm, Nathaniel Talbott wrote:

Can anyone take a look at this and tell me what the hek is happening with
extend? (as in Pickaxe Chapter 19)

ruby-talk:87344

I thought I finally understood, but now I’m just confused again.

Thanks,
T.

Copy of 87344 follows:

···

On Friday 05 December 2003 08:26 pm, T. Onoma wrote:

On Friday 05 December 2003 07:02 pm, Austin Ziegler wrote:

It is a mix-in.

class A; end
class B; include Transaction::Simple; end
x = A.new
y = B.new
x.extend(Transaction::Simple)
class << x; self; end.ancestors
=> [Transaction::Simple, A, Object, Kernel]
class << y; self; end.ancestors
=> [B, Transaction::Simple, Object, Kernel]

It’s just that #extend mixes into the object’s singleton class.

Hmm… Well, you actually prove my point. Transaction::Simple is coming
before A in the first case, and after B in the second. Quite different form
the ordinary mixin-in. Yet you’ll have to excuse my while I scream
“Arrrrgggghhh!!!” b/c it is even more complex than I realized. So, yes, it
is techinaclly a mix-in per se, but since it is a mix-in on the sinlgeton
and not the class itself, it is more akin to a singleton. Or at least one
would think! But it seems it is actually more akin to just
redefining/restating the class:

module M
def happy; print “M”; super if defined?(super); end
end

class MC
def happy; print “M”; super if defined?(super); end
end

class S < MC
def happy; print “x”; super if defined?(super); end
end

class I
include M
def happy; print “x”; super if defined?(super); end
end

class E
def happy; print “x”; super if defined?(super); end
end

class C
def happy; print “x”; super if defined?(super); end
end

s = S.new

a = I.new

b = E.new
b.extend(M)

c = C.new
def c.happy; print “M”; super if defined?(super); end

print "superclass: "; s.happy
print “\t”, class << s; self; end.ancestors.inspect; puts

print " include: "; a.happy
print “\t”, class << a; self; end.ancestors.inspect; puts

print " extend: "; b.happy
print “\t”, class << b; self; end.ancestors.inspect; puts

print " singleton: "; c.happy
print “\t”, class << c; self; end.ancestors.inspect; puts

This produces:

superclass: xM [S, MC, Object, Kernel]
include: xM [I, M, Object, Kernel]
extend: M [M, E, Object, Kernel]
singleton: Mx [C, Object, Kernel]

Notice in the singleton that “M” is invisible, but it does in fact exist
anonymously before C.

I have to say, I’m actually very disturbed to see the x missing in the
extend. Where the heck did it go? Extending just redefined the happy method
altogether! That’s not something I would call “extend”.

T.

I wrote:

“Tom complaint” example:

“Tom compliant” example:

/Christoph

Nathaniel Talbott wrote:

In this case it is trivial to alias the super-class method if
I need continued access to the super-classes implementation.
I don’t know of a way that could be done for instance
variables. More importantly, though, I think instance
variables are fundamentally a different construct than
methods. I’m having difficulty precisely delineating the
differences (internal vs. external?), but I just don’t think
you can compare the potential problems from method overriding
with those of instance variable shadowing. They certainly
have commonalities, just as apples and oranges are both
fruit, but they have quite different cores.

I am not sure if this philosophical difference
is really so deep - in fact some languages, the
most widely used is probably JavaScript (okay,
maybe that’s an argument against my point:-)
don’t distinguish between data and methods
at all.

I still think namespaces are a good place to look for the
answer to class local instance variables (and perhaps class
local methods, too).

Maybe, but this almost feels like an overkill to me?

/Christoph

Then why mess with class local instance variables at all? If I already
know that I’m shadowing, then obviously I would pick a different name
and NOT shadow. I think the issue is when one is using a library and
doesn’t know what instance variables it uses internally. I agree, it’s
a shaky premise that one would not know this (or figure it out real
fast), and thus I tend to think the premise that Ruby needs class local
variables is rather shaky itself. The only real reason for it is when a
library writer wants to be able to use a common variable name (like
@message or something) and doesn’t want to cause those using his
library name clashes (and doesn’t want to use ugly names like
@message.

The concept of local instance variable actually does make a lot of sense when
you think about it in a more tangebale way. The idea can be most clearly
understood, I think, by way of analogy: Local instance varibales are to class
instances as local variables are to methods. If you consider this poignant
analogy carefully I think you will see why they are desirable.

module Transaction::Simple
def simple_checkpoint
@checkpoint
end
end

Maybe it’s just me, but I do NOT want to have to re-open a third-party
library to be able to access data that should be (and is, in current
Ruby) already accessible to me.

Instance varaibles really aren’t intended to be open like this. It prevents
the library builder from clearly defining the interface by which one is to
generally use the library. For a particular case, as you suggest, in which
one does in fact need access to an instance variable that is not provided
through an accessor method, it is likely that the library maintainer would
want to know about it, so they could incorporate that access. One can of
course just take issue with the immediate restraint this causes, but in the
end it actually improves code and its reusability.

T.

···

On Friday 05 December 2003 09:05 pm, Nathaniel Talbott wrote:

Can anyone take a look at this and tell me what the hek is happening with
extend? (as in Pickaxe Chapter 19)

Well, I've not understood your problem.

To simplify : by default (because it's possible to redefine what do ruby)
an extend can be seen as an include in the singleton class.

For your example

c = C.new
def c.happy; print "M"; super if defined?(super); end

[...]

singleton: Mx [C, Object, Kernel]

Notice in the singleton that "M" is invisible, but it does in fact exist
anonymously before C.

M is not invisible : it just don't exist. You have just defined a method
#happy for `c', like the module M define a method #happy

Guy Decoux

Hi –

Nathaniel Talbott wrote:

In this case it is trivial to alias the super-class method if
I need continued access to the super-classes implementation.
I don’t know of a way that could be done for instance
variables. More importantly, though, I think instance
variables are fundamentally a different construct than
methods. I’m having difficulty precisely delineating the
differences (internal vs. external?), but I just don’t think
you can compare the potential problems from method overriding
with those of instance variable shadowing. They certainly
have commonalities, just as apples and oranges are both
fruit, but they have quite different cores.

I am not sure if this philosophical difference
is really so deep - in fact some languages, the
most widely used is probably JavaScript (okay,
maybe that’s an argument against my point:-)
don’t distinguish between data and methods
at all.

But at a non-philosophical level, there’s a big difference in Ruby
between an instance variable and a method. Nathaniel is right that in
discussing how to design and write Ruby classes, one can’t assume that
if X is true with regard to instance variables, then X.gsub(“instance
variable”, “method”) is true about methods :slight_smile: Instance variables may
assist you in creating a “uniform access” environment for users of
your class (actually Ruby really does that for you, since everything
is a method call and “attributes” don’t exist as separate language
constructs), but they themselves do not play the same role as
methods. I think that’s what he meant.

David

···

On Sat, 6 Dec 2003, Christoph wrote:


David A. Black
dblack@wobblini.net

The concept of local instance variable actually does make a lot of
sense when
you think about it in a more tangebale way. The idea can be most
clearly
understood, I think, by way of analogy: Local instance varibales are
to class
instances as local variables are to methods. If you consider this
poignant
analogy carefully I think you will see why they are desirable.

OK, lets work that out a bit more:

  • When I use a local variable I’m saying, “Limit the scope to this
    method”.
  • When I use an instance variable I’m saying, “Limit the scope to this
    instance”.

So if I apply your analogy (instance variables are to instances of
classes as local variables are to methods), all instance variables
should be accessible to all descendants of a given class, just as all
local variables are available to all scopes enclosed in a method
(except blocks, but that’ll be fixed in 2.0.

I think you just made my argument for me :wink:

module Transaction::Simple
def simple_checkpoint
@checkpoint
end
end

Maybe it’s just me, but I do NOT want to have to re-open a third-party
library to be able to access data that should be (and is, in current
Ruby) already accessible to me.

Instance varaibles really aren’t intended to be open like this.

Where did you read that? I wasn’t aware that instance variables had a
stated intent.

It prevents
the library builder from clearly defining the interface by which one
is to
generally use the library. For a particular case, as you suggest, in
which
one does in fact need access to an instance variable that is not
provided
through an accessor method, it is likely that the library maintainer
would
want to know about it, so they could incorporate that access. One can
of
course just take issue with the immediate restraint this causes, but
in the
end it actually improves code and its reusability.

“Prevents” seems like a pretty strong word. As a matter of fact, I
don’t think instance variables affect one iota a library writer’s
ability to clearly define the interface by which their library should
generally be used. And yes, it is good to give feedback to library
writers, but what if a library writer disagrees with my perceived need
to access the internals of their library? Currently I can deal with
that fairly cleanly by simply subclassing, and both I and the library
writer are happy. With class local instance variables, either I have an
ugly hack, or I pester the library writer until he adds an interface to
his library that he really doesn’t like. So… do class local instance
variables PREVENT a library writer from defining an interface that he
likes for his library? No, but he might end up having to support more
special cases than he does under current Ruby.

Oh, and I don’t see much point in digging in to the obvious problems
that occur when you have a slow and/or nonexistent library maintainer,
other than to say it’s one more reason one shouldn’t argue that a
feature is good because, “it forces you to get the maintainer to
incorporate what you need.” Sort of like saying using proprietary
software is good because, “You don’t end up with a bunch of people
fixing their own problems.”

Just my $0.02,

Nathaniel

<:((><

···

On Dec 5, 2003, at 15:44, T. Onoma wrote:

Can anyone take a look at this and tell me what the hek is happening
with T> extend? (as in Pickaxe Chapter 19)

Well, I’ve not understood your problem.

Thanks for responding, Guy. I’ll explain better.

To simplify : by default (because it’s possible to redefine what do ruby)
an extend can be seen as an include in the singleton class.

“seen as an include in the singleton class”: That’s what confuses me. I can
“see” this by combing the diagrams on Pickaxe pg. 246 and 247, no problem.
But it dosen’t explain to me why x isn’t printed in my extend example.

(I wish there way a way I could draw a picture of it here)

singleton: Mx [C, Object, Kernel]

Notice in the singleton that “M” is invisible, but it does in fact exist
anonymously before C.

M is not invisible : it just don’t exist. You have just defined a method
#happy for `c’, like the module M define a method #happy

Indeed I have defined that method, but it is put in a an unnamed class, i.e.
the singleton class. (Pickaxe Figure 19.2 on page 246, has a diagram of it.)
I’m simply refering to it as M, analogous to the rest of the examples. This
is why M is printed before x and dosen’t simply replace x.

T.

[NOTE: I figured it out and it may be a bug in Ruby. At the the very least it
is a “bugaboo”. I’ll explain in next message -T.]

···

On Saturday 06 December 2003 04:31 pm, ts wrote:

Take a look at this:

class MC
  def happy; print "C"; super if defined?(super); end
end

module M
  def happy; print "M"; super if defined?(super); end
end

class S < MC
  include M
  def happy; print "x"; super if defined?(super); end
end

s = S.new

print "superclass: "; s.happy
print "\t", class << s; self; end.ancestors.inspect; puts

Outputs:

superclass: xM  [S, M, MC, Object, Kernel]

Now look at this:

class MC
  def happy; print "C"; super if defined?(super); end
end

module M
  def happy; print "M"; super; end
end

class S < MC
  include M
  def happy; print "x"; super if defined?(super); end
end

s = S.new

print "superclass: "; s.happy
print "\t", class << s; self; end.ancestors.inspect; puts

Outputs:

superclass: xMC  [S, M, MC, Object, Kernel]

The last is what one would expect. Seems that defined?(super) dosen’t work
with mixins even though calling super does. What do you make of that? Bug?

T.

So if I apply your analogy (instance variables are to instances of
classes as local variables are to methods), all instance variables
should be accessible to all descendants of a given class, just as all
local variables are available to all scopes enclosed in a method
(except blocks, but that’ll be fixed in 2.0.

I think you just made my argument for me :wink:

I suppose I should have spelled it out, so that you would see the actual
analogy rather that contrive it to fit your argument. These “scopes enclosed
in a method” are not analogous as they have no inheritability, as do classes
and their methods. Local variables prevent name clashing between methods,
even when they are “inherited”:

class A
def x
a = “A”
end
end

class B < A
def x
a = “B”
super
a
end
end

b = B.new
b.x # => “B”

Just as class B has inherited the superclass A, so too has the method B#x
inherited the functionaity of A#x by using super. Yet their local namespace
remains distinct. The result of b.x is not “A”, but rather “B”. While it is
quite possible to program without local variables altogther, it is much more
advantages to use them for the seperation of scope they provide. The same is
true for class local instance variables.

So you see, I have certainly NOT made your argument for you, but to the
contrary. You did not consider the analogy carefully. [ Not that I’m one to
talk, mind you :wink: ]

“Prevents” seems like a pretty strong word. As a matter of fact, I
don’t think instance variables affect one iota a library writer’s
ability to clearly define the interface by which their library should
generally be used. And yes, it is good to give feedback to library
writers, but what if a library writer disagrees with my perceived need
to access the internals of their library? Currently I can deal with
that fairly cleanly by simply subclassing, and both I and the library
writer are happy. With class local instance variables, either I have an
ugly hack, or I pester the library writer until he adds an interface to
his library that he really doesn’t like. So… do class local instance
variables PREVENT a library writer from defining an interface that he
likes for his library? No, but he might end up having to support more
special cases than he does under current Ruby.

Okay, first of all, the whole “ugly hack” thing about “re-opening a library
class” has gots to go. That idea is simply way off base. This is NOT an ugly
hack. It is done regularly and with good reason. I for instance almost always
“re-open” NilClass to add a few extra methods. This is extremely clean, and
as long as I have done so with careful consideration to the context I am
applying it, works beautifully, and is why we have the functionality in the
first place. An “ugly hack” would be me trying to subclass NilClass and
telling every other class that I require to use MyNilClass it its place.

Oh, and I don’t see much point in digging in to the obvious problems
that occur when you have a slow and/or nonexistent library maintainer,
other than to say it’s one more reason one shouldn’t argue that a
feature is good because, “it forces you to get the maintainer to
incorporate what you need.” Sort of like saying using proprietary
software is good because, “You don’t end up with a bunch of people
fixing their own problems.”

Argue? You suggest, and if the maintainer says “no”, then they have their
reasons. If they don’t exist, then why care what you do to their (who’s?)
library. And no one’s forcing anyone. That you might discover a local
instance variable that could be useful to the “outside” is simply something a
library maintatiner would normally want to know about. Furthermore it means
you must really know that library pretty dang well, so clashing method names
is about the most unlikely occurance you would ever face. In fact, it just
doesn’t happen. No one uses a library class wearing a blind fold.

T.

···

On Friday 05 December 2003 11:24 pm, Nathaniel Talbott wrote:

    superclass: xM [S, M, MC, Object, Kernel]

svg% cat b.rb
#!./ruby -v
class MC
   def happy; print "C"; super if defined?(super); end
end

module M
   def happy; print "M"; super if defined?(super); end
end

class S < MC
   include M
   def happy; print "x"; super if defined?(super); end
end

s = S.new

print "superclass: "; s.happy
print "\t", class << s; self; end.ancestors.inspect; puts
svg%

svg% b.rb
ruby 1.8.1 (2003-11-30) [i686-linux]
superclass: xMC [S, M, MC, Object, Kernel]
svg%

Guy Decoux