[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

class locals as class methods

Trans

4/14/2005 5:19:00 PM

So I find myself once again creating some classes that have
attributes/state. I have two options, either the class defines
a class method for the info, or in a superclass I define a method
that will set that info to a class var when called.

# Example A
class Thing1 < TheseThings
def self.mystate ; "what have you" ; end
end

or

# Example B
class Thing1 < TheseThings
mystate "what have you"
end

The first is rather, well, ugly. Although it makes sense, it's
what one does at the instance level all the time (i.e. defining
methods to fit the interface). The second is nice and dsl-ish,
but requires a method to be predefined in TheseThings which
actually creates a number of oddities, like how does one read
the info out, and still be able to set it to nil? If that's an
issue one is lead to instead define two class methods, and
having to use self.maystate = "blah blah", instead.

Now everytime I go about this kind of thing I actually find
myself writing:

# Example C
class Thing1 < TheseThings
mystate = "what have you"
end

as that just feels natural. But then I have to go back and fix
it, of course. So last night it hits me, why not? Why not have
class locals define class methods? So in this case, Example C
would basically be like doing Example A. Yes, I know there's
namespace overlap, but class locals are rare enough that I don't
think that's a show stopper. Maybe there are other problems I'm
not seeing, perhaps there's some OOP formalism that this rubs the
wrong way. I don't know. But I've given it more than "15 minutes"
and it's actually growing on me. Am I crazy?

T.

13 Answers

Mark Hubbart

4/14/2005 6:03:00 PM

0

On 4/14/05, Trans <transfire@gmail.com> wrote:
> So I find myself once again creating some classes that have
> attributes/state. I have two options, either the class defines
> a class method for the info, or in a superclass I define a method
> that will set that info to a class var when called.
[...]
> as that just feels natural. But then I have to go back and fix
> it, of course. So last night it hits me, why not? Why not have
> class locals define class methods? So in this case, Example C
> would basically be like doing Example A. Yes, I know there's
> namespace overlap, but class locals are rare enough that I don't
> think that's a show stopper. Maybe there are other problems I'm
> not seeing, perhaps there's some OOP formalism that this rubs the
> wrong way. I don't know. But I've given it more than "15 minutes"
> and it's actually growing on me. Am I crazy?

I think meta-programming would suffer.

# a Foo that is sort of like a Bar
class FooBar < Foo
bar_methods = Bar.instance_methods - self.instance_methods
bar_methods.each{ ... }
end

FooBar.bar_methods => ?????

It would be like penalizing people for using metaprogramming techniques :(

Perhaps, if you just want to set attributes:

class Class
def set(name, value)
self.class_eval "def self.#{name}() @@#{name} end"
self.class_eval "@@#{name} = ObjectSpace._id2ref(#{value.object_id})"
end
end
==>nil
class Foo
set :foo, "yep!"
end
==>"yep!"
Foo.foo
==>"yep!"

I'm sure it could be condensed even further, if needed.

Off topic now, I thought there was an equivalent of
#instance_variable_set for class variables? It would seem not. I
wonder why.

cheers,
Mark



Trans

4/14/2005 6:48:00 PM

0

Mark Hubbart wrote:
> I think meta-programming would suffer.
>
> # a Foo that is sort of like a Bar
> class FooBar < Foo
> bar_methods = Bar.instance_methods - self.instance_methods
> bar_methods.each{ ... }
> end
>
> FooBar.bar_methods => ?????
>
> It would be like penalizing people for using metaprogramming
techniques :(

Hmm... I would think that code would work just fine. I'm not suggesting
that local vars be displaced, if that is what you mean, only that they
overlap. So a class local var is a class method is a class local var.
It is the same namespace afterall (i.e. self resoves to the same thing)
so that's okay too. Am I understanding your example?

For reference I tried:

module Bar
def a ; ; end
def b ; ; end
def c ; ; end
end

class Foo
def x ; ; end
def y ; ; end
def z ; ; end
end

class FooBar < Foo

# local
foo_bar = Bar.instance_methods - self.instance_methods
p foo_bar

# class
def self.bar_methods
Bar.instance_methods - self.instance_methods
end

end

p FooBar.bar_methods

with the result:

["c", "b", "a"]
["c", "b", "a"]

> Perhaps, if you just want to set attributes:
>
> class Class
> def set(name, value)
> self.class_eval "def self.#{name}() @@#{name} end"
> self.class_eval "@@#{name} =
ObjectSpace._id2ref(#{value.object_id})"
> end
> end
> ==>nil
> class Foo
> set :foo, "yep!"
> end
> ==>"yep!"
> Foo.foo
> ==>"yep!"
>
> I'm sure it could be condensed even further, if needed.

Sure, that's one fair way. There are a number of ways to do it, like
the simple first examples I gave. But all of them seem, well,
contrived. In other words, there's no sort of obvious standard to this
kind of thing. And worse to me, the solutions all look like they've
been hit up with an ugly stick ;-)

> Off topic now, I thought there was an equivalent of
> #instance_variable_set for class variables? It would seem not. I
> wonder why.

Hmm... I don't know, maybe b/c this is less characters?

Klass.class_eval { @@x = "foo" }

Thanks,
T.

Mark Hubbart

4/14/2005 8:02:00 PM

0

On 4/14/05, Trans <transfire@gmail.com> wrote:
> Mark Hubbart wrote:
> > I think meta-programming would suffer.
> >
> > # a Foo that is sort of like a Bar
> > class FooBar < Foo
> > bar_methods = Bar.instance_methods - self.instance_methods
> > bar_methods.each{ ... }
> > end
> >
> > FooBar.bar_methods => ?????
> >
> > It would be like penalizing people for using metaprogramming
> techniques :(
>
> Hmm... I would think that code would work just fine. I'm not suggesting
> that local vars be displaced, if that is what you mean, only that they
> overlap. So a class local var is a class method is a class local var.
> It is the same namespace afterall (i.e. self resoves to the same thing)
> so that's okay too. Am I understanding your example?
[snip example]

I don't think so. I was referring to intermediate local variables that
you use inside classes when metaprogramming. I think I elided too much
code there; I just didn't want to bother thinking something up to take
up the elipses :) I'm just saying that you don't necessarily want all
your temporary variables to be permanently accessible. Also, there are
garbage collection implications. local variables are not usually
thought to be hanging around forever.

> > Perhaps, if you just want to set attributes:
> >
> > class Class
> > def set(name, value)
> > self.class_eval "def self.#{name}() @@#{name} end"
> > self.class_eval "@@#{name} =
> ObjectSpace._id2ref(#{value.object_id})"
> > end
> > end
> > ==>nil
> > class Foo
> > set :foo, "yep!"
> > end
> > ==>"yep!"
> > Foo.foo
> > ==>"yep!"
> >
> > I'm sure it could be condensed even further, if needed.
>
> Sure, that's one fair way. There are a number of ways to do it, like
> the simple first examples I gave. But all of them seem, well,
> contrived. In other words, there's no sort of obvious standard to this
> kind of thing. And worse to me, the solutions all look like they've
> been hit up with an ugly stick ;-)
>
> > Off topic now, I thought there was an equivalent of
> > #instance_variable_set for class variables? It would seem not. I
> > wonder why.
>
> Hmm... I don't know, maybe b/c this is less characters?
>
> Klass.class_eval { @@x = "foo" }

Doesn't work for arbitrary variables. Maybe this can be done without a
string-based eval or ObjectSpace._id2ref, but I couldn't quickly
figure out how:

class Class
def class_attr_accessor( name )
self.class_eval "def #{name}() @@#{name} end"
self.class_eval "def #{name}=(val) @@#{name}=val end"
end
end

compare to attr_accessor, which could be defined in pure ruby without
the evil string-based-eval.

class Class
def attr_accessor(name)
attr_name = :"@@#{name}"
name_eq = :"#{name}="
define_method(name){ instance_variable_get(attr_name)}
define_method(name_eq){ instance_variable_get(attr_name)}
end
end

cheers,
Mark



Lionel Thiry

4/14/2005 9:27:00 PM

0

Trans a écrit :
> So I find myself once again creating some classes that have
> attributes/state. I have two options, either the class defines
> a class method for the info, or in a superclass I define a method
> that will set that info to a class var when called.
>
> # Example A
> class Thing1 < TheseThings
> def self.mystate ; "what have you" ; end
> end
>
> or
>
> # Example B
> class Thing1 < TheseThings
> mystate "what have you"
> end
>


You can use the attr_* instead:

class Thing1 < TheseThings
class <<self
attr_accessor :mystate
end
end



> The first is rather, well, ugly. Although it makes sense, it's
> what one does at the instance level all the time (i.e. defining
> methods to fit the interface). The second is nice and dsl-ish,
> but requires a method to be predefined in TheseThings which
> actually creates a number of oddities, like how does one read
> the info out, and still be able to set it to nil? If that's an
> issue one is lead to instead define two class methods, and
> having to use self.maystate = "blah blah", instead.
>
> Now everytime I go about this kind of thing I actually find
> myself writing:
>
> # Example C
> class Thing1 < TheseThings
> mystate = "what have you"
> end
>
> as that just feels natural. But then I have to go back and fix
> it, of course. So last night it hits me, why not? Why not have
> class locals define class methods? So in this case, Example C
> would basically be like doing Example A.

That's actually how python works.

class Thing1(TheseThings):
my_state = "what have you"
print Thing1.my_state # output: what have you

Well, it doesn't really create a my_state method, and doesn't really create some
@my_state anywhere. But at use, it works the same as you'd want ruby to work.

> Yes, I know there's
> namespace overlap, but class locals are rare enough that I don't
> think that's a show stopper. Maybe there are other problems I'm
> not seeing, perhaps there's some OOP formalism that this rubs the
> wrong way.

I haven't the ability to demonstrate you anything, but my intuition is that it
is not much adequate for ruby...

> I don't know. But I've given it more than "15 minutes"
> and it's actually growing on me. Am I crazy?

Crazy of wanting ruby to look like python? Err... ;)

--
Lionel Thiry

dblack

4/14/2005 10:09:00 PM

0

Mark Hubbart

4/14/2005 10:40:00 PM

0

Hi,

On 4/14/05, David A. Black <dblack@wobblini.net> wrote:

> Local variables have the advantage of being 'scratch-pad'-like. You
> don't have to worry about outside access, nor about using the same
> variable name twice in different scopes at the same level. If these
> things are no longer the case, then the change is pretty deep.

Thank you. You just did a much better job of explaining this than I
did; What you said is exactly what I was thinking :)

cheers,
Mark



Robert Klemme

4/15/2005 11:30:00 AM

0


"Trans" <transfire@gmail.com> schrieb im Newsbeitrag
news:1113499156.837299.173260@z14g2000cwz.googlegroups.com...
> So I find myself once again creating some classes that have
> attributes/state. I have two options, either the class defines
> a class method for the info, or in a superclass I define a method
> that will set that info to a class var when called.
>
> # Example A
> class Thing1 < TheseThings
> def self.mystate ; "what have you" ; end
> end
>
> or
>
> # Example B
> class Thing1 < TheseThings
> mystate "what have you"
> end
>
> The first is rather, well, ugly. Although it makes sense, it's
> what one does at the instance level all the time (i.e. defining
> methods to fit the interface). The second is nice and dsl-ish,
> but requires a method to be predefined in TheseThings which
> actually creates a number of oddities, like how does one read
> the info out, and still be able to set it to nil? If that's an
> issue one is lead to instead define two class methods, and
> having to use self.maystate = "blah blah", instead.
>
> Now everytime I go about this kind of thing I actually find
> myself writing:
>
> # Example C
> class Thing1 < TheseThings
> mystate = "what have you"
> end
>
> as that just feels natural. But then I have to go back and fix
> it, of course. So last night it hits me, why not? Why not have
> class locals define class methods? So in this case, Example C
> would basically be like doing Example A. Yes, I know there's
> namespace overlap, but class locals are rare enough that I don't
> think that's a show stopper. Maybe there are other problems I'm
> not seeing, perhaps there's some OOP formalism that this rubs the
> wrong way. I don't know. But I've given it more than "15 minutes"
> and it's actually growing on me. Am I crazy?

Probably - but then again, aren't we all? :-)

Ok, here's what I'd probably do:

class TheseThings
module ThingClassProperties
attr_accessor :mystate

# needed for further inheritance levels
def inherited(cl) cl.extend ThingClassProperties end
end

extend ThingClassProperties
end

class Thing1 < TheseThings
self.mystate = "t1 state"
end

class Thing2 < Thing1
self.mystate = "t2 state"
end

p Thing1.mystate
p Thing2.mystate

13:28:13 [source]: ruby /c/temp/ruby/meta-prog.rb
"t1 state"
"t2 state"

You can make that even smarter by defining property accessors on the fly
etc.

Cheers

robert

Trans

4/15/2005 5:29:00 PM

0

Agreed, the scratch-pad analogy makes a good case.

Thanks,
T.

Trans

4/15/2005 6:11:00 PM

0

Actually I should go further with this...

The idea of a clean nomenclature is very appealing, which is one of the
resons the idea of this thread is appealing to me. But I do see the
point of the "scratch-pad" variable. What's interesting though, is that
it is this distinction that really matters: whether the var is
temporary or permanant. How do we mark that distinction now? Lo, it's
not as far from what I had imagined as it is, actually. You can define
just such a variable using an @ sign. Of course you still need to
create the accessor methods to go with it:

class X
@a = 1
def self.a ; @a ; end
def self.a=(x) ; @a = x ; end
end

But this is what gets me when I think about it. It is this form --the
accessor form, that requires all this extra footwork; not the
"scratch-pad" local vars. You'd think it were the local vars that were
most commonly used then, but they aren't. So it would seem preferable
to make the locals the ones with the extra syntax, either in defining
them like a := 1 or a prefix, like %a = 1 or something.

Yet, going further, we might take this down to the method level too. It
has been suggested before (and I think quite reasonably) that we could
have local methods:

class X
def a
def b
"1"
end
b
end
end

In this case #b is local to #a. Applying the idea of this thread in
this context would mean that local vars are local methods too. So,

class X
def a
b = "1"
b
end
end

would be equivalent to the previous example. Here, again the
"scratch-pad" critique posses an issue. In effect the local vars are
becoming persistant. So, we could make a distinction between the
persitant vs. non-persistant to deal with this, but in this case the
syntax it is not quite as clear b/c local vars are much more common in
this method context.

T.

Trans

4/15/2005 6:25:00 PM

0

> Ok, here's what I'd probably do:

robert, thanks for the example, I like the looks off it and I will play
with it.

T.