Path: csiph.com!usenet.pasdenom.info!weretis.net!feeder1.news.weretis.net!feeder.erje.net!eu.feeder.erje.net!newsfeed.xs4all.nl!newsfeed2a.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.003 X-Spam-Evidence: '*H*': 0.99; '*S*': 0.00; 'languages.': 0.04; '21,': 0.07; 'debugging': 0.07; 'nasty': 0.07; '22,': 0.09; 'callback': 0.09; 'namespace': 0.09; 'references.': 0.09; 'themselves,': 0.09; 'works.': 0.09; 'cc:addr:python-list': 0.11; 'python': 0.11; 'assume': 0.14; 'creates': 0.14; 'accepts': 0.16; 'callable': 0.16; 'closures': 0.16; 'determining': 0.16; 'expecting': 0.16; 'garbage': 0.16; 'it".': 0.16; 'objects.': 0.16; 'subclass': 0.16; 'surprises': 0.16; 'surprising': 0.16; 'weird.': 0.16; 'with?': 0.16; 'weird': 0.16; 'thanks,': 0.17; 'wrote:': 0.18; 'code.': 0.18; 'library': 0.18; 'trying': 0.19; 'possible,': 0.19; 'feb': 0.22; 'code,': 0.22; 'python?': 0.22; 'saying': 0.22; 'cc:addr:python.org': 0.22; "aren't": 0.24; 'certainly': 0.24; 'library,': 0.24; 'rid': 0.24; 'decide': 0.24; 'earlier': 0.24; 'cc:2**0': 0.24; '(see': 0.26; 'logging': 0.26; 'references': 0.26; 'pass': 0.26; 'least': 0.26; 'header:In-Reply-To:1': 0.27; 'idea': 0.28; 'point': 0.28; 'chris': 0.29; 'am,': 0.29; 'bigger': 0.30; 'originally': 0.30; "i'm": 0.30; 'work.': 0.31; '(which': 0.31; 'code': 0.31; 'end,': 0.31; 'probably': 0.32; 'agreed': 0.32; 'figure': 0.32; 'another': 0.32; 'guess': 0.33; 'sense': 0.34; 'maybe': 0.34; 'could': 0.34; 'problem': 0.35; "can't": 0.35; 'agree': 0.35; 'problem.': 0.35; 'something': 0.35; 'objects': 0.35; 'point.': 0.35; 'but': 0.35; 'received:google.com': 0.35; 'there': 0.35; 'really': 0.36; 'combination': 0.36; 'object,': 0.36; 'done': 0.36; 'next': 0.36; 'charset:us-ascii': 0.36; 'so,': 0.37; 'clear': 0.37; 'message- id:@gmail.com': 0.38; 'handle': 0.38; 'list,': 0.38; 'anything': 0.39; 'expect': 0.39; 'how': 0.40; 'even': 0.60; 'remove': 0.60; 'skip:u 10': 0.60; 'around.': 0.60; 'deleting': 0.60; 'event.': 0.60; 'most': 0.60; 'break': 0.61; 'matter': 0.61; 'simply': 0.61; "you're": 0.61; 'you.': 0.62; 'back': 0.62; 'header:Message-Id:1': 0.63; 'real': 0.63; 'more': 0.64; 'different': 0.65; 'to:addr:gmail.com': 0.65; 'effectively': 0.66; 'realized': 0.68; 'obvious': 0.74; 'surprise': 0.74; 'subject:Design': 0.78; "'dead'": 0.84; '2015': 0.84; 'around,': 0.84; 'grave': 0.84; 'haunt': 0.84; 'road.': 0.84; 'subject:thought': 0.84 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=content-type:mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=cPCakbLlnKU/+Hgwidp2qu04d0b/b9qoedCB59bfxkI=; b=XgMXyYPjOv4H7QGud3MBaPTHIoChNb5BKor7zPf+uOxbYhfPhga6LLPGpiMHfIerIk GAXg7mQ+KbMf95AA5C9PLgFj0H+Nu37leFsMS0aBiBCRIY4CnBQq3tEgoO5YBhPt5lip QGJvSPLi9gGfsaE/rFwM0VgVDbJLA+rOWUARMdjZBDUAqjgyHQe5dkVRZl8X2N3KkY9H g8/TLoKgJ7WxUQmd4lTWDuSWvxsM+FsP9nKBWW6GeIDY1zM2ahajDIOZYrTbEpLRNG8+ 4dOCGhdOp+e9H7xVAFVo9kGSXNMKl7/ywYOhyFZK7r8qtLA7plJLjQzos3qSm+uB09CZ tDSw== X-Received: by 10.140.38.197 with SMTP id t63mr5480891qgt.61.1424527663663; Sat, 21 Feb 2015 06:07:43 -0800 (PST) Content-Type: text/plain; charset=us-ascii Mime-Version: 1.0 (Mac OS X Mail 6.6 \(1510\)) Subject: Re: Design thought for callbacks From: Cem Karan In-Reply-To: Date: Sat, 21 Feb 2015 09:07:42 -0500 Content-Transfer-Encoding: quoted-printable References: <33677AE8-B2FA-49F9-9304-C8D93784255D@gmail.com> <39813568-6DB8-4341-A130-C256CFF352EE@gmail.com> To: Chris Angelico X-Mailer: Apple Mail (2.1510) Cc: "comp.lang.python" X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 63 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1424527666 news.xs4all.nl 2898 [2001:888:2000:d::a6]:48504 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:86035 On Feb 21, 2015, at 8:15 AM, Chris Angelico wrote: > On Sun, Feb 22, 2015 at 12:13 AM, Cem Karan = wrote: >> OK, so it would violate the principle of least surprise for you. = Interesting. Is this a general pattern in python? That is, callbacks = are owned by what they are registered with? >>=20 >> In the end, I want to make a library that offers as few surprises to = the user as possible, and no matter how I think about callbacks, they = are surprising to me. If callbacks are strongly-held, then calling 'del = foo' on a callable object may not make it go away, which can lead to = weird and nasty situations. Weakly-held callbacks mean that I (as the = programmer), know that objects will go away after the next garbage = collection (see Frank's earlier message), so I don't get 'dead' = callbacks coming back from the grave to haunt me. >>=20 >> So, what's the consensus on the list, strongly-held callbacks, or = weakly-held ones? >=20 > I don't know about Python specifically, but it's certainly a general > pattern in other languages. They most definitely are owned, and it's > the only model that makes sense when you use closures (which won't > have any other references anywhere). I agree about closures; its the only way they could work. When I was = originally thinking about the library, I was trying to include all types = of callbacks, including closures and callable objects. The callable = objects may pass themselves, or one of their methods to the library, or = may do something really weird. =20 Although I just realized that closures may cause another problem. In my = code, I expect that many different callbacks can be registered for the = same event. Unregistering means you request to be unregistered for the = event. How do you do that with a closure? Aren't they anonymous? > If you're expecting 'del foo' to destroy the object, then you have a > bigger problem than callbacks, because that's simply not how Python > works. You can't _ever_ assume that deleting something from your local > namespace will destroy the object, because there can always be more > references. So maybe you need a more clear way of saying "I'm done > with this, get rid of it". Agreed about 'del', and I don't assume that the object goes away at the = point. The problem is debugging and determining WHY your object is = still around. I know a combination of logging and gc.get_referrers() = will probably help you figure out why something is still around, but I'm = trying to avoid that headache. =20 I guess the real problem is how this creates cycles in the call graph. = User code effectively owns the library code, which via callbacks owns = the user code. I have no idea what the best point the cycle is to break = it, and not surprise someone down the road. The only idea I have is to = redesign the library a little, and make anything that accepts a callback = actually be a subclass of collections.abc.Container, or even = collections.abc.MutableSet. That makes it very obvious that the object = owns the callback, and that you will need to remove your object to = unregister it. The only problem is how to handle closures; since they = are anonymous, how do you decide which one to remove? Thanks, Cem Karan=