Dynamic classes

P

PsiPro

So I am working on some metaprograming and have some questions about
how to get what I need out of dynamic classes.

Right now I know I can define dynamic classes like so:
a) TestClass = Class.new
b) var_class = Class.new

These work as expected but I need the functionality provided by case
A. Specifically I need to have the instances respond to .class
appropriately. .class for case B returns Class, while case A responds
TestClass

The reason I need to do this is that I want to dynamically generate
classes, including their names. How can I accomplish this?

My desired results:

variable = Class.new
variable.class.name == 'variable'

OR, I need to be able to assign a dynamic constant name (I know I
know).

Any help would be appreciated.
 
P

PsiPro

So I am working on some metaprograming and have some questions about
how to get what I need out of dynamic classes.

Right now I know I can define dynamic classes like so:
a) TestClass = Class.new
b) var_class = Class.new

These work as expected but I need the functionality provided by case
A. Specifically I need to have the instances respond to .class
appropriately. .class for case B returns Class, while case A responds
TestClass

The reason I need to do this is that I want to dynamically generate
classes, including their names. How can I accomplish this?

My desired results:

variable = Class.new
variable.class.name == 'variable'

OR, I need to be able to assign a dynamic constant name (I know I
know).

Any help would be appreciated.

So I figured it out on my own, but still need some feedback.

Running
x="Foo"
c = eval("ClassNamePrefix#{x} = Class.new")

provided the desired results. I don't like the idea of using eval if
at all possible tho, any feedback would be greatly appreciated.

Thank you.
 
V

Vicente Bosch Campos

You can give it a dynamic name with eval:

ruby-1.9.2-p180 > a =3D "Monkey"
=3D> "Monkey"=20
ruby-1.9.2-p180 > eval("#{a} =3D Class.new")
=3D> Monkey=20
ruby-1.9.2-p180 > b =3D Monkey.new
=3D> #<Monkey:0x00000100b37f80>=20
ruby-1.9.2-p180 >=20

It seemed a bit messy so I checked out also Class.new, Module.new and =
Module.name ( class inherits from module and hence uses the name =
property) but no luck :-(

I wonder whyClass.new and Module.new don't have a parameter to define =
the name (seems something a person would want to do). Any ideas ?=20

Regards,
V.
 
R

Robert Klemme

So I am working on some metaprograming and have some questions about
how to get what I need out of dynamic classes.

Right now I know I can define dynamic classes like so:
a) TestClass = Class.new
b) var_class = Class.new

These work as expected but I need the functionality provided by case
A. Specifically I need to have the instances respond to .class
appropriately. .class for case B returns Class, while case A responds
TestClass

Case b cannot return Class. You would rather see something like this:

16:10:04 ~$ ruby19 -e 'TestClass = Class.new; p TestClass.new.class;
var_class = Class.new; p var_class.new.class'
TestClass
# said:
The reason I need to do this is that I want to dynamically generate
classes, including their names. How can I accomplish this?

My desired results:

variable = Class.new
variable.class.name == 'variable'

Magic works only with constants. The first constant that a Class or
Module instance is assigned determines its name.
OR, I need to be able to assign a dynamic constant name (I know I
know).

16:30:47 ~$ ruby19 -e 'x=Class.new;Object.const_set("Foo",x);p x, x.new.class'
Foo
Foo

Why do you need this? Maybe you can do

classes = {}

classes["Foo"] = Class.new do
def nifty_method
42
end
end

Now you can do

obj = classes["Foo"].new

You could even override Class#name or #to_s per instance to return the
proper value, if you must have the class name...

Cheers

robert
 
7

7stud --

My desired results:
variable = Class.new
variable.class.name == 'variable'

Are you sure about that? 'variable' is a class object--not what you
would normally think of as an instance of a class. Because 'variable'
is a class object, its class is Class, and the name of the generic Class
class would not be 'variable'.
 
7

7stud --

Vicente Bosch Campos wrote in post #989219:
I wonder why Class.new and Module.new don't have a parameter to define
the name (seems something a person would want to do). Any ideas ?

Because you have to assign the newly created class to a
variable--otherwise it will be discarded--just like all values that
aren't assigned to a variable. If you want to name the class, you
assign the newly created class to a constant, i.e. a name that is
capitalized.
 
V

Vicente Bosch Campos

I understand how it works at the moment. Still if you are doing =
metaprogramming and consider with a very purist perspective that =
everything is an object then a Class definition is just an instance of =
the Class Class and I should be able to change its properties and that =
should be independent of having the definition assigned to a variable =
otherwise it would be discarded as you say.

Did a bit of reading and at the end you can also create a class in the =
following manner which allows you to define a name dynamically with out =
using eval:

Object.const_set("Bar",Class.new)

This is due (from my opinion) to how the vm stores the classes as =
constants in Object. I understand why but I think there should be a more =
cleaner,abstract way to create Class definitions as they are objects =
instead of the current Bare metal approach ( we get to see to much of =
the internals ?)
 
R

Robert Klemme

I understand how it works at the moment. Still if you are doing
metaprogramming and consider with a very purist perspective that
everything is an object then a Class definition is just an instance
of the Class Class

The definition is a definition, the _result of executing it_ is an
instance of class Class.
and I should be able to change its properties and
that should be independent of having the definition assigned to a
variable otherwise it would be discarded as you say.

You can change a class's properties, e.g. by adding methods etc. It's
just that the name happens to be a read only property and there is some
additional magic which will set it on first constant assignment. I
don't see how that collides with a "purist perspective".
Did a bit of reading and at the end you can also create a class in
the following manner which allows you to define a name dynamically
with out using eval:

Object.const_set("Bar",Class.new)

See my posting in this thread from yesterday. :)

Oh, and btw, that code does not really make sense that way because it
can be easily replaced by

Bar = Class.new

or even

class Bar
end

The approach with Object.const_set basically only makes sense if the
name is dynamic, too.

Everything can be done on a low level but usually we define artifacts
(classes, methods) to group functionality so we can access it more
conveniently and manage complexity.
This is due (from my opinion) to how the vm stores the classes as
constants in Object.

I find that wording slightly irritating: it sounds a bit as if you
assume the class is somehow in the constant. In Reality the constant
just references the class instance. There is no particular magic
involved other than the custom syntax with "class Name...end".
I understand why but I think there should be a
more cleaner,abstract way to create Class definitions as they are
objects instead of the current Bare metal approach ( we get to see to
much of the internals ?)

I am not sure what you mean by "too much internals". After all, I would
consider doing

Foo = Class.new do
def x;123;end
end

more bare metal than

class Foo
def x;123;end
end

Syntax with "class" certainly helps makes things a bit more abstract and
less "internal". What would be the cleaner, more abstract way?

Cheers

robert
 
V

Vicente Bosch Campos

=20
The definition is a definition, the _result of executing it_ is an = instance of class Class.
=20

I agree with you.
=20
You can change a class's properties, e.g. by adding methods etc. It's =
just that the name happens to be a read only property and there is some =
additional magic which will set it on first constant assignment. I =
don't see how that collides with a "purist perspective".

I have not explained my self properly. Imagine we are talking about =
making an instance of any other object e.g. a Car and the car has a name =
and it allows you reference the car instance by it in the future.

Would you prefer the car name is defined by the variable that contains =
it or by setting the name in the constructor?

hotwheels =3D Car.new

current_car =3D Car.new("hotwheels")

I don't think anyone would understand directly that I have automatically =
set a property inside my car with the variable name. It would be a bit =
counterintuitive and different from how any other instance properties =
work on this class and how they are usually set on any other type of =
object of any library.

Considering the Class to be an object too by not allowing me set the =
name at the .new and taking the name of the left hand side of the =
equality sign in case it is a Constant ( otherwise it does not) it is =
not acting very much like any other object.=20

=20
See my posting in this thread from yesterday. :)
=20
Oh, and btw, that code does not really make sense that way because it = can be easily replaced by
=20
Bar =3D Class.new
=20
or even
=20
class Bar
end
=20
The approach with Object.const_set basically only makes sense if the =
name is dynamic, too.


Yes sorry, I do want to have the name dynamic too ( I might be going =
off-topic for the original post, sorry).
=20
Everything can be done on a low level but usually we define artifacts =
(classes, methods) to group functionality so we can access it more =
conveniently and manage complexity.
=20
=20
I find that wording slightly irritating: it sounds a bit as if you =
assume the class is somehow in the constant. In Reality the constant =
just references the class instance. There is no particular magic =
involved other than the custom syntax with "class Name...end".

Agreed, its just a reference. But if I want to have a dynamic name =
without having to use eval I need to understand that the list of classes =
defined are referred to as constants in the Object and I can do that =
with

Object.const_set("Bar",Class.new)

I am just saying it would be nicer to do Class.new("Bar") would be much =
more like any other object instantiation and less questioned about as it =
would not be an exception to how the rest of the stuff works ( although =
Class object is truly a bit of an exception and its one of those =
marvelous things ruby allows us to tinker with ).=20
=20
=20
I am not sure what you mean by "too much internals". After all, I =
would consider doing

By "too much internals" I mean that I actually need to get to know that =
the class Names are referenced in a list of constants in Object and that =
I can do Object.const_set("Bar",Class.new) to create a class with a =
dynamic name ( and not have to use eval) instead of Class.new("Bar"). =
( Sorry for going in circles)

=20
Foo =3D Class.new do
def x;123;end
end
=20
more bare metal than
=20
class Foo
def x;123;end
end
=20
Syntax with "class" certainly helps makes things a bit more abstract =
and less "internal". What would be the cleaner, more abstract way?

For a definition with a set name totally agree with you.=20
=20
Cheers

Many thanks for the healthy discussion :)

Cheers

Vicente
 
E

Eric Christopherson

I have not explained my self properly. Imagine we are talking about makin=
g an instance of any other object e.g. a Car and the car has a name and it =
allows you reference the car instance by it in the future.
Would you prefer the car name is defined by the variable that contains it=
or by setting the name in the constructor?
hotwheels =3D Car.new

current_car =3D Car.new("hotwheels")

I don't think anyone would understand directly that I have automatically =
set a property inside my car with the variable name. It would be a bit coun=
terintuitive and different from how any other instance properties work on t=
his class and how they are usually set on any other type of object of any l=
ibrary.
Considering the Class to be an object too by not allowing me set the name=
at the .new and taking the name of the left hand side of the equality sign=
in case it is a Constant ( otherwise it does not) it is not acting very mu=
ch like any other object.

Is there a way in Ruby to do this with objects generally (i.e. to
automatically set a name property upon assignment with =3D), not just
with Classes?
 
R

Robert Klemme

I have not explained my self properly. Imagine we are talking about
making an instance of any other object e.g. a Car and the car has a
name and it allows you reference the car instance by it in the
future.

Would you prefer the car name is defined by the variable that
contains it or by setting the name in the constructor?

hotwheels = Car.new

current_car = Car.new("hotwheels")

I don't think anyone would understand directly that I have
automatically set a property inside my car with the variable name. It
would be a bit counterintuitive and different from how any other
instance properties work on this class and how they are usually set
on any other type of object of any library.

Considering the Class to be an object too by not allowing me set the
name at the .new and taking the name of the left hand side of the
equality sign in case it is a Constant ( otherwise it does not) it is
not acting very much like any other object.

OK, now I get your point. Thanks! I think Matz just decides that doing

X = Class.new do
def foo; end
end

is less clean than

class X
def foo; end
end

and hence created the const magic because class definitions are so
common. If you want, you can still use the bar bones idiom though.
Yes sorry, I do want to have the name dynamic too ( I might be going
off-topic for the original post, sorry).

Then consider this: if the name is dynamic during definition it
certainly has to be dynamic during referencing as well. In that case
there is probably not much point in assigning the class to a constant.
Rather a Hash would be a much better place to keep all those classes
around. You could even do something like this:

irb(main):012:0> cl = Hash.new do |h,name|
irb(main):013:1* c = Class.new
irb(main):014:1> class<<c;self;end.send:)define_method, :name) { name }
irb(main):015:1> h[name]=c
irb(main):016:1> end
=> {}
irb(main):017:0> cl["Foo"]
=> #<Class:0x106c15bc>
irb(main):018:0> cl["Foo"]
=> #<Class:0x106c15bc>
irb(main):019:0> cl["Foo"].name
=> "Foo"

or

irb(main):027:0> cl = {}
=> {}
irb(main):028:0> def cl.new_class(name, &b)
irb(main):029:1> c = Class.new(&b)
irb(main):030:1> class<<c;self;end.send:)define_method, :name) { name }
irb(main):031:1> self[name]=c
irb(main):032:1> end
=> nil
irb(main):033:0> cl.new_class "Foo" do
irb(main):034:1* def bar;123;end
irb(main):035:1> end
=> #<Class:0x105a7364>
irb(main):036:0> cl["Foo"]
=> #<Class:0x105a7364>
irb(main):037:0> cl["Foo"]
=> #<Class:0x105a7364>
irb(main):038:0> cl["Foo"].name
=> "Foo"
irb(main):039:0> cl["Foo"].new.bar
=> 123

Now the Hash defines a namespace where all your dynamic classes reside.
If you want to get rid of them you just need to clear the Hash. This
approach can be extended to define a specific DSL for your domain which
would make method definitions even simpler.
I am just saying it would be nicer to do Class.new("Bar") would be
much more like any other object instantiation and less questioned
about as it would not be an exception to how the rest of the stuff
works ( although Class object is truly a bit of an exception and its
one of those marvelous things ruby allows us to tinker with ).

Actually I haven't seen the syntax "class Name ... end" questioned in a
while. I believe this is such a fundamental and frequent idiom to
warrant a bit of syntactic sugar mixed with naming magic. :)
Many thanks for the healthy discussion :)

Ditto.

Kind regards

robert
 
V

Vicente Bosch Campos

making an instance of any other object e.g. a Car and the car has a name =
and it allows you reference the car instance by it in the future.automatically set a property inside my car with the variable name. It =
would be a bit counterintuitive and different from how any other =
instance properties work on this class and how they are usually set on =
any other type of object of any library.name at the .new and taking the name of the left hand side of the =
equality sign in case it is a Constant ( otherwise it does not) it is =
not acting very much like any other object.
=20
Is there a way in Ruby to do this with objects generally (i.e. to
automatically set a name property upon assignment with =3D), not just
with Classes?
=20


I think this Constant "Magic" only works for classes as Robert has =
indicated. At least I have not seen anything on google or my bookshelf =
to do it.

I personally would not use it, its an exception of how the operator =
works, and forces people to delve into how your object works which can =
be considered as not very clean.

For the specific case of the Class and being such a high level =
metaprogramming structure, love Ruby for it, I can understand why Matz =
treated it as something special.
 
J

Jesús Gabriel y Galán

I think this Constant "Magic" only works for classes as Robert has indicated. At least I have not seen anything on google or my
bookshelf to do it.

I personally would not use it, its an exception of how the operator works, and forces people to delve into how your object works which
can be considered as not very clean.

But it allows some very nice things, like having ways of creating
classes, assign them to constants and have them work as a regularly
defined class very easily:

ruby-1.8.7-p334 :001 > TestClass = Struct.new :id
=> TestClass
ruby-1.8.7-p334 :004 > TestClass.name
=> "TestClass"

(Struct.new returns a class)

Jesus.
 

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,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top