[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: Underpinnings of Method Wrapping

Peter

12/2/2003 7:02:00 PM

1 Answer

T. Onoma

12/2/2003 8:47:00 PM

0

Peter:

You won't beleive what I just did! I am working on a program for
distrowatch.com and I decided I wanted to change how a method worked in a
standard class, I speedily typed:

class NilClass
def split(*args)
super || [ ]
end
end

Thinking split already existed. Of course then it dawned on me that NilClass
doesn't have a split function yet, so the super would not work anyway despite
the fact that I'm also not making a subclass. All of which is very telling,
because as a programmer (or as the Ruby interpretor) the following descision
tree must be figured out:

subclassing -> exists -> def -> call super => outer class wrap
subclassing -> exists -> def -> no super => redefine
subclassing -> exists -> wrap -> call super => same as def or ERROR?
subclassing -> exists -> wrap -> no super => same as redef or ERROR?
subclassing -> not exists -> def -> call super => ERROR
subclassing -> not exists -> def -> no super => define
subclassing -> not exists -> wrap -> call super => ERROR
subclassing -> not exists -> wrap -> no super => same as define or ERROR?
not subclassing -> exists -> def -> call super => redefine w/ out. class wrap
not subclassing -> exists -> def -> no super => redefine
not subclassing -> exists -> wrap -> call super => wrap
not subclassing -> exists -> wrap -> no super => same as redef or ERROR or?
not subclassing -> not exists -> def -> call super => ERROR
not subclassing -> not exists -> def -> no super => define
not subclassing -> not exists -> wrap -> call super => ERROR
not subclassing -> not exists -> wrap -> no super => same as define or ERROR?

Lots of fun, huh? ;-) And this doesn't take into account the descisions of
outer vs. inner wrapping. (Note: class wrap means the effective wrapping of
the superclass' method; it is necessarily outer) So if you ask me the above
descision tree is too complex, and is really on the verge of becoming too
unwieldy for any ordinary programmer.

> If you had called it that, I'd have known what you meant right away!

I will keep calling it that then. :-) For clearity I'm going to start using
the following terms:

outer - a wrap that remians even when the prime method is redefined
inner - a wrap the is removed when the prime method is redefined
passive - a wrap that does not alter functionality in any way
active - a wrap that alters functionality in some way
shrink - same as superwrap

> But to go a bit further, I'm wondering whether we should make a difference
> at all and just have the programmer indicate whether the wrap should be
> removed on primary redefinition or not - I mentioned the basic idea once
> upon a time in [ruby-talk:86551]. Even wraps that are intrinsic can be
> generic, e.g.,
>
> def foo(*args)
> args.map! { |a|
> if a.respond_to? :unpack
> a.unpack
> else
> a
> end
> }
> result = super
> if result.respond_to? :pack
> result.pack
> else
> result
> end
> end
>
> I realize pack and unpack clash with the methods of String and Array, but
> that's what those method indicators are for. But point is that the method
> above not necessarily needs discarding, even if it does influence the
> arguments and result. So maybe that too is up to the programmer to decide.
> If he says the wrap should be kept, and it breaks things, then he should
> fix it. If he was right, all's well.

That's a good point. And I am leaning in its favor. But to be sure about this
I think we will need to carefully think about how code gets reused. With
patient thinking on this matter, we'll come to a certain conclusion on how
this should work.

> I know that that's a break from Matz's proposal for pre and post where the
> call to super is implicit and it is (apparently) easily enforced that the
> arguments to super and its results are left alone. I never questioned that
> that was a Good Thing. But it's only skin deep since the internal state of
> the arguments and results can be changed anyhow (String#gsub! being an
> example); also the internal state of self can be changed, and all
> practical protection against that is again only skin deep. We can protect
> the interface - or the skin if you want - but to what avail?

Well, it dosen't matter so much what Matz has previously thought, if we find
something better for good reasons. And if we explain it well enough he'll
understand (I hope).

> So my conclusion is that maybe we should have two separate keywords for
> "submethod wraps" and "watch wraps", and be done with it. Ruby will
> discard the former when the primary method is redefined, and will keep the
> latter. And the rest is the programmer's responsibility. What do you
> think?

I like the simplicty of it. But I'm not sure yet. Something tells me that
having a safe way to wrap, even if its only method interface safe, is
important.

> Hmmmm, thinking about it some more, it seems that maybe we're unifying two
> concepts that are really orthogonal. On one hand there's whether a wrap
> should go when the primary method goes or whether it should stay. On the
> other hand there's whether the interface (args + result) is meddled with
> or not. I think the former is a functional difference, while the latter
> feels like a documentation issue because nothing happens with it at run
> time.

Yep, pretty close to right on.

> > BTW: did you read ruby-talk:86785?
>
> I read it, but not thoroughly. It's on my toread pile for when my mind
> unblanks.

Get to it when you can. I think there's a good idea in there that's related,
basically the idea of singleton mixins.

-t0

P.S. By the way, I think we've certainly come along way already!