Can subclass have superclass method return instance of subclass

Is it possible to have the Superclass method return an instance of
the Subclass type.

Basically are there any hooks that would allow a Array methods return
an instance of a sub-class of Array.

The partition method would need to return an array of Array
Sublcasses.

I know I can make an Array subclass (or another class altogether)
that itself can be subclassed and would do what I wanted. I just
wondered if there is a much easier general solution that I am
missing.

example:

class Q
attr_accessor :e, :r

def initialize(e,r)
@e,@r = e,r
end
end

class QArray < Array
def sum_e
inject(0){|sum, item| sum+=item.e}
end
end

qArray = QArray.new
qArray << Q.new(49, ‘A’)
qArray << Q.new(50, ‘B’)
qArray << Q.new(51, ‘A’)

puts qArray.class
puts qArray.sum_e
puts qArray.find_all{|item| item.e < 50}.sum_e #fails here

Can find_all defined in Array be coerced into returning
a QArray and not a plain Array?

Thanks,

Walt

···

Walter Szewelanczyk
IS Director
M.W. Sewall & CO. email : walter@mwsewall.com
259 Front St. Phone : (207) 442-7994 x 128
Bath, ME 04530 Fax : (207) 443-6284


walter@mwsewall.com wrote:

class QArray < Array
def sum_e
inject(0){|sum, item| sum+=item.e}
end
end

Why not just put sum_e into Array, instead of creating a subclass? That
would then allow it to be accessed from any array object.

class Array
def sum_e

end
end


sum = a.find_all {…}.sum_e

···


Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis

ruby -h | ruby -e
‘a=;readlines.join.scan(/-(.)[e|Kk(\S*)|le.l(…)e|#!(\S*)/) {|r| a <<
r.compact.first };puts “\n>#{a.join(%q/ /)}<\n\n”’

The simplest solution: add a to_qa method to your QArray class. Then
call it like this:

qArray.find_all{|item| item.e < 50}.to_qa.sum_e

A slightly less-simple solution: Don’t subclass Array, wrap it. Then,
wrap the array methods so it coerces the returned value if an Array is
returned.

class QArray
def initialize(ary)
@ary = ary
end
def sum_e
@ary.inject(0){|sum, item| sum+=item.e}
end
def method_missing(*args)
if @ary.responds_to? args.first
response = @ary.send(*args)
if response.kind_of? Array
QArray.new( response )
else
response
end
else
raise NoMethodError
end
end
end

I didn’t test the code, but I’m pretty sure the logic is sound.

–Mark

···

On Mar 17, 2004, at 8:41 AM, walter@mwsewall.com wrote:

Can find_all defined in Array be coerced into returning
a QArray and not a plain Array?

Hi –

Is it possible to have the Superclass method return an instance of
the Subclass type.

Basically are there any hooks that would allow a Array methods return
an instance of a sub-class of Array.

This question has come up before in several contexts – for instance,
if you subclass String, getting back an instance of MyString (or
whatever) when you do matches or substrings. I believe the short
answer, based on what Matz has said in the past, is no :slight_smile: (at least
not automatically)

One route you might want to take is to lightly wrap the methods whose
behavior you want to change:

class QArray < Array
def find_all
QArray.new.replace(super)
end
end

and this kind of thing could be modularized and done in batches (e.g.,
you could have a SelfReturning module which wrapped a number of
Enumerable methods this way all at once for any class that included
it).

David

···

On Thu, 18 Mar 2004 walter@mwsewall.com wrote:


David A. Black
dblack@wobblini.net

That would work in this simple example… What I find is that I tend
to perform similar tasks on groups of Objects.

We have classes that represent different objects in our domain ie
Customers, invoices, deliveries, etc… and we tend to perform
similar tasks on groups of these classes. Sum all invoices, find
invoices that are overdue, find most recent delivery, etc.

I have created CustomerList, InvoiceLists, etc, so I can embed the
logic of the domain in one area and not have the same logic spread
throughout the application and ui layers. I really don’t want to put
all of that logic in Array, plus then I’d have to do a lot of type
checking in many cases.

Ruby has such beautiful Array functionality that I find I always end
up wanting to use it in my customized subclasses.

Walt

···

walter@mwsewall.com wrote:

class QArray < Array
def sum_e
inject(0){|sum, item| sum+=item.e}
end
end

Why not just put sum_e into Array, instead of creating a subclass?
That would then allow it to be accessed from any array object.

class Array
def sum_e

end
end


sum = a.find_all {…}.sum_e


Walter Szewelanczyk
IS Director
M.W. Sewall & CO. email : walter@mwsewall.com
259 Front St. Phone : (207) 442-7994 x 128
Bath, ME 04530 Fax : (207) 443-6284


walter@mwsewall.com wrote:

That would work in this simple example… What I find is that I tend
to perform similar tasks on groups of Objects.

I use object.extend(Module) a bit, to add aspect-oriented features to
existing objects in my code generator. The generator reads a schema
file creating various kinds of objects, and then, when running one
of (for example) the C# generators (we have 4), I extend the schema
objects with knowledge of C#. Same thing for C++, SQL, documentation,
etc - so the generators don’t duplicate code or require shared
functions, and the knowledge of all generatable languages isn’t built
into the schema objects all the time.

Ruby has such beautiful Array functionality that I find I always end
up wanting to use it in my customized subclasses.

Can’t you get much of what you want my mixing-in Enumerable?

walter@mwsewall.com schrieb im Newsbeitrag
news:4058461D.22531.E498AB@localhost…

class QArray < Array
def sum_e
inject(0){|sum, item| sum+=item.e}
end
end

Why not just put sum_e into Array, instead of creating a subclass?
That would then allow it to be accessed from any array object.

class Array
def sum_e

end
end


sum = a.find_all {…}.sum_e

That would work in this simple example… What I find is that I tend
to perform similar tasks on groups of Objects.

If it’s general enough module Enumerable is the place to put it:

irb(main):001:0> module Enumerable
irb(main):002:1> def sum_e; inject(0){|sum,i|sum+i}; end
irb(main):003:1> end
=> nil
irb(main):004:0> (1…10).to_a.sum_e
=> 55
irb(main):005:0>

We have classes that represent different objects in our domain ie
Customers, invoices, deliveries, etc… and we tend to perform
similar tasks on groups of these classes. Sum all invoices, find
invoices that are overdue, find most recent delivery, etc.

If it’s that special I’d do any of these:

(i) Create a module of your own and extend collections:

irb(main):001:0> module MyEnum
irb(main):002:1> def sum_e; inject(0){|sum,i|sum+i}; end
irb(main):003:1> end
=> nil
irb(main):004:0> a=(1…10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb(main):005:0> a.extend MyEnum
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb(main):006:0> a.sum_e
=> 55

(ii) Create a module (or multiple modules) of your own with the functions
you need:

irb(main):001:0> module EnumAlgorithms
irb(main):002:1> def self.sum_e(enum); enum.inject(0){|sum,i|sum+i}; end
irb(main):003:1> end
=> nil
irb(main):004:0> EnumAlgorithms.sum_e( (1…10).to_a )
=> 55

I have created CustomerList, InvoiceLists, etc, so I can embed the
logic of the domain in one area and not have the same logic spread
throughout the application and ui layers. I really don’t want to put
all of that logic in Array, plus then I’d have to do a lot of type
checking in many cases.

In that case I’d probably choose option (ii) and put the algorithmic
functions into the classes on which they operate, i.e.

class InvoiceLists
def self.sum(invoices)
invoices.inject(0){|sum,inv| sum += inv.amount}
end
end

etc.

Ruby has such beautiful Array functionality that I find I always end
up wanting to use it in my customized subclasses.

Trying to convince methods that return Array to return something else will
not work. Extending Array itself does work but should be done with care
because IMHO only the most general functionality that applies to Arrays
should be there. There are other better ways to solve this (see above).

Kind regards

robert
···

walter@mwsewall.com wrote:

Quoteing cjh-nospam@nospaManagesoft.com, on Thu, Mar 18, 2004 at 07:20:54AM +0900:

Ruby has such beautiful Array functionality that I find I always end
up wanting to use it in my customized subclasses.

Can’t you get much of what you want my mixing-in Enumerable?

Array has lots of useful apis that Enumerable doesn’t. I suspect,
though, that you could define a core set of “Array” operations, and
then write an Arrayable module that when you mix-in, gives you all the
other Array methods (&, *, slice, …) that Enumerable doesn’t have.

Maybe you could even write Arrayable so it is entirely implemented with
each(), but I think it wouldn’t be very efficient, imagine having to
implment by doing each_with_index() until you found the required
index!

Cheers,
Sam

···

walter@mwsewall.com wrote: