Un-extending objects

Hi –

I’ve become intrigued by the idea of unextending objects – that is,
removing capabilities from them module-wise.

A couple of things that have been mentioned here recently that relate
at least very indirectly to this are: the idea of a “clean” root class
for objects; and the discussion about inheritance (especially from
core classes) leaving an object with “extra” methods. In general, all
of these thoughts seem to pertain to the idea of a the granularity of
the modular, “plug-in” capabilities of Ruby objects.

Anyway, I don’t have any big idea in mind. Just playing around with
the idea of being able to add and remove modules at run-time. My
current little testbed for this looks like this:

Object#stretch(aModule) – extend only for duration of block

class Object
def stretch(mod)
c = class << self; self; end
before = methods
extend(mod)
yield
(methods - before).each { |m| c.class_eval {undef_method(m)} }
end
end

Demo

module Stuff
def talk; puts “hi”; end
end

a = [1,2,3]
a.stretch(Stuff) { a.talk } # hi
p a.respond_to?(:talk) # false

This has a kind of aesthetic or maybe narrative appeal to me: the
capabilities required of an object for a given purpose exist only at a
kind of flashpoint, the exact place and time where they’re needed, and
then they disappear again.

I’m interested in whether people have done things like this before,
whether it looks like the kind of thing one would ever actually use,
etc.

David

···


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

In article Pine.LNX.4.44.0212141930001.8475-100000@candle.superlink.net,

···

dblack@candle.superlink.net wrote:

Hi –

I’ve become intrigued by the idea of unextending objects – that is,
removing capabilities from them module-wise.

A couple of things that have been mentioned here recently that relate
at least very indirectly to this are: the idea of a “clean” root class
for objects; and the discussion about inheritance (especially from
core classes) leaving an object with “extra” methods. In general, all
of these thoughts seem to pertain to the idea of a the granularity of
the modular, “plug-in” capabilities of Ruby objects.

Anyway, I don’t have any big idea in mind. Just playing around with
the idea of being able to add and remove modules at run-time. My
current little testbed for this looks like this:

Object#stretch(aModule) – extend only for duration of block

class Object
def stretch(mod)
c = class << self; self; end
before = methods
extend(mod)
yield
(methods - before).each { |m| c.class_eval {undef_method(m)} }
end
end

Demo

module Stuff
def talk; puts “hi”; end
end

a = [1,2,3]
a.stretch(Stuff) { a.talk } # hi
p a.respond_to?(:talk) # false

This has a kind of aesthetic or maybe narrative appeal to me: the
capabilities required of an object for a given purpose exist only at a
kind of flashpoint, the exact place and time where they’re needed, and
then they disappear again.

I’m interested in whether people have done things like this before,
whether it looks like the kind of thing one would ever actually use,
etc.

I like this.

I’ve been thinking for a while that it would be nice to be able to
un-extend an object. A while back I was doing something where I was
passing an object around and extending it when it arrived somewhere, but I
wanted to un-extend it prior to passing it on the next receiver.

Phil


“Or perhaps the truth is less interesting than the facts?”
Amy Weiss (accusing theregister.co.uk of engaging in ‘tabloid journalism’)
Senior VP, Communications
Recording Industry Association of America

dblack@candle.superlink.net wrote:

Object#stretch(aModule) – extend only for duration of block

Simply beautiful.

martin

  # Object#stretch(aModule) -- extend only for duration of block
  class Object
    def stretch(mod)
      c = class << self; self; end
      before = methods
      extend(mod)
      yield
      (methods - before).each { |m| c.class_eval {undef_method(m)} }
    end
  end

Nice, very nice :-)))

pigeon% cat b.rb
#!/usr/bin/ruby
class Object
   def stretch(mod)
      c = class << self; self; end
      before = methods
      extend(mod)
      yield
      (methods - before).each { |m| c.class_eval {undef_method(m)} }
   end
end

class A
   def a
      puts "a"
   end
end

module M
   def a
      puts "b"
   end
end

a = A.new
a.a
a.stretch(M) { a.a }
a.a
pigeon%

pigeon% b.rb
a
b
b
pigeon%

Guy Decoux

This reminds of me of something I was thinking of recently, which would make
something like this pretty easy:

What if we could change an object’s class (or a class’s parent class) at
runtime?

<side_note>
I started thinking about things we weren’t allowed to do in Ruby after
reading about the development of Arc:

http://www.paulgraham.com/arcll1.html

“By default, allow.”

The idea of allowing just about everything, of assuming the programmer is
brilliant, is a neat idea.
</side_note>

In any case, you could create a subclass of the object’s class with whatever
functionality or mixins you wanted, then switch the object’s class to the
new class, run the block, and switch it back. Assuming this were part of
Ruby, it would allow us to do this without having to grab the singleton
class (which I think is what matz didn’t like, for some reason).
Actually, if the object didn’t already have a singleton class, you wouldn’t
have to create one… though you do have to create the new subclass, so I
don’t see what that buys you, except that you can delete a class.

Chris

Probably you are interested in the followings:

class-in-state, scope-in-state by Keiju ISHITSUKA
http://www.ruby-lang.org/raa/list.rhtml?id=171
http://www.ruby-lang.org/raa/list.rhtml?id=261

import-module by Shin-ichiro HARA
http://www.ruby-lang.org/raa/list.rhtml?id=108

Just FYI.

···

In message Pine.LNX.4.44.0212141930001.8475-100000@candle.superlink.net dblack@candle.superlink.net writes:

I’m interested in whether people have done things like this before,
whether it looks like the kind of thing one would ever actually use,
etc.


kjana@dm4lab.to December 16, 2002
A man is known by the company he keeps.

Actually on a somewhat related idea, I wanted to have an object be able
to mixin an eval’ed set of methods. That way I could dynamically change
them by re-eval’ing changed behavior. Its for a software agent system I
am playing with…anyway…what I did was have a random module created
for my target “Agent” object which was empty of methods. I then eval’ed
the method definitions (String) into that module. Whenever the methods
definitions changed I could then remove all the methods on the module
cleanly and re-eval the defintions. It works really well, but not at
the granularity your describe below (during a method call).

-rich

···

-----Original Message-----
From: dblack@candle.superlink.net
[mailto:dblack@candle.superlink.net]
Sent: Saturday, December 14, 2002 7:46 PM
To: ruby-talk ML
Subject: un-extending objects

Hi –

I’ve become intrigued by the idea of unextending objects –
that is, removing capabilities from them module-wise.

A couple of things that have been mentioned here recently
that relate at least very indirectly to this are: the idea of
a “clean” root class for objects; and the discussion about
inheritance (especially from core classes) leaving an object
with “extra” methods. In general, all of these thoughts seem
to pertain to the idea of a the granularity of the modular,
“plug-in” capabilities of Ruby objects.

Anyway, I don’t have any big idea in mind. Just playing
around with the idea of being able to add and remove modules
at run-time. My current little testbed for this looks like this:

Object#stretch(aModule) – extend only for duration of block

class Object
def stretch(mod)
c = class << self; self; end
before = methods
extend(mod)
yield
(methods - before).each { |m| c.class_eval {undef_method(m)} }
end
end

Demo

module Stuff
def talk; puts “hi”; end
end

a = [1,2,3]
a.stretch(Stuff) { a.talk } # hi
p a.respond_to?(:talk) # false

This has a kind of aesthetic or maybe narrative appeal to me:
the capabilities required of an object for a given purpose
exist only at a kind of flashpoint, the exact place and time
where they’re needed, and then they disappear again.

I’m interested in whether people have done things like this
before, whether it looks like the kind of thing one would
ever actually use, etc.

David


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Hi –

a = A.new
a.a
a.stretch(M) { a.a }
a.a
pigeon%

pigeon% b.rb
a
b
b
pigeon%

Do we consider that a bug or a feature? :slight_smile:

OK, the slightly less compact second iteration:

class Object
def stretch(mod)
c = class << self; self; end
before = methods
cache = {}
mod.instance_methods.select {|m| respond_to?(m)}.each do |m|
alt = “#{id}#{m}”
c.send(:alias_method,alt,m)
cache[alt] = m
end
extend(mod)
yield
cache.each {|alt,m| c.send(:alias_method,m,alt)}
(methods - before).each { |m| c.class_eval {undef_method(m)} }
end
end

I’d rather do this by binding and unbinding methods… but that technique
doesn’t seem to fit exactly.

And there must be thread-related problems with this (aren’t there
always? :slight_smile:

David

···

On Sun, 15 Dec 2002, ts wrote:


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Sorry to reply to my own mail, but…

One thing to realise is that your object is still being extended by the
module. If someone extends the module, your object will also be extended.

The idea I had doesn’t have this problem. (It does have the slightly larger
problem of being currently impossible in Ruby, though. :slight_smile:

Chris

What if we could change an object's class (or a class's parent class) at
runtime?

Bad idea, try to forget about this :slight_smile:

Just an example

   a =

Now change the class of `a' to Hash and ruby just crash.

Guy Decoux

Hi –

···

On Mon, 16 Dec 2002, YANAGAWA Kazuhisa wrote:

In message Pine.LNX.4.44.0212141930001.8475-100000@candle.superlink.net > dblack@candle.superlink.net writes:

I’m interested in whether people have done things like this before,
whether it looks like the kind of thing one would ever actually use,
etc.

Probably you are interested in the followings:

class-in-state, scope-in-state by Keiju ISHITSUKA
http://www.ruby-lang.org/raa/list.rhtml?id=171
http://www.ruby-lang.org/raa/list.rhtml?id=261

import-module by Shin-ichiro HARA
http://www.ruby-lang.org/raa/list.rhtml?id=108

Just FYI.

Indeed – very interesting. I admit I hadn’t scoured RAA, though I’m
not sure the names of those programs would have clued me in to the
similarity of at least a couple of them to what I’ve been hacking at.

David


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

And there must be thread-related problems with this (aren't there
always? :slight_smile:

You have found :slight_smile:

Not tested

   class Object
      def stretch(mod)
         c = dup
         c.extend(mod)
         yield(c)
      end
   end

Guy Decoux

Hi –

···

On Mon, 16 Dec 2002, Chris Pine wrote:

Sorry to reply to my own mail, but…

One thing to realise is that your object is still being extended by the
module. If someone extends the module, your object will also be extended.

I think “someone” would have to be you, though :slight_smile: Given this:

obj.stretch(mod) { … }

mod is not going to change between the start and end of the block,
unless you change it inside the block. (Thread issues apart.)

David


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Hello ts,

Sunday, December 15, 2002, 6:52:30 PM, you wrote:

a =

Now change the class of `a’ to Hash and ruby just crash.

  1. you are right
  2. user classes not derived from c-defined classes ALL are just sort of hash
···


Best regards,
Bulat mailto:bulatz@integ.ru

Hi –

Not tested

class Object
def stretch(mod)
c = dup
c.extend(mod)
yield(c)
end
end

I thought about dup, and avoided it partly because it always seems to
raise issues about deep/shallow copy as well as just being
(potentially) expensive. In this case, also, the resulting semantics
have a different feel:

obj.stretch(mod) {|o| o.blah … }

rather than:

obj.stretch(mod) { obj.blah … }

The first one, to me, doesn’t convey the sense that this object is
being stretch’ed. And I think it would behave differently if, say,
there were multiple references to the object, and you expected all
references to be stretched.

Picking up on the block param thing, though: in the non-dup version,
perhaps ‘yield self’ would be a good idea, so one could chain them:

arr.stretch(ArrayExtras) {
arr.to_hash.stretch(HashExtras) { |h| p h.some_new_thing… }
}

(Getting very hypothetical here :slight_smile:

Qu’est-ce qu’on y pense?

David

···

On Mon, 16 Dec 2002, ts wrote:


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

  obj.stretch(mod) { obj.blah ... }

The problem with this is that it's not thread safe and I don't really want
to debug a script which use #stretch in 2 differents threads because I
think that it will be difficult to find the error.

The first one, to me, doesn't convey the sense that this object is
being stretch'ed.

Not a problem for me : I just see a strange combination of the letters
's', 't', 'r', 'c', 'h' and 'e' :slight_smile:

Guy Decoux

  obj.stretch(mod) { obj.blah ... }

Another problem is that you'll not be able to dump the object after the
call to #stretch

Imagine that you give the object to a method, or call a method), and this
method use #stretch. Latter to try Marshal#dump and you have an error.

Now try to retrieve the reason of this error if you don't know exactly
what all methods do.

Guy Decoux