Changing self class from inside a method?

Let’s start off with the assumption I want a method that allows an
object to transform itself into another object. In other words:

begClass = a.class
a.changeToSomethingElse(42)
endClass = a.class

Where begClass != endClass

As a more specific example, consider some hopeful code for allowing
auto-creation of arrays from nil, perl-ish style:

class Nil
def push(*els)
a = Array.new
a.push(*els)
#self = a # Nope!
#self.class = Array # Nope!
end
end

This would allow:
a = nil
a.push(1,2,3)
puts “#{a.class}”

I know we have things like to_a, but that requires an assigment instead
of just the method call. Let’s just assume we need a way to do it like
this.

Is this just considered impossible, or is there a way to change/convert
the class of self from inside a method? I can imagine it would cause
complications the moment the class changes, since we’d suddenly be in
the method of the wrong class, but if any language had a way to do it, I
figure it’d be ruby.

hi:

I don’t think you can reassign self in the middle of an instance, but
I’m not an expert on metaprogramming.

However, I’m not sure how useful it is to change classes midstream. For
expample you can simply do this:

begClass = a.class
endClass = a.changeToSomethingElse(42)
endClass = a.class

Just have changeToSomethingElse(42) return an instance of a different
class. Likewise, just have “push()” return a new class type.

If you’re more spesific about what you’re trying to do, it would help me
understand.

Eric

The class-oriented idiom is very strict. I.e An object is an instance of
a class.

However, leaving classes behind, objects are nothing but state and
behavior.

In ruby and other purely object oriented languages, an object isn’t
judged on it’s class but on it’s behavior (ducktyping).

Thus you don’t need to change the class of an object —which isn’t much
more than a factory to create object — to achieve what you want.

  • Mixins allows you to inject behavior to objects at runtime.
  • It’s possible to alter (undef) methods
  • You might want to github search for Mixology
  • Read about Role modeling (maybe DCI) and traits.

On Tue, May 22, 2012 at 6:43 AM, David M. [email protected]
wrote:

Let’s start off with the assumption I want a method that allows an
object to transform itself into another object. In other words:

begClass = a.class
a.changeToSomethingElse(42)
endClass = a.class

Where begClass != endClass

You can’t do this.

As a more specific example, consider some hopeful code for allowing
auto-creation of arrays from nil, perl-ish style:

If you miss Perl that much you are probably using the wrong language
here.

a = nil
a.push(1,2,3)
puts “#{a.class}”

I know we have things like to_a, but that requires an assigment instead
of just the method call. Let’s just assume we need a way to do it like
this.

I am not ready to assume “that we need a way to do it like this”. The
Ruby idiom for this is

a = nil

(a ||=[]).push(1,2,3)

Is this just considered impossible, or is there a way to change/convert
the class of self from inside a method? I can imagine it would cause
complications the moment the class changes, since we’d suddenly be in
the method of the wrong class, but if any language had a way to do it, I
figure it’d be ruby.

There might be a way in a C extension but actually I consider it a bad
idea because it violates one of the basic assumptions of the language
(i.e. that the class of an instance does not change) - and it’s
unnecessary (see above).

What you can do is to use a proxy object like SimpleDelegator and
change the instance it points to later. But then you need to
initialize the variable and if you know it’s going to be an Array you
can just as well initialize with an empty Array instance.

Kind regards

robert

Hi,

I also don’t think you can reassign self without digging into Ruby’s
source code. My idea was to at least fake an object transformation by
making the nil instance a wrapper for an array:

#------------------
class NilClass
def push *values
@array = values
@array.methods.each do |method|
define_singleton_method method do |*args, &block|
@array.send method, *args, &block
end
end
end
end

a = nil
a.push 1, 2
p a
puts a.class
#------------------

But then I realized that nil is actually a singleton object (there’s
only one nil). This somewhat makes the whole thing pointless, because
any change to a nil instance would affect all “nils”.

I don’t see the point in this feature, anyway. It perhaps would make
some sense if you didn’t have to set the variable in the first place but
could magically create a new array by calling the push method on a new
identifier. PHP has this, for example:

$x[0] = “abc”; // this makes $x an array

But when you have to write “a = nil” first, then you might as well write
“a = []” and leave out all the magic.

On Tue, May 22, 2012 at 12:17 PM, Jan E. [email protected] wrote:

I also don’t think you can reassign self without digging into Ruby’s
source code.

What are you guys talking about reassigning self all the time? David
wants to change the class of an instance - not its identity. Even if
you could reassign self inside a method all variable references still
point to the same old instance self pointed to before. This clearly
does not achieve the goal as stated.

My idea was to at least fake an object transformation by
making the nil instance a wrapper for an array:

But then I realized that nil is actually a singleton object (there’s
only one nil). This somewhat makes the whole thing pointless, because
any change to a nil instance would affect all “nils”.

Exactly.

I don’t see the point in this feature, anyway. It perhaps would make
some sense if you didn’t have to set the variable in the first place but
could magically create a new array by calling the push method on a new
identifier. PHP has this, for example:

$x[0] = “abc”; // this makes $x an array

But when you have to write “a = nil” first, then you might as well write
“a = []” and leave out all the magic.

The use case is probably rather instance variables which do not
require initialization and default to nil. Still, I don’t think it’s
needed. I believe OP hasn’t got the hang of how Ruby works yet.

Kind regards

robert

2012/5/22 David M. [email protected]:

Is this just considered impossible, or is there a way to change/convert
the class of self from inside a method? I can imagine it would cause
complications the moment the class changes, since we’d suddenly be in
the method of the wrong class, but if any language had a way to do it, I
figure it’d be ruby.

Fun fact: it’s possible in Python. (It tends to lead to segfaults.)

It’s not possible in Ruby, but may be achievable using a C extension.
Still, that seems like a very bad idea. I don’t know your usecase, but
you could probably either start with an empty array instead of nil, or
“guard” all array methods with “ary ||= []”.

– Matma R.

On Tue, May 22, 2012 at 8:46 PM, Admin T. [email protected]
wrote:

Yes, indeed it is achievable using a C extension, at least for the
user-defined class.

Still it does not help for the use case at hand since nil is a
singleton instance. All others will also see nil turn into an Array
which will have dramatic effects. This is a classical Bad Idea™.

Cheers

robert

you could probably either start with an empty array instead of nil, or
“guard” all array methods with “ary ||= []”.

A related and useful idiom is auto-vivification of Hash elements:

h = Hash.new { |h,k| h[k] = [] }
h[:foo] << “bar”
h[:foo] << “baz”
p h # {:foo=>[“bar”, “baz”]}

Objects in ruby cannot change their class. If you really need to do
this, then you can have a proxy object which delegates calls, and you
can change the target object dynamically:

require ‘delegate’
=> true

myvar = SimpleDelegator.new(nil)
=> nil

myvar.to_s
=> “”

myvar.setobj([])
=> []

myvar << “foo” << “bar”
=> [“foo”, “bar”]

Bartosz Dziewoński wrote in post #1061706:

It’s not possible in Ruby, but may be achievable using a C extension.

– Matma R.

Hi,

Yes, indeed it is achievable using a C extension, at least for the
user-defined class.

Regards,

Bill