[PATCH 2 of 2] keyword: eliminate potential reference cycles from kwrepo

Christian Ebert blacktrash at gmx.net
Tue Jul 7 17:43:54 CDT 2009


* Martin Geisler on Tuesday, July 07, 2009 at 22:50:37 +0200
> Matt Mackall <mpm at selenic.com> writes:
> 
>> How do we work around this? Good question. In the case of kwrepo,
>> where we're defining a new class already, the easiest thing to do is
>> simply to superclass:
>> 
>> class baz(foo):
>>  def bar(self):
>>    # add our baz-specific behavior
>>    ...
>>    # fall through to base behavior where appropriate
>>    super(baz, self).bar()
>> 
>> Then no reassignment is necessary and we never need to deal with bound
>> methods.
>
> Right, that makes good sense. And so I would say that the part of the
> patch that adds wrappers like this is unnecessary (since we don't add
> any kwrepo-specific behavior to sopener):
> 
>    class kwrepo(repo.__class__):
>        def sopener(self, *args):
>            return super(kwrepo, self).sopener(*args)

In the code should it be:

    class kwrepo(repo.__class__):
        def file(self, f):
            if f[0] == '/':
                f = f[1:]
            return kwfilelog(self.sopener, kwt, f)

or:

    class kwrepo(repo.__class__):
        def file(self, f):
            if f[0] == '/':
                f = f[1:]
            return kwfilelog(repo.sopener, kwt, f)
                             ^^^^
or doesn't it matter at all?

>> The second issue is repo.foo vs self.foo. If you have something that
>> looks like:
>> 
>> def wrapobject(repo):
>>  class superrepo(repo.__class__):
>>    def foo(self):
>>      repo.val += 1
>>  repo.__class__ == superrepo
>> 
>> ..that repo.val pins a reference to repo from the surrounding scope
>> inside the class definition. When we slap it onto the repo object,
>> repo now contains a reference loop again. Changing that repo.val to
>> self.val cures that.
> 
> With code like this:
> 
>        def commit(self, text='', user=None, date=None, match=None,
>                   force=False, editor=None, extra={}):
>            # use custom commitctx for user commands
>            # other extensions can still wrap repo.commitctx directly
>            repo.commitctx = self.kwcommitctx
>            return super(kwrepo, self).commit(text, user, date, match, force,
>                         editor, extra)
> 
>        def kwcommitctx(self, ctx, error=False):
>            # ...
> 
> where the patch changes repo.commitctx to self.commitctx, would it not
> make more sense to simply override commitctx in the kwrepo subclass?

That's what I did first. But then the "double wrapper" was
proposed for the reasons I try to describe in the comment.

Practical example discussed were external convert extensions.

> If needed, commit could set a flag to signal to commitctx when
> to do something and when to just pass control to the
> superclass.

But what about extensions where you don't know their load order?
 
c
-- 
_B A U S T E L L E N_ lesen! --->> <http://www.blacktrash.org/baustellen/>


More information about the Mercurial-devel mailing list