Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > extending a core class cleanly [noobish alert]

Reply
Thread Tools

extending a core class cleanly [noobish alert]

 
 
Fearless Fool
Guest
Posts: n/a
 
      07-05-2010
Assume I'd like to create a statistics package designed to work on
Arrays [but see P.S.]. One way to do this would be to create functions
that take an array as an argument:

def mean(array)
return NaN unless array && array.size > 0
array.reduce(0.0) {|accum, val| accum + val} / array.size
end

... but that's so old school. What I'd really like is to *cleanly*
extend the Array class so you can operate on it directly, as in:

>> [1, 2, 3].mean

=> 2.0

I'm sure that it's considered bad style to simply open the Array class
and extend it, since that can lead to unexpected user surprises:

class Array
def mean
return NaN unless self.size > 0
self.reduce(0.0) {|accum, val| accum + val} / self.size
end
end

My hunch is that the stats functions should be wrapped in a module and
then included (extended?) when desired. But despite reading the
tutorials and docs, I'm not sure what's considered the stylistically
correct way (and the syntax) to package that up.

Comments? Pointers?

Thanks!

- ff

[P.S.: Before you tell me about available stats packages, etc, note that
I'm only using statistics as an example. My real question is about
extending a class...]
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
 
 
 
David Masover
Guest
Posts: n/a
 
      07-05-2010
On Monday, July 05, 2010 03:30:44 pm Fearless Fool wrote:
> Assume I'd like to create a statistics package designed to work on
> Arrays [but see P.S.]. One way to do this would be to create functions
> that take an array as an argument:
>
> def mean(array)
> return NaN unless array && array.size > 0
> array.reduce(0.0) {|accum, val| accum + val} / array.size
> end
>
> ... but that's so old school. What I'd really like is to *cleanly*
>
> extend the Array class so you can operate on it directly, as in:
> >> [1, 2, 3].mean

>
> => 2.0
>
> I'm sure that it's considered bad style to simply open the Array class
> and extend it, since that can lead to unexpected user surprises:
>
> class Array
> def mean
> return NaN unless self.size > 0
> self.reduce(0.0) {|accum, val| accum + val} / self.size
> end
> end


What kind of surprises?

> My hunch is that the stats functions should be wrapped in a module and
> then included (extended?) when desired. But despite reading the
> tutorials and docs, I'm not sure what's considered the stylistically
> correct way (and the syntax) to package that up.


Simple enough:

module MyModule
def mean
...
end
end

Then, you can always do this:

[].extend MyModule

Or this:

class Array
include MyModule
end

Then, probably, provide a file people can 'require' that'll do the inclusion
for them, maybe even make that the default.

It might also be nice to provide a way to do this on Enumerables, though that
would be less efficient if you know you have an array. For example:

def mean
size = 0
count = inject(0){|accum, val| size+=1; accum+val}
count / size.to_f
end

 
Reply With Quote
 
 
 
 
Fearless Fool
Guest
Posts: n/a
 
      07-05-2010
David Masover wrote:

> What kind of surprises?


Coming from conventional programming environments, one might be
surprised when a core class suddenly acquires new methods -- e.g.
Rails/ActiveSupport's extensions to String -- so I wanted to make sure I
was packaging such extensions properly.

> Simple enough:
> [snip]


Perfect -- I see how that works now. Thank you.

> Then, probably, provide a file people can 'require' that'll do the
> inclusion for them, maybe even make that the default.


... or if I was feeling adventuresome, perhaps an autoload?

> It might also be nice to provide a way to do this on Enumerables, though
> that would be less efficient if you know you have an array.


Good catch. If I *do* implement a stats package, I'll think about
making it ambidextrous.

Thanks again.

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

 
Reply With Quote
 
Jesús Gabriel y Galán
Guest
Posts: n/a
 
      07-06-2010
On Mon, Jul 5, 2010 at 11:22 PM, David Masover <> wrote:
> On Monday, July 05, 2010 03:30:44 pm Fearless Fool wrote:
>> Assume I'd like to create a statistics package designed to work on
>> Arrays [but see P.S.]. =A0One way to do this would be to create function=

s
>> that take an array as an argument:
>>
>> =A0 def mean(array)
>> =A0 =A0 return NaN unless array && array.size > 0
>> =A0 =A0 array.reduce(0.0) {|accum, val| accum + val} / array.size
>> =A0 end
>>
>> ... but that's so old school. =A0What I'd really like is to *cleanly*
>>
>> extend the Array class so you can operate on it directly, as in:
>> =A0 >> [1, 2, 3].mean
>>
>> =A0 =3D> 2.0
>>
>> I'm sure that it's considered bad style to simply open the Array class
>> and extend it, since that can lead to unexpected user surprises:
>>
>> =A0 class Array
>> =A0 =A0 def mean
>> =A0 =A0 =A0 return NaN unless self.size > 0
>> =A0 =A0 =A0 self.reduce(0.0) {|accum, val| accum + val} / self.size
>> =A0 =A0 end
>> =A0 end

>
> What kind of surprises?
>
>> My hunch is that the stats functions should be wrapped in a module and
>> then included (extended?) when desired. =A0But despite reading the
>> tutorials and docs, I'm not sure what's considered the stylistically
>> correct way (and the syntax) to package that up.

>
> Simple enough:
>
> module MyModule
> =A0def mean
> =A0 =A0...
> =A0end
> end
>
> Then, you can always do this:
>
> [].extend MyModule


I agree, this is the less dangerous thing to do: just extend the
specific array instances with your functionality. That way, all other
arrays are left intact.

Jesus.

 
Reply With Quote
 
David Masover
Guest
Posts: n/a
 
      07-07-2010
On Monday, July 05, 2010 06:16:10 pm Fearless Fool wrote:
> David Masover wrote:
> > What kind of surprises?

>
> Coming from conventional programming environments, one might be
> surprised when a core class suddenly acquires new methods -- e.g.
> Rails/ActiveSupport's extensions to String -- so I wanted to make sure I
> was packaging such extensions properly.


Libraries like that do tend to isolate the syntactic sugar from the utility
code. I think the idea is that you might do this instead:

module MathStuff
def mean(array)
...
end
end

And then, in another file:

class Array
def mean
MathStuff.mean self
end
end

This might be overkill, but the idea here is: If you just require
activesupport, you get all the extensions to string. If you require
active_support/inflector, you get all the string manipulation methods, without
ever having to extend a string -- all your strings stay pure.

I actually don't see a problem with extending String, and I don't see what the
conventional argument is. The _only_ potential problem is namespace conflicts
-- if two different libraries define String#pluralize, and it means a
different thing to each library, you've got a problem.

> > Then, probably, provide a file people can 'require' that'll do the
> > inclusion for them, maybe even make that the default.

>
> ... or if I was feeling adventuresome, perhaps an autoload?


That only automatically works if you then extend/include it at some point. So,
for example, it might make sense like this:

autoload :MathStuff, 'whatever'
...
[].extend MathStuff



It would be kind of wasteful here:



autoload :MathStuff, 'whatever'
class Array
# always loads right now
include MathStuff
end



And it'd be completely useless otherwise.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Cleanly exiting multi thread application on SIGINT jrpfinch Python 2 03-23-2007 01:32 PM
Core Solo & Core Duo are not Core microarchitecture; 65nm Pentium M chips bigal Hardware 0 03-22-2006 11:24 AM
Cleanly end a thread with blocked i/o in win32? Jon Wright Python 2 10-22-2004 12:54 PM
Adding your own site directories cleanly and supportedly? Tim Bradshaw Python 2 05-27-2004 08:53 PM
Problems cleanly breaking a socket connection Kerry Shetline Java 2 12-18-2003 01:42 AM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57