Problems Using Array Instance Methods in Array Subclasses

Asked 2 years ago, Updated 2 years ago, 36 views

Below is a sample code that uses the Array instance method for the instance of the class that inherited the Array.

class MyArray<Array
end

m=MyArray.new
n = MyArray.new
added=m+n

putsm.class#MyArray
putsn.class#MyArray
puts added.class#Array

We use + here.
As mentioned above, added is an instance of the Array class.

I would like to get a subclass instance at this time.Is there any way?

Additional information

Thank you all for your kind reply.I learned a lot.
The implementation overrides the existing method, and if the return value is superclass, it generates an instance of subclass and uses it as a return value.
I need to use send, and although it looks ugly, I tried using gem.

https://github.com/mmmmmavo/subper_class/blob/master/spec/subper_class_spec.rb

ruby

2022-09-30 16:40

2 Answers

Array#+ returns Array, so if you call the parent class +, it will remain Array.The only way to change this is to overwrite (override) the + method (the term "overload operator" is incorrect because the operator is also just a method in Ruby).However, the problem is not only + but also - and &.Based on that, I thought of a way to overwrite it.

class MyArray<Array
  def+(_)
    MyArray.new(super)
  end
  def -(_)
    MyArray.new(super)
  end
  def&(_)
    MyArray.new(super)
  end
  def|(_)
    MyArray.new(super)
  end
end

If you only write super, call the parent method exactly with the same argument.The return value is Array, so simply MyArray.new() it becomes an instance of MyArray.

Now, four of the same codes came out.For those of you who love DRY, this code doesn't suit you, so let's summarize it.

class MyArray<Array
  def self.new_creation_method(*methods)
    methods.each do | method |
      define_method(method) do | * args, & block |
        MyArray.new(super(*args, & block))
      end
    end
  end
  new_creation_method:+, :-, :&, :|, :uniq, :sort
end

define_method is the Module method for creating instance methods.Ruby can dynamically create instance methods in this way.For more information, see Module#define_method.This super cannot omit arguments.

As in the code above, a method that returns a new Array such as uniq as well as + and - can be defined in the same way, as well as passing blocks such as sort.However, depending on the type and result of the argument, methods that return anything other than Array cannot be supported, so they need to be handled separately.


2022-09-30 16:40

As @metropolis said, I think we need to override the Array#+ method.

The original Array#+ method does the following:

If this is done for MyArray:

The code is as follows.(Using the initialization array, we are doing 1,2 at the same time)

class MyArray<Array
  def+(x)
    MyArray.new(self).concat(x)
  end
end


2022-09-30 16:40

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.