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.

···

--
Posted via http://www.ruby-forum.com/.

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

···

--
Posted via http://www.ruby-forum.com/.

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.

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.

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

···

On Tue, May 22, 2012 at 6:43 AM, David Madison <lists@ruby-forum.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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
    values.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.

--
Posted via http://www.ruby-forum.com/.

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 Rex

···

2012/5/22 David Madison <lists@ruby-forum.com>:

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.

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"]

···

--
Posted via http://www.ruby-forum.com/\.

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 May 22, 2012, at 9:03 AM, Robert Klemme <shortcutter@googlemail.com> wrote:

On Tue, May 22, 2012 at 6:43 AM, David Madison <lists@ruby-forum.com> 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.

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.

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

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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

···

On Tue, May 22, 2012 at 12:17 PM, Jan E. <lists@ruby-forum.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Bartosz Dziewoński wrote in post #1061706:

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

-- Matma Rex

Hi,

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

Regards,

Bill

···

--
Posted via http://www.ruby-forum.com/\.

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(tm).

Cheers

robert

···

On Tue, May 22, 2012 at 8:46 PM, Admin Tensor <lists@ruby-forum.com> wrote:

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

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/