Class instance variable idiom

P

Perry Smith

I am using this technique for class instance variables:

class << self
def set_foo(s)
@foo = s
end
alias :foo= :set_foo

def foo
@foo
end
end

Then to reference foo from an instance of the class (or subclass), I do:

self.class.foo

Is there a cleaner way, in particular for the reference of the class
instance variable, to do this?

Thank you,
pedz
 
R

Robert Klemme

I am using this technique for class instance variables:

class << self
def set_foo(s)
@foo = s
end
alias :foo= :set_foo

def foo
@foo
end
end

Then to reference foo from an instance of the class (or subclass), I do:

self.class.foo

Is there a cleaner way, in particular for the reference of the class
instance variable, to do this?

class << self
attr_accessor :foo
end

robert
 
D

David A. Black

Hi --

I am using this technique for class instance variables:

class << self
def set_foo(s)
@foo = s
end
alias :foo= :set_foo

def foo
@foo
end
end

Then to reference foo from an instance of the class (or subclass), I do:

self.class.foo

Is there a cleaner way, in particular for the reference of the class
instance variable, to do this?

Yes:

class C
class << self
attr_accessor :foo
end
end


David

--
Upcoming training from Ruby Power and Light, LLC:
* Intro to Ruby on Rails, Edison, NJ, October 23-26
* Advancing with Rails, Edison, NJ, November 6-9
Both taught by David A. Black.
See http://www.rubypal.com for more info!
 
D

David A. Black

Hi --

Thanks!

Do I still do the self.class.foo to access it?

Yes. The call to attr_accessor will create singleton methods for use
by the class object Foo.


David

--
Upcoming training from Ruby Power and Light, LLC:
* Intro to Ruby on Rails, Edison, NJ, October 23-26
* Advancing with Rails, Edison, NJ, November 6-9
Both taught by David A. Black.
See http://www.rubypal.com for more info!
 
B

Brian Adkins

I am using this technique for class instance variables:

class << self
def set_foo(s)
@foo = s
end
alias :foo= :set_foo

def foo
@foo
end
end

Then to reference foo from an instance of the class (or subclass), I do:

self.class.foo

Is there a cleaner way, in particular for the reference of the class
instance variable, to do this?

Just out of curiosity, why do you want a "class instance variable"
instead of a class variable?
 
R

Robert Klemme

2007/10/18 said:
Just out of curiosity, why do you want a "class instance variable"
instead of a class variable?

Probably because class variables have @@various issues as has
discusses before. I would also recommend to not use them.

Kind regards

robert
 
B

Brian Adkins

Probably because class variables have @@various issues as has
discusses before. I would also recommend to not use them.

What issues have you experienced with them to cause you to not
recommend them? I rarely have a need for either class variables or
"class instance variables", but I've yet to experience any problems
with class variables.

I think they have different purposes, strengths and weaknesses, but I
wouldn't recommend not using class variables, so I'm curious if I'm
missing some problem with them.
 
D

David A. Black

Hi --

What issues have you experienced with them to cause you to not
recommend them? I rarely have a need for either class variables or
"class instance variables", but I've yet to experience any problems
with class variables.

I think they have different purposes, strengths and weaknesses, but I
wouldn't recommend not using class variables, so I'm curious if I'm
missing some problem with them.

I'm on record as saying that class variables are the thing I dislike
most about Ruby, so I'll try to explain why.

They break encapsulation. They are visible to a weird assortment of
objects: class C, instances of C, class D < C, instances of D... all
the same variable. This cross-section of objects doesn't have anything
in common except that they can all see each other's class variables.

The prefix @@ makes it appear that they have some connection or
kinship with instance variables. Actually, they're almost the
opposite. Instance variables represent state on a strictly per-object
basis. Class variables cut across many different objects and scopes.
I would prefer them to look like $$this, since they're really a
kind of restricted global variable rather than an extended instance
variable.

The worst thing about them, in my view, is the amount of confusion
they have caused. The fact that there is something called a "class
variable" -- and that it looks vaguely like an instance variable --
has been a huge obstacle for people trying to get a grasp on the idea
that classes are objects and can, via *instance* variable, have their
own state. Class variables throw a big shadow over that otherwise very
consistent and lucid state of things. I've seen this happen again and
again for seven years.

In Ruby > 1.8, class variables are going to be somewhat more strictly
per-class. That's a mixed blessing. They're going to come closer to
representing a class's state, but then the question will arise: why
have both that *and* instance variables of classes? It's not
impossible to answer that, but it's not a bad question.

That sums up my views. Just so you know: I love Ruby madly :) This is
one of the very few areas where I dissent strongly from the way it's
designed.


David

--
Upcoming training from Ruby Power and Light, LLC:
* Intro to Ruby on Rails, Edison, NJ, October 23-26
* Advancing with Rails, Edison, NJ, November 6-9
Both taught by David A. Black.
See http://www.rubypal.com for more info!
 
R

Rick DeNatale

I'm on record as saying that class variables are the thing I dislike
most about Ruby, so I'll try to explain why.

They break encapsulation. They are visible to a weird assortment of
objects: class C, instances of C, class D < C, instances of D... all
the same variable. This cross-section of objects doesn't have anything
in common except that they can all see each other's class variables.
And even that is squirrely. Visibility depends on sequence of
class A
@@x = "A"

def self.show_x
@@x
end
end
A.show_x # => "A"

class B < A
end
B.show_x # => "A"

class B
@@x = "B" # !> already initialized class variable @@x
end
B.show_x # => "B"
A.show_x # => "B"

class C
end

class D < C
@@x = "D"
def self.show_x
@@x # !> class variable @@x of C is overridden by D
end
end
D.show_x # => "D"

class C
@@x = "C"
def self.show_x
@@x
end
end
D.show_x # => "D"
C.show_x # => "C"

class D
@@x = "Blorp" # !> class variable @@x of C is overridden by D
end
D.show_x # => "Blorp"
C.show_x # => "C"
That sums up my views. Just so you know: I love Ruby madly :) This is
one of the very few areas where I dissent strongly from the way it's
designed.

Amen, brother!
 
G

Gary Wright

In Ruby > 1.8, class variables are going to be somewhat more strictly
per-class. That's a mixed blessing. They're going to come closer to
representing a class's state, but then the question will arise: why
have both that *and* instance variables of classes? It's not
impossible to answer that, but it's not a bad question.

My gut says that code that utilizes class variables can always be
refactored to use class instance variables and perhaps some accessor
methods and the result will be equal or better to the original
class variable code.

I say ditch class variables all together.

Gary Wright
 
J

John Joyce

Well, I have to agree there are some odd things about Ruby's class
variables, and they're not terribly useful most of the time, but in
the cases where they are useful, they are useful.
Unless you need to count the number of instantiations of a class, I
can't imagine what else to use them for.
But perhaps this kind of counter of class instantiations ( minus GC'd
instances ) should be built-in to all Ruby classes and accessible via
a method. Or at least the ability to create that count without using
class variables proper.
Then again, is it that useful?
It is when it is needed.

I do think all the books should generally make a note that most folks
will rarely need or want to use class variables.
Then each book should explicitly state that instance vars are what
you will normally want to use day to day.

In the case of subclasses and so forth, choosing where you want to
have a class variable is a design issue.
While OOP is easy to learn and understand, it is not easy to become
good at designing classes. I know. I'm still not good at it.
 
A

ara.t.howard

I'm on record as saying that class variables are the thing I dislike
most about Ruby, so I'll try to explain why.

They break encapsulation.

i honestly don't think they do - inheritance breaks encapsulation.
for example

class A
CONST = 42

class << self
def shared() 42.0 end
end
end

class B < A
end

p B::CONST
p B::shared

class vars are exactly like this - only with state that happens to be
resettable. i don't see anything particular about the way class vars
behave that is different from constants or singleton (note the
*single* in singleton methods that can be called on multiple
objects!). it's the concept of inheritance that breaks
encapsulation, this is of course generally accepted by oop geeks, and
ruby doesn't change this wart on oop's many graces.
They are visible to a weird assortment of
objects: class C, instances of C, class D < C, instances of D... all
the same variable. This cross-section of objects doesn't have anything
in common except that they can all see each other's class variables.

and constants and singleton methods.... of course class singleton
methods, in an instance context, require a 'self.class' prefix to
invoke while constants do not but this is not encapsulation - it's
the breaking of it - instances *should* be allowed to access the
unfettered methods of their class because requiring the 'self.class'
prefix also makes them *public* which, of course, seriously breaks
encapsulation.

in point of fact inheritance is *designed* to break encapsulation so
that we can reuse code and remain sane. child classes, mixins,
friend classes et al are all about tearing down the barriers between
bits of code so we don't descend.into.dot.dot.dot.dot.hell and
develop carpal tunnel from all that code pasting
The prefix @@ makes it appear that they have some connection or
kinship with instance variables. Actually, they're almost the
opposite. Instance variables represent state on a strictly per-object
basis. Class variables cut across many different objects and scopes.
I would prefer them to look like $$this, since they're really a
kind of restricted global variable rather than an extended instance
variable.

i can see that. still, they *are* associated with an instance - an
instance of a class hierarchy. i realize people don't generally seem
to grasp this concept though. the idea of switching syntax is a good
one. i hate $ because it looks like perl and perl is clearly evil.
i'm not sure what would be better though.
The worst thing about them, in my view, is the amount of confusion
they have caused. The fact that there is something called a "class
variable" -- and that it looks vaguely like an instance variable --
has been a huge obstacle for people trying to get a grasp on the idea
that classes are objects and can, via *instance* variable, have their
own state. Class variables throw a big shadow over that otherwise very
consistent and lucid state of things. I've seen this happen again and
again for seven years.

absolutely correct.
In Ruby > 1.8, class variables are going to be somewhat more strictly
per-class. That's a mixed blessing. They're going to come closer to
representing a class's state, but then the question will arise: why
have both that *and* instance variables of classes? It's not
impossible to answer that, but it's not a bad question.

That sums up my views. Just so you know: I love Ruby madly :) This is
one of the very few areas where I dissent strongly from the way it's
designed.

yeah i see all that. still, i've deigned quite a few ruby classes
and i can assure people that they will miss them when they are gone/
limited. the reason, curiously, is that classes do not have an
initialize method/hook. let me explain: let's say you want to do
something quite reasonable like so

class Parser

def self.bufsize(*value)
value.size == 0 ? @@bufsize : self.bufsize=(value.first)
end

def self.bufsize=(value)
@@bufsize = Integer value
end

bufsize 4242

def initialize options = {}
@bufsize = options[:bufsize] || @@bufsize
end

end

Parser.new


that is to say you want to grab default initialization options from
your class and you want users to be able to configure the class such
that it stamps out instances with those defaults. it's really nice
if people can configure via the environment or like so

Parser.bufsize 42

as i'm sure we can all agree. obviously constants aren't really in
order unless you want to use hackery like

class Parser

BUFSIZE = [ :value ]

def self.bufsize=(value) BUFSIZE[0] = Integer value end

...

blechh!

i can hear people thinking "you need instance variables!" sure, if
you want to write totally non-reusable code. why? because if i do

class Parser
def self.bufsize(*value)
value.size == 0 ? @bufsize : self.bufsize=(value.first)
end

def self.bufsize=(value)
@bufsize = Integer value
end

bufsize 4242

def initialize options = {}
@bufsize = options[:bufsize] || self.class.bufsize
end
end

Parser.new

then, seemingly, all is well. but then

class SubParser < Parser
...

now i have a problem: *only* the Parser class has an initialized of
the class instance variable @bufsize - it's of course 'nil' in
SubParser. now, it's true that we can write something like

class Parser

def self.inherited other
super if defined? super
ensure
other.init ### note that this must be *public* less we result
to class_eval...
end

def other.init
bufsize 4242
end

init()

this all starts to get just as confusing as the current situation. i
can hear people now: "why is it so hard to inherit class variables in
ruby?"

in short there are a million reasons to use class variables revolving
around the glitch that class inheritance in ruby does not provide a
straightforward way for child classes to have any sort of setup step
performed and that class variables let you perform that setup once in
a way that is inherited and yet settable by client code.

anyhow i really think it's the syntax, not the concept, that is cause
for confusion.

my 2cts.

ps. there are a lot of powerful concepts in ruby that are mostly mis-
understood: closures, mixins, singleton classes, callcc, throw/catch,
and lambda abstraction are part of what allows ruby to grow in
usefulness beyond the realm of the 'mere scripting language' some
people set out to learn. i would be loathe so any of them vanish.

pss. encapsulation is vastly overrated. when is that last time you
used 'protected' in any ruby code? ;-)

a @ http://codeforpeople.com/
 
D

David A. Black

Hi --

i honestly don't think they do - inheritance breaks encapsulation. for
example

class A
CONST = 42

class << self
def shared() 42.0 end
end
end

class B < A
end

p B::CONST
p B::shared

I think we're defining encapsulation differently. I don't mean that no
two objects should ever share any kind of data; rather, it's that
class variables don't play nicely with the system of which they are
part. I know about the "singleton" non-singletons... but at least
that's implemented in terms of inheritance (so really only the
terminology is at stake). I can see what a subclass has to do with its
parent class, especially given Matz's point that inheritance in Ruby
is mostly about "shared implementation". I find automatic variable
sharing between classes and instances much more problematic,
especially given the fact that classes are first-class objects (which
leads to all the problems with @@vars obscuring @vars, conceptually at
least).
and constants and singleton methods.... of course class singleton methods,

It's not a contest, though :) It's possible that constants are
well-designed and class variables aren't, even if they share certain
behaviors. Actually, I'd add constants to the list of things, along
with instance variables, that can do most of what people usually use
class variables for.
in an instance context, require a 'self.class' prefix to invoke while
constants do not but this is not encapsulation - it's the breaking of it -
instances *should* be allowed to access the unfettered methods of their class
because requiring the 'self.class' prefix also makes them *public* which, of
course, seriously breaks encapsulation.

I'm not following this, I'm afraid. If an object has a public method
defined on it, and you call obj.meth, how does that break
encapsulation? I guess it's the "*should*" I'm not understanding.
in point of fact inheritance is *designed* to break encapsulation so that we
can reuse code and remain sane. child classes, mixins, friend classes et al
are all about tearing down the barriers between bits of code so we don't
descend.into.dot.dot.dot.dot.hell and develop carpal tunnel from all that
code pasting

OK... but I don't think we have to choose between (a) no two objects
ever sharing anything, and (b) deciding that some objects share some
things so we might as well give up trying to differentiate among
different cases. It's possible that mixins are well-designed and class
variables aren't, even if both of them involve, described at a very
high level, tearing down barriers between bits of code.

The sense I get from class variables is of quasi-globalness. I don't
get that sense when I include a mixin; I actually don't think it's the
same in either kind or degree.
i can see that. still, they *are* associated with an instance - an instance
of a class hierarchy. i realize people don't generally seem to grasp this
concept though.

I'm not sure what the advantage is of generalizing the technical term
"instance" that way. You can say that global variables are associated
with an "instance" of a computer program, so they must be OK :)
the idea of switching syntax is a good one. i hate $
because it looks like perl and perl is clearly evil. i'm not sure what would
be better though.

"Clearly evil" works for me :)
In Ruby > 1.8, class variables are going to be somewhat more strictly
per-class. That's a mixed blessing. They're going to come closer to
representing a class's state, but then the question will arise: why
have both that *and* instance variables of classes? It's not
impossible to answer that, but it's not a bad question.

That sums up my views. Just so you know: I love Ruby madly :) This is
one of the very few areas where I dissent strongly from the way it's
designed.

yeah i see all that. still, i've deigned quite a few ruby classes and i can
assure people that they will miss them when they are gone/limited. the
reason, curiously, is that classes do not have an initialize method/hook.
let me explain: let's say you want to do something quite reasonable like so

class Parser

def self.bufsize(*value)
value.size == 0 ? @@bufsize : self.bufsize=(value.first)
end

def self.bufsize=(value)
@@bufsize = Integer value
end

bufsize 4242

def initialize options = {}
@bufsize = options[:bufsize] || @@bufsize

I don't think it would be such a disaster to have to say
"|| self.class.bufsize". It would certainly be worthwhile tradeoff for
all the other problems.
end

end

Parser.new


that is to say you want to grab default initialization options from your
class and you want users to be able to configure the class such that it
stamps out instances with those defaults. it's really nice if people can
configure via the environment or like so

Parser.bufsize 42

as i'm sure we can all agree.

(I'm happier with an equal-sign but I won't press the point :)
obviously constants aren't really in order
unless you want to use hackery like

class Parser

BUFSIZE = [ :value ]

def self.bufsize=(value) BUFSIZE[0] = Integer value end

...

blechh!

i can hear people thinking "you need instance variables!" sure, if you want
to write totally non-reusable code. why? because if i do

class Parser
def self.bufsize(*value)
value.size == 0 ? @bufsize : self.bufsize=(value.first)
end
[code snipped]

in short there are a million reasons to use class variables revolving around
the glitch that class inheritance in ruby does not provide a straightforward
way for child classes to have any sort of setup step performed and that class
variables let you perform that setup once in a way that is inherited and yet
settable by client code.

I'm still happier with class objects playing in the same ballpark as
other objects, when it comes to per-object state. Set up, if desired,
a way for other objects to get at the state, and then have the other
objects send you messages. It's all about where one thinks the
special-case horizon should be, I guess.
ps. there are a lot of powerful concepts in ruby that are mostly
mis-understood: closures, mixins, singleton classes, callcc, throw/catch, and
lambda abstraction are part of what allows ruby to grow in usefulness beyond
the realm of the 'mere scripting language' some people set out to learn. i
would be loathe so any of them vanish.

I'm not saying they should. I'm saying I'd like it if class variables
did :) It's not a one-size-fits-all argument about misunderstood Ruby
features; it's specifically about class variables.


David

--
Upcoming training from Ruby Power and Light, LLC:
* Intro to Ruby on Rails, Edison, NJ, October 23-26
* Advancing with Rails, Edison, NJ, November 6-9
Both taught by David A. Black.
See http://www.rubypal.com for more info!
 
A

ara.t.howard

I think we're defining encapsulation differently. I don't mean that no
two objects should ever share any kind of data; rather, it's that
class variables don't play nicely with the system of which they are
part. I know about the "singleton" non-singletons... but at least
that's implemented in terms of inheritance (so really only the
terminology is at stake). I can see what a subclass has to do with its
parent class, especially given Matz's point that inheritance in Ruby
is mostly about "shared implementation". I find automatic variable
sharing between classes and instances much more problematic,
especially given the fact that classes are first-class objects (which
leads to all the problems with @@vars obscuring @vars, conceptually at
least).

yeah i see that. i avoid them much of the time for those reasons.
but, technically, doing something like this

class C
SHARED_WITH_ALL_SUBCLASSES_AND_INSTANCES = []
end

does the same. it's something worth considering.
It's not a contest, though :) It's possible that constants are
well-designed and class variables aren't, even if they share certain
behaviors. Actually, I'd add constants to the list of things, along
with instance variables, that can do most of what people usually use
class variables for.

sort of. if you need state to be inherited you can use constants.
if you want true class singleton state that is settable you can use
class instance variables. if you want state that is settable AND
inherited the simplest option at the moment are class @@variables.
the way they mix into instances, i would agree is confusing, but
there really aren't any other *simple* options for inheriting state
in classes
I'm not following this, I'm afraid. If an object has a public method
defined on it, and you call obj.meth, how does that break
encapsulation? I guess it's the "*should*" I'm not understanding.

in some languages instances of a class may call private/protected
methods of that class which, if you think about it, makes sense. in
ruby, a method must (ignoring xxx_eval and send) be exposed to the
world if instances also need to call it. so when using class
instance vars you give instances one simple option for accessing
them: expose them through attr_accessor thereby also exposing them to
the world. for example

class C
@how_do_instances_get_at_this

def initialize
class << self.class
def with_a_public_accessor() @how_do_instances_get_at_this end
end

self.class.with_a_public_accessor
end

so the typical pattern with class instance variables is to expose
them publicly and this may break encapsulation iff the information
exposed is best left internal to the class and it's instances
OK... but I don't think we have to choose between (a) no two objects
ever sharing anything, and (b) deciding that some objects share some
things so we might as well give up trying to differentiate among
different cases. It's possible that mixins are well-designed and class
variables aren't, even if both of them involve, described at a very
high level, tearing down barriers between bits of code.

The sense I get from class variables is of quasi-globalness. I don't
get that sense when I include a mixin; I actually don't think it's the
same in either kind or degree.

yeah the fact that instances see them does indeed make them seem
quasi global - but the lack of another inherited class state
mechanism is a show stopper when it comes to declaring them useless
and poorly designed. that's critical functionality in some object
hierarchies.

I'm not sure what the advantage is of generalizing the technical term
"instance" that way. You can say that global variables are associated
with an "instance" of a computer program, so they must be OK :)

heh. i actually meant it quite specifically with regard to classes -
each iteration of oo laguanges is breaking down the barrier between
classes, objects, and other constructs like modules. i think we all
can see that the distinction in ruby is largely artificial: layers
put on top to make us see them as distinct. i probably program a lot
more class factories than your average ruby programmer and, when you
are working with classes at that level you, correctly, are thinking
of them as instances. but you also start wondering why things like
this don't work:

class C
@var = 42
class << self
p @var
end
end

and this too

class B < C
p @var
end

if you've programmed using prototypes this shouldn't really come as a
surprise: it's normal to expect classes that *are* objects to have
some mechanism for sharing or copying that object's state. in ruby
you have to resort to @@vars and other weirdness like klass.clone or
klass.dup to get the affect. in summary it's correct, i think, in a
language where classes are first class objects to consider attributes
of that class, like it's singleton class and it's child classes, as
*instance* data.
class Parser

def self.bufsize(*value)
value.size == 0 ? @@bufsize : self.bufsize=(value.first)
end

def self.bufsize=(value)
@@bufsize = Integer value
end

bufsize 4242

def initialize options = {}
@bufsize = options[:bufsize] || @@bufsize

I don't think it would be such a disaster to have to say "||
self.class.bufsize". It would certainly be worthwhile tradeoff for
all the other problems.

i disagree - if you do that you've designed a class that cannot be
subclassed: as that line will return 'nil' in those subclasses. if
you do that you should be using a singleton object or module - not a
class - to model your problem domain.
i can hear people thinking "you need instance variables!" sure,
if you want to write totally non-reusable code. why? because if
i do

class Parser
def self.bufsize(*value)
value.size == 0 ? @bufsize : self.bufsize=(value.first)
end
[code snipped]

in short there are a million reasons to use class variables
revolving around the glitch that class inheritance in ruby does
not provide a straightforward way for child classes to have any
sort of setup step performed and that class variables let you
perform that setup once in a way that is inherited and yet
settable by client code.

I'm still happier with class objects playing in the same ballpark as
other objects, when it comes to per-object state. Set up, if desired,
a way for other objects to get at the state, and then have the other
objects send you messages. It's all about where one thinks the
special-case horizon should be, I guess.

the lack of class setup with class instance variables isn't really a
special case though - any newbie would expect to be able to write this

class C
@a, @b = 4, 2
end

class B < C
end

and have @a and @b end up being initialized in B somehow. i guess i
just don't think that inheritance/setup of class state is something
that people should be expected to roll on their own in a language as
powerful as ruby - it can get quite complex when modules enter the
picture too. i'd rather entrust matz to solved the problem
generically ;-)
I'm not saying they should. I'm saying I'd like it if class variables
did :) It's not a one-size-fits-all argument about misunderstood Ruby
features; it's specifically about class variables.

oh i understand that david - no worries. what i'm saying is simply
that i've probably designed as many complex ruby class hierarchies as
anyone else out there and i've solved the class state sharing issue a
whole bunch of times in different ways: sometimes using 'inherited',
sometimes by factoring things out into modules, and sometimes using
@@variables and none of them are perfect. my experience has lead me
to think that any discussion of the evils of class variables (and
i've said they are evil on this list too!) shouldn't be outside the
context of how to *better* share and initialize state between parent
and child classes because it's an important feature in an oop
language - in short, it's a red herring.

cheers.

a @ http://codeforpeople.com/
 
D

Daniel DeLorme

ara.t.howard said:
yeah i see all that. still, i've deigned quite a few ruby classes and i
can assure people that they will miss them when they are gone/limited.
the reason, curiously, is that classes do not have an initialize
method/hook. let me explain: let's say you want to do something quite
reasonable like so

class Parser

def self.bufsize(*value)
value.size == 0 ? @@bufsize : self.bufsize=(value.first)
end

def self.bufsize=(value)
@@bufsize = Integer value
end

bufsize 4242

def initialize options = {}
@bufsize = options[:bufsize] || @@bufsize
end

end

Parser.new

But this still works with ruby1.9! And it works in subclasses too. As
long as @@bufsize is within the lexical context of Parser, it works just
like 1.8. The difference is only if you try to use @@bufsize within the
(lexical) scope of a subclass.
 
R

Rick DeNatale

i honestly don't think they do - inheritance breaks encapsulation.
for example

class A
CONST = 42

class << self
def shared() 42.0 end
end
end

class B < A
end

p B::CONST
p B::shared

class vars are exactly like this - only with state that happens to be
resettable. i don't see anything particular about the way class vars
behave that is different from constants or singleton (note the
*single* in singleton methods that can be called on multiple
objects!).

The main reason, I've never been completely comfortable with the Ruby
conflation of singleton class and metaclass. Or maybe it's the
conflation of singleton methods and class methods.

Seems to me that singleton methods SHOULD only be applicable to a
single object. A singleton class of a non-class is constrained to
containing only singleton methods in that sense, because it can't be
subclassed. A singleton class of a class is not. It's actually the
class that's the singleton here in that it's the only allowed instance
of its, dare I say it, metaclass.

But I digress.
it's the concept of inheritance that breaks
encapsulation, this is of course generally accepted by oop geeks, and
ruby doesn't change this wart on oop's many graces.

Agreed.

Inheritance is a power tool, valuable and sometimes dangerous. Did I
mention that it's valuable!
and constants and singleton methods.... of course class singleton
methods, in an instance context, require a 'self.class' prefix to
invoke while constants do not but this is not encapsulation - it's
the breaking of it - instances *should* be allowed to access the
unfettered methods of their class because requiring the 'self.class'
prefix also makes them *public* which, of course, seriously breaks
encapsulation.

I'm not sure that I totally agree here. There might well be class
methods which the class doesn't/shouldn't expose even to its
instances.

Perhaps there are use cases for a fourth visibility (in addition to
public, protected, and private) which makes a method visible to
instances, between public and protected.
in point of fact inheritance is *designed* to break encapsulation so
that we can reuse code and remain sane. child classes, mixins,
friend classes et al are all about tearing down the barriers between
bits of code so we don't descend.into.dot.dot.dot.dot.hell and
develop carpal tunnel from all that code pasting
Yes.


i can see that. still, they *are* associated with an instance - an
instance of a class hierarchy. i realize people don't generally seem
to grasp this concept though.

I understand what you're saying Ara, but it's a little hard to grasp
because there really isn't anything which reifies 'a class hierarchy'.
In reality a class variable is associated with a class, which of
course is the root of a class hierarchy, but the way they are
implemented, it really means they get associated with a kind of
snapshot of the hierarchy as it existed at the time the class variable
was defined. I say this by way of explaining the problems of defining
a class variable in a superclass, AFTER a subclass has already defined
a class variable with the same name.

This is one instance of a small set of curiosities in Ruby due to
problems in re-building the runtime structures when certain
inheritance related changes occur. To me it seems to be similar to
the problems with the semantics of module re-inclusion.

Now I'm not sure that Matz was directly inspired by Smalltalk in
coming up with class variables, but given my background I tend to
think so. Ruby class variable have a lot in common with Smaltalk's
certainly in terms of inheritance and visibility in both class and
instance methods. Assuming he was...

One of the biggest differences (and I'd say for the most part it's an
improvement) between Ruby and Smalltalk is that in Smaltalk variables
are declared, whereas in Ruby they are defined in the process of
expression parsing/execution.

In Smalltalk, you declare a class with something like

Object subclass: #Foo
instanceVariableNames: 'instVar'
classVariableNames: 'ClassVar'
classInstanceVariableNames: 'classInstVar'
poolDictionaries: 'PoolDict'

And the compiler uses these declarations when compiling a method. In
Smalltalk instance variables and class instance variables can be bound
to a slot at a fixed offset from the begining of the instance, or
class. Class variables can be bound to the value slot in a dictionary
associated with the class. I'll ignore pool dictionaries, they serve
some of the purposes of the name space aspect of modules.

The compiler searches up the hierarchy to find inherited class
variables, and the methods for manipulating the classVariableNames
list of a class validate that a conflict can't be created. Changing
the class declaration in Smalltalk triggers a recompilation of all
methods of the class and its subclasses.

Ruby substitutes run-time binding binding of variables, rather than
being at a fixed offset, ruby instance (and class instance) variables
are bound to a value slot in a hash associated with the instance or
class, class variables are bound to a hash as well (the last time I
looked it was the same hash, which works because the key contains the
sigil, so the keys :mad:instance_var, and :mad:@class_var can both be in the
hash, reflection methods like Object#instance_variables filter their
results to hide this implementation. Note also that this description
is from my memory of reading the MRI 1.8.x code, other Ruby 1.8
implementations might well use different implementation techniques but
should have the same semantics.

So what was my point here? Oh yes. I was talking about what happens
when you make certain changes to the inheritance structure. If we
had:

class A
end

class B < A
@@cv = 42
end

And then later
class A
@@cv = 57
end

Ruby currently at most warns about a conflict then goes ahead and adds
a new class variable to A, leaving the existing one in C.

I think that the change in 1.9 was motivated by this anomaly, by doing
away with the inheritance of class variables we avoid the surprise.
On the other hand, as you point out below, the baby might be being
thrown out with the bath water!

It seems to me that another solution would be to simply remove the
class variable from a subclass when a superclass subsequently creates
one with the same name. Sure B's view of @@cv would change from 42 to
57, but that's consistent with the intended semantics, I think.

On the other hand, there might be subtleties I can't yet fathom, much
like I still don't understand why 1.9 changed the semantics of:

module M
def meth
"M"
end
end

class A
include M
end

class B < A
def meth
"B"
end
end

class C
include M
end

C.new.meth

So that in 1.9 this used to result in "M" but then they changed it
back to the 1.8 semantics which ignore the re-inclusion and results in
"B".
absolutely correct.

i think that the problem should be dissected, it's really two problems:

1) Ruby class variables look too much like instance variables
because of syntax @@ vs @
2) The Ruby class variable implementation has a few rough edges.

The first problem makes me tend to agree that it would have been
better to choose another sigil for denoting class variables, although
this would seem to have a pretty sizable cost in backward
compatibility.

The second problem would seem to be fixable, at some cost to backward
compatibility, but 1.9 has already taken one path at fixing it.

I guess that the only difference between class variables and class
instance variables in 1.9 is that the former are visible in instance
methods.

It seems to me that the baby is in the bathwater here, the baby being
uses which rely on inheritance of class variables.

It might be interesting to see what happens when rails steps up to
ruby 1.9. It appears to use class variables pretty extensively. I'm
not sure how much it relies on class variable inheritance though.
yeah i see all that. still, i've deigned quite a few ruby classes
and i can assure people that they will miss them when they are gone/
limited. the reason, curiously, is that classes do not have an
initialize method/hook. let me explain: let's say you want to do
something quite reasonable like so
.. Long example justifying inheritable class variables snipped.
in short there are a million reasons to use class variables revolving
around the glitch that class inheritance in ruby does not provide a
straightforward way for child classes to have any sort of setup step
performed and that class variables let you perform that setup once in
a way that is inherited and yet settable by client code.

Not much to disagree with here.

An interesting side note. In Smalltalk, the declaration of variables
doesn't initialize them. Conventionally, class variables are
initialized in a class method called initialize. I'm a bit rusty on
this but IIRC this is something which has to be done manually after
defining the method and before instantiating any instances of the
class.
anyhow i really think it's the syntax, not the concept, that is cause
for confusion.

To summarize what I've said, I think it's a combination of the
semantics and the implementation.
ps. there are a lot of powerful concepts in ruby that are mostly mis-
understood: closures, mixins, singleton classes, callcc, throw/catch,
and lambda abstraction are part of what allows ruby to grow in
usefulness beyond the realm of the 'mere scripting language' some
people set out to learn. i would be loathe so any of them vanish.
Amen.


pss. encapsulation is vastly overrated. when is that last time you
used 'protected' in any ruby code? ;-)

Careful, Ara, the thought police are lurking! <G>
 
B

Brian Adkins

So what was my point here? Oh yes. I was talking about what happens
when you make certain changes to the inheritance structure. If we
had:

class A
end

class B < A
@@cv = 42
end

And then later
class A
@@cv = 57
end

Ruby currently at most warns about a conflict then goes ahead and adds
a new class variable to A, leaving the existing one in C.

Ok, you've used a similar example multiple times now, so my curiosity
is getting the best of me - do you actually code this way, or are you
trying to come up with a contrived example to show the alleged
problems with class variables? Wouldn't you typically initialize the
class variable in the "superest" class only?
...
On the other hand, there might be subtleties I can't yet fathom, much
like I still don't understand why 1.9 changed the semantics of:

module M
def meth
"M"
end
end

class A
include M
end

class B < A
def meth
"B"
end
end

class C
include M
end

C.new.meth

So that in 1.9 this used to result in "M" but then they changed it
back to the 1.8 semantics which ignore the re-inclusion and results in
"B".

Should 'class C' be 'class C < B' ?
 
A

ara.t.howard

But this still works with ruby1.9! And it works in subclasses too.
As long as @@bufsize is within the lexical context of Parser, it
works just like 1.8. The difference is only if you try to use
@@bufsize within the (lexical) scope of a subclass.

yup. i haven't used that in anger so i really don't know if it'll be
helpful or even more confusing - at least state can still be
inherited, even with a somewhat crippled impl.

time will tell!

cheers.

a @ http://codeforpeople.com/
 

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,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top