Is better to subclass or to add methods to an existing class?

I was discussing with a (Python) friend last night. I told him that one
thing I liked better about Ruby than Python was that you could add
methods to already existing methods. For instance, if I wanted to add a
rot13 method to the String class, all I have to do is this:

class String
  def rot13
    tr("A-Za-z", "N-ZA-Mn-za-m")
  end
end

"foobar".rot13

But my friend told me that Python didn’t have that because it was not a
good thing and it was not the proper way to do it. He said that the
true way of doing it, is to subclass (since Python 2.2 can now subclass
builtin types) the base class:

class myStr(str):
  def rot13(self):
      trans = maketrans(
                  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
                  "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm")
      newstring = translate(word, trans)
      return newstring

myStr("foobar").rot13()

or in Ruby

class MyStr < String
  def rot13
    tr("A-Za-z", "N-ZA-Mn-za-m")
  end
end

MyStr.new("foobar").rot13

His main argument was just that, “It’s the Wrong Way ™ to do it”. To
me, it just seems like extra code and added complexity.

Can you enligthen me and tell me if it’s really that bad an idea to add
methods to an existing class, or if he’s just being a Python zealot?

I’d also like to know if other OO languages (SmallTalk, Eiffel, Sather,
etc.) allow class modifications.

Cheers,

Vince

···

Vincent Foley-Bourgon
Email: vinfoley@iquebec.com
Homepage: http://darkhost.mine.nu:81

Hello –

I was discussing with a (Python) friend last night. I told him that one
thing I liked better about Ruby than Python was that you could add
methods to already existing methods. For instance, if I wanted to add a
rot13 method to the String class, all I have to do is this:

class String
>   def rot13
>     tr("A-Za-z", "N-ZA-Mn-za-m")
>   end
> end
>
> "foobar".rot13

But my friend told me that Python didn’t have that because it was not a
good thing and it was not the proper way to do it. He said that the
true way of doing it, is to subclass (since Python 2.2 can now subclass
builtin types) the base class:

I tend to go for the adding methods approach, but there’s always the
issue of name conflicts among different libraries…

For what it’s worth, personally I wouldn’t subclass String to get
rot13 functionality, even if I were opposed to create String#rot13.
I’d rather do something like:

class Rot13
def self.
str.tr(“A-Za-z”, “N-ZA-Mn-za-m”)
end
end

Rot13[“abc”] # => “nop”

David

···

On Thu, 19 Sep 2002, Vincent Foley wrote:


David Alan Black | Register for RubyConf 2002!
home: dblack@candle.superlink.net | November 1-3
work: blackdav@shu.edu | Seattle, WA, USA
Web: http://pirate.shu.edu/~blackdav | http://www.rubyconf.com

I was discussing with a (Python) friend last night. I told him that one
thing I liked better about Ruby than Python was that you could add
methods to already existing methods. For instance, if I wanted to add a
rot13 method to the String class, all I have to do is this:

class String
>   def rot13
>     tr("A-Za-z", "N-ZA-Mn-za-m")
>   end
> end
> 
> "foobar".rot13

But my friend told me that Python didn’t have that because it was not a
good thing and it was not the proper way to do it. He said that the
true way of doing it, is to subclass (since Python 2.2 can now subclass
builtin types) the base class:

class myStr(str):
>   def rot13(self):
>       trans = maketrans(
>                   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
>                   "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm")
>       newstring = translate(word, trans)
>       return newstring
> 
> myStr("foobar").rot13()

or in Ruby

class MyStr < String
>   def rot13
>     tr("A-Za-z", "N-ZA-Mn-za-m")
>   end
> end
> 
> MyStr.new("foobar").rot13

His main argument was just that, “It’s the Wrong Way ™ to do it”. To
me, it just seems like extra code and added complexity.

Can you enligthen me and tell me if it’s really that bad an idea to add
methods to an existing class, or if he’s just being a Python zealot?

I can’t speak of it being a bad idea, but a related feature of Ruby that
may be even more important than extending classes is extending objects.
(I don’t know, can Python even dream of doing this?)

irb(main):001:0> s = “fred”
“fred”
irb(main):002:0> module Fred
irb(main):003:1> def rot13
irb(main):004:2> tr(“A-Za-z”,“N-ZA-Mn-za-m”)
irb(main):005:2> end
irb(main):006:1> end
nil
irb(main):007:0> s.extend Fred
“fred”
irb(main):008:0> s.rot13
“serq”

In this case I don’t pollute the class and I don’t have to
make the expense of subclassing a big class like String.

Vincent Foley-Bourgon
Email: vinfoley@iquebec.com
Homepage: http://darkhost.mine.nu:81

Jim

···

On Thu, Sep 19, 2002 at 09:20:13PM +0900, Vincent Foley wrote:


Jim Freeze

Programming Ruby
def initialize; fun; end
A language with class

Um, what is Python doing with this block of code:

def foo():
print “foo”

?? In Ruby, it simply adds a private method to the current object.

So, if Python does the same (allowing you to add methods to instances
of objects at runtime) then why would being able to add methods to a
class of objects at runtime be the wrong thing?

Granted I think in Ruby the inclination to add methods to existing base
classes instead of subclassing them may be more common than it should
be, but the feature is certainly one that makes Ruby very powerful when
done right.

– Dossy

···

On 2002.09.19, Vincent Foley vinfoley@iquebec.com wrote:

But my friend told me that Python didn’t have that because it was not a
good thing and it was not the proper way to do it. He said that the
true way of doing it, is to subclass (since Python 2.2 can now subclass
builtin types) the base class:


Dossy Shiobara mail: dossy@panoptic.com
Panoptic Computer Network web: http://www.panoptic.com/
“He realized the fastest way to change is to laugh at your own
folly – then you can let go and quickly move on.” (p. 70)

[example modification of existing class snipped]

But my friend told me that Python didn’t have that because it was not a
good thing and it was not the proper way to do it. He said that the
true way of doing it, is to subclass (since Python 2.2 can now subclass
builtin types) the base class:

[python code removed… washing hands…]

His main argument was just that, “It’s the Wrong Way ™ to do it”. To
me, it just seems like extra code and added complexity.

It is the Right Way To Do It if your code passes all its unit and
acceptance tests. It is the Wrong Way To Do It if your code fails to
perform as expected. Beyond that, who cares?

You might perform some trivial benchmark to compare the two on a variety of
base classes and a variety of common “extensions” and reach some overall
efficiency conclusion, though.

Can you enligthen me and tell me if it’s really that bad an idea to add
methods to an existing class, or if he’s just being a Python zealot?

Nope, can’t say. :wink:

Personally if I have a function that takes a string and only a string (like
the example Rot13) then I would extend the String class. Otherwise, while
programming, I have to remember if my strings (lowercase) are Strings or
MyStrings in order to remember which methods they have access to.

But it depends on the application. Maybe in some cases I want two separate
kinds of strings… kind of like how we have lots of separate kinds of
numbers.

-michael

···

On Thursday 19 September 2002 07:20, Vincent Foley wrote:

++++++++++++++++++++++++++++++++++++++++++
Michael C. Libby x@ichimunki.com
public key: http://www.ichimunki.com/public_key.txt
web site: http://www.ichimunki.com
++++++++++++++++++++++++++++++++++++++++++

But my friend told me that Python didn’t have that because it was not a
good thing and it was not the proper way to do it. He said that the
true way of doing it, is to subclass (since Python 2.2 can now subclass
builtin types) the base class:

[snippage]

His main argument was just that, “It’s the Wrong Way ™ to do it”. To
me, it just seems like extra code and added complexity.

Can you enligthen me and tell me if it’s really that bad an idea to add
methods to an existing class, or if he’s just being a Python zealot?

I think it could be considered bad because it can produce
alergic reactions between libraries.

For example:

— LibA
class String
def rot13
tr(A-Za-z,…)
end
end

— LibB
class String
def rot13
puts “rotate 13 degrees”
end
end

···

On Thu, Sep 19, 2002 at 09:20:13PM +0900, Vincent Foley wrote:


require liba
require libb

“fred”.rot13 #=> this will probably not do what you want it to.

Since both libraries have redefined a core class and have added
a method with the same name, there will ultimately be a problem
in the code.

This is why I avoid modifying core libraries and I hope other
library writers do as well.


Jim Freeze

Programming Ruby
def initialize; fun; end
A language with class

But my friend told me that Python didn’t have that because it was not a
good thing and it was not the proper way to do it. He said that the
true way of doing it, is to subclass (since Python 2.2 can now subclass
builtin types) the base class:

  1. He is right that adding methods to an already-defined class is
    generally a bad idea. There are some valid reasons to do that, but
    99% of the time there is an alternative.

    Subclassing is one such alternative. Extending an instance of a
    class is another alternative. Creating a new method that takes your
    object as an explicit parameter instead of as an implicit parameter
    is a third alternative.

  2. Correct me if I’m wrong, but I think python does let you add methods
    at run-time:

    [pbrannan@zaphod pbrannan]$ python
    Python 2.2.1c2 (#1, Apr 8 2002, 18:12:08)
    [GCC 3.0.4] on linux2
    Type “help”, “copyright”, “credits” or “license” for more information.

    class Foo:
    … def foo(self):
    … print “foo!”

    f = Foo()
    f.foo()
    foo!
    f.bar()
    Traceback (most recent call last):
    File “”, line 1, in ?
    AttributeError: Foo instance has no attribute ‘bar’
    def bar(self):
    … print “bar!”

    Foo.dict[‘bar’] = bar
    f.foo()
    foo!
    f.bar()
    bar!

Paul

···

On Thu, Sep 19, 2002 at 09:20:13PM +0900, Vincent Foley wrote:

Subclassing is, I think, the thing to do if you need to extend the
behavior of a class. The case where method-adding becomes useful is
when you need to extend Ruby itself, because subclassing doesn’t alter
the anonymous operators or the classes of object returned by Ruby’s
builtin methods.

For example, if you add a specialized sort function to Hash:

class MyHash < Hash
def sortedkeys
keys.sort
end
end

a = { “foo” => “bar” }

‘a’ will still be a Hash, not a MyHash. There’s no way to tell the {}
constructor to return a MyHash.

And builtins will still return builtin classes:

class MyString < String
def rot13
tr(“A-Za-z”, “N-ZA-Mn-za-m”)
end
end

hex = sprintf(“0x%x”, 12345)

‘hex’ will be an ordinary String, not a MyString. If you tried to do
this with subclassing, you’d have to convert everything that came out
of an anonymous constructor or builtin method into the subclassed
object, which would be tedious.

Dan

···


/^Dan Debertin$/
airboss@nodewarrior.org | Did I sleep a little too late,
www.nodewarrior.org | or am I awake? --Byrne

Vincent Foley wrote:

I was discussing with a (Python) friend last night. I told him that one
thing I liked better about Ruby than Python was that you could add
methods to already existing methods.
[snipped example]
But my friend told me that Python didn’t have that because it was not a
good thing and it was not the proper way to do it. He said that the
true way of doing it, is to subclass (since Python 2.2 can now subclass
builtin types) the base class
[snipped another example]
His main argument was just that, “It’s the Wrong Way ™ to do it”. To
me, it just seems like extra code and added complexity.

First, note that the subclassing technique will not work if you do not
create the objects yourself (i.e. they are created by another part of the
system and you cannot control how they are created.) You could use a
“copy constructor” technique in your subclass to get around this, but it’s
often more trouble than it’s worth and also less efficient.

That said, it’s true that most of the time subclassing is a better idea
because adding methods to an existing class can sometimes lead to name
clashes. Even then, though, you might be better off by dynamically adding
a singleton method to an individual object, rather than an entire class:

my_string = get_my_string_from_somewhere()
def my_string.rot13
tr(“A-Za-z”, “N-ZA-Mn-za-m”)
end

This way your string has rot13 capabilities but other strings will not be
affected by this.

I posted some arguments in favor of the Ruby approach to comp.lang.python
a while back. The post can be found at:

http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&selm=91acf731.0112050832.947307f%40posting.google.com&prev=/groups%3Fq%3Dvoegele%2Bruby%2Bmethod%2Bgroup:comp.lang.python.*%26hl%3Den%26lr%3D%26ie%3DUTF-8%26selm%3D91acf731.0112050832.947307f%2540posting.google.com%26rnum%3D2

(If that URL doesn’t work for you due to wrapping, you can search for the
thread “Python evangelists unite!” on comp.lang.python).

I’d also like to know if other OO languages (SmallTalk, Eiffel, Sather,
etc.) allow class modifications.

Smalltalk allows class modifications, Eiffel does not, I don’t know about
Sather.

···


Jason Voegele
“We believe that we invent symbols. The truth is that they invent us.”
– Gene Wolfe, The Book of the New Sun

In article odji9.4863$3F1.23903@weber.videotron.net,
Vincent Foley vinfoley@iquebec.com writes:

Can you enligthen me and tell me if it’s really that bad an idea to add
methods to an existing class, or if he’s just being a Python zealot?

Currently it is not great idea because name crash in method names.
But if matz introduce selector namespace into Ruby, we can avoid the
problem.

If name crash can be solved (by selector namespace or some prefix),
I think it is good idea. For example, we don’t need Visitor pattern
with such modifiable class.

I’d also like to know if other OO languages (SmallTalk, Eiffel, Sather,
etc.) allow class modifications.

Various (but mainly research) languages have it:
CLOS, AspectJ, MultiJava, Cecil, MixJuice etc.

The author of a paper of MultiJava calls the modifiable class `open
class’.

···


Tanaka Akira

Hi –

Can you enligthen me and tell me if it’s really that bad an idea to add
methods to an existing class, or if he’s just being a Python zealot?

I think it could be considered bad because it can produce
alergic reactions between libraries.

Clearly this is a serious problem, though at the same time I think the
power of all this is just too great to go unused.

<signature_tune>

This is where the (stagnated, I’m afraid) Ruby Behaviors package comes
in. I have to regard it as proof-of-concept more than anything
else… but anyway:

class String
  def rot13
"first version"
  end
end

require 'behaviors-0.0.1/lib/behaviors.rb'

class Behavior
  class ROT13 < Definer
def start
  rot13 = "def rot13; 'behaviors version'; end"
  define(String, "rot13", rot13)
end
  end
end

b = Behavior.new(:ROT13)

puts "abc".rot13
b.adopt { puts "abc".rot13 }    # block form of adopt
puts "abc".rot13

# =>
#   first version
#   behaviors version
#   first version

</signature_tune>

David

···

On Thu, 19 Sep 2002, Jim Freeze wrote:

On Thu, Sep 19, 2002 at 09:20:13PM +0900, Vincent Foley wrote:


David Alan Black | Register for RubyConf 2002!
home: dblack@candle.superlink.net | November 1-3
work: blackdav@shu.edu | Seattle, WA, USA
Web: http://pirate.shu.edu/~blackdav | http://www.rubyconf.com

Actually, because in Ruby a class definition is never closed, don’t we
fundamentally have a similar problem (although possibly with much less
probability, especially when module is used) by subclassing as adding a
method? In other words, the name of subclass that we create may already
be used as a name of some other class.

Regards,

Bill

···

============================================================================
Jim Freeze jim@freeze.org wrote:

I think it could be considered bad because it can produce
alergic reactions between libraries.

(deleted)

Paul Brannan pbrannan@atdesk.com writes:

  1. Correct me if I’m wrong, but I think python does let you add
    methods

    at run-time:

You’re right, there are some objects you can’t do it with though
strings and dictionaries come to mind.

You can do it smoother too. (I admit the ruby way is more explicit).

class Foo:
pass

aFoo = Foo()

def aMethodToBecomeFoosSoon(self, arg):
print self, arg

Foo.method = aMethodToBecomeFoosSoon

aFoo.method(‘aNiceString’)

···

Vennlig hilsen

Syver Enstad

“Paul Brannan”

  1. He is right that adding methods to an already-defined class is
    generally a bad idea. There are some valid reasons to do that, but
    99% of the time there is an alternative.

Well I generally try to avoid this too - but I don’t believe that there
is a very strong case against this (well as long as your code isn’t
intended as an extension for general consumption).

/Christoph

“Tanaka Akira” wrote

I’d also like to know if other OO languages (SmallTalk, Eiffel, Sather,
etc.) allow class modifications.

Various (but mainly research) languages have it:
CLOS, AspectJ, MultiJava, Cecil, MixJuice etc.

The author of a paper of MultiJava calls the modifiable class `open
class’.

This is a rather interesting collection of languages

3 out 5 have multi-method support of some kind (I never
heard of MixJuice so maybe it is really 4 out 5).

This runs squarely against a prominent argument of the
anti multi-method camp'' that Ruby's open classes’’
(a very descriptive term btw.) somehow reduce the need
of method overloading.

Apparently the exact opposite seems to be true:
Method overloading (preferable in the incarnation of
full blown multi-methods) and '‘class openness’ seem
to form a very strong synergy …

/Christoph

Fri, 20 Sep 2002 14:40:35 +0900, Christoph chr_news@gmx.net pisze:

This runs squarely against a prominent argument of the anti multi-method camp'' that Ruby's open classes’’ (a very descriptive
term btw.) somehow reduce the need of method overloading.

Apparently the exact opposite seems to be true: Method overloading
(preferable in the incarnation of full blown multi-methods) and
'‘class openness’ seem to form a very strong synergy …

It seems logical to me. If methods are standalone objects, it’s
easy to do both multidispatch (looking up classes inside a method,
not methods inside a class - lookup is more complicated but there is
no problem where to look up) and creating methods anytime (classes
aren’t modified so it makes no sense to freeze them; they are methods
which are modified).

···


__("< Marcin Kowalczyk
__/ qrczak@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/

You can create the subclass inside a “namespace”, e.g.:

module MyProject
class String < ::String

end
end

You can also create an anonymous subclass:

class Foo
@@my_string = Class.new(String)
end

Paul

···

On Fri, Sep 20, 2002 at 01:20:37AM +0900, William Djaja Tjokroaminata wrote:

Actually, because in Ruby a class definition is never closed, don’t we
fundamentally have a similar problem (although possibly with much less
probability, especially when module is used) by subclassing as adding a
method? In other words, the name of subclass that we create may already
be used as a name of some other class.

This runs squarely against a prominent argument of the
``anti multi-method camp'' that Ruby's ``open classes''
(a very descriptive term btw.) somehow reduce the need
of method overloading.

Well expect that you forget that

  Coercion + Overloading = Chaos

and ruby has coercion

Guy Decoux

“Paul Brannan” wrote in

You can also create an anonymous subclass:

class Foo
@@my_string = Class.new(String)
end

Anonymous subclasses are pain to work with btw.

  • because of scoping problems you often have to
    use the evil string eval …
···

Beast = self
(@temptation = Class.new String).class_eval <<-Body
Beast = self
def six_six_six; Beast end
Body

/Christoph

“ts” wrote

Well expect that you forget that

Coercion + Overloading = Chaos

and ruby has coercion

Well you would (better finally could) get ride of
coercion … not that I would miss the latter a
micro,pico, nano, … second;-)

/Christoph