Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:47211 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 58978 invoked from network); 13 Mar 2010 03:22:03 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 13 Mar 2010 03:22:03 -0000 Authentication-Results: pb1.pair.com header.from=gwynne@darkrainfall.org; sender-id=unknown Authentication-Results: pb1.pair.com smtp.mail=gwynne@darkrainfall.org; spf=permerror; sender-id=unknown Received-SPF: error (pb1.pair.com: domain darkrainfall.org from 208.97.132.81 cause and error) X-PHP-List-Original-Sender: gwynne@darkrainfall.org X-Host-Fingerprint: 208.97.132.81 caiajhbdcaib.dreamhost.com Received: from [208.97.132.81] ([208.97.132.81:59856] helo=homiemail-a38.g.dreamhost.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 33/C3-13686-9D40B9B4 for ; Fri, 12 Mar 2010 22:22:02 -0500 Received: from [192.168.1.2] (pool-96-252-5-186.bstnma.fios.verizon.net [96.252.5.186]) (using TLSv1 with cipher AES128-SHA (128/128 bits)) (No client certificate requested) by homiemail-a38.g.dreamhost.com (Postfix) with ESMTP id D6B36D4842; Fri, 12 Mar 2010 19:21:57 -0800 (PST) Mime-Version: 1.0 (Apple Message framework v1077) Content-Type: text/plain; charset=us-ascii In-Reply-To: <416155e11003121828i41e11coe8a681da055baf48@mail.gmail.com> Date: Fri, 12 Mar 2010 22:21:56 -0500 Cc: Etienne Kneuss , internals@lists.php.net Content-Transfer-Encoding: quoted-printable Message-ID: <615C3589-0EE2-41DB-B830-3AD627A5A3B3@darkrainfall.org> References: <416155e11003121750o4b1f8e11j4c9124fdaa34a22d@mail.gmail.com> <416155e11003121828i41e11coe8a681da055baf48@mail.gmail.com> To: Chris Trahey X-Mailer: Apple Mail (2.1077) Subject: Re: [PHP-DEV] RFC - "class underloading" -or- "ancestor overloading" From: gwynne@darkrainfall.org (Gwynne Raskind) On Mar 12, 2010, at 9:28 PM, Chris Trahey wrote: > The old class is still there, think of it as if the inserted = (overloading) > class extends the base (overloaded) class and any classes the were = extending > the base now extend the inserted class. So as far as the runtime, it's > run-of-the-meill inheritance. Methods that are not re-implimented in = the > inserted class are called in the original class, etc. >=20 > It could be implemented either at the time a class is loaded (when we = see > 'overloads' keyword) or perhaps in a function call: > overload_class('Library_Class', 'My_LibClass_Overload'); >=20 > As for conflicts where multiple overloads are attempted, they could be = in > sequence, such that you'd end up having an inheritance chain like = this: >=20 > called_class <-- second_overload <-- first_overload <-- Library_Class = <-- > etc. In Objective-C, one did this in the older days by calling NSObject's = -poseAsClass: method, which would replace the class you sent it to with = the class you specified. Nowadays that approach is strongly discouraged = in favor of method swizzling, a technique by which you replace a = specific class' implementation of a single method with your own (which, = with a minor bit of extra work, can call through to the original). = Internally, it's done by replacing the function pointer in the class' = method table with a new one and returning the old one. Zend's = implementation is slightly more twisted than libobjc's, amusingly = enough, but it's still doable. This is the typical way for a dynamic = language to solve the problem you've described. In PHP I believe the = necessary work is already implemented in runkit via the function = runkit_method_redefine(). You need only install that, or refer to it to = make an extension of your own. If you want this functionality in core, = file a feature request. (I'm personally in favor of making a lot of = runkit's dynamic class tweaking abilities core). As far as I understand your issue, this technique would solve it = cleanly. > On Fri, Mar 12, 2010 at 8:11 PM, Etienne Kneuss = wrote: >=20 >> Hi, >>=20 >> On Sat, Mar 13, 2010 at 2:50 AM, Chris Trahey >> wrote: >>> Perhaps a new concept in class-based OO programming, I'm not sure. >>>=20 >>> Depending on your perspective you could call it ancestor overloading = (or >>> upstream overloading) or class underloading. >>>=20 >>>=20 >>> We are increasingly developing with the aid of frameworks & = libraries. In >>> fact, this idea came from my current project using the Zend = Framework. >>>=20 >>> These libraries, while greatly extensible, are also fairly >> self-extending. >>> That is, they include many classes that extend many classes, which = is >> great. >>>=20 >>> As consumers of these libraries, we can extend the classes and = consume >> the >>> API however we please, but there is one sticking point. >>>=20 >>> We cannot change classes that many other classes extend without = extending >> or >>> changing each child class and then making sure that our code uses = the new >>> class. >>>=20 >>>=20 >>> For a concrete example, I was working with the Zend_Form_Element >> subclasses, >>> and I realized that I wanted to change some of the default behavior = (in >>> Zend_Form_Element). >>>=20 >>> - at this point I will assume the reader understands why I wouldn't = want >> to >>> just start changing the Zend library files - >>>=20 >>> There are many subclasses of Zend_Form_Element. If you want to = change the >>> default behavior for all of them, you have 3 choices currently: >>>=20 >>> 1. Directly edit the Zend_Form_Element file in the library, -bad for >> updates >>> & other projects that use the library >>>=20 >>> 2. subclass Zend_Form_Element and change declaration of the = descendants >> to >>> extend new class - same problems >>>=20 >>> 3. extend each child class and implement those subclasses in your = app >> code >>> -very tedious and TONS of repeated code, breaks consistency of API = for >>> developers. >>>=20 >>>=20 >>> There could be a better way, if we could insert a class into the = family >>> tree. >>>=20 >>> And that's the heart of this idea, so I'll repeat it: >>>=20 >>> * insert a class into the family tree * >>>=20 >>>=20 >>> Image we do it using an alternative keyword to "extends", such as >>> "overloads". >>>=20 >>>=20 >>> Example: >>>=20 >>>=20 >>> class Library_Class { } >>>=20 >>> class Library_Subclass extends Library_Class {} >>>=20 >>> and then: >>>=20 >>> class My_LibClass_Overload overloads Library_Class{} >>>=20 >>>=20 >>> Now new instances of Library_Subclass actually extend >> My_LibClass_Overload, >>> which "extends" Library_Class. The developer would then code >>> My_LibClass_Overload as if it were declared like this: >>>=20 >>> class Library_Class {} >>>=20 >>> class My_LibClass_Overload extends Library_Class {} >>>=20 >>> class Library_Subclass extends My_LibClass_Overload {} >>>=20 >>>=20 >>> But indeed the declaration of Library_Subclass would *not* have to >> change. >>>=20 >>>=20 >>> This way developers could "extend" default functionality and have >> *existing* >>> library classes pick up the new functionality without redeclaring >> anything >>> in the library. >>>=20 >>> Downstream classes would still override any methods that they = redeclare. >> If >>> you wanted to have end-point classes in the library have different >> behavior, >>> you would overload them instead, such as >>>=20 >>> class My_LibSubclass_Overload overloads Lib_Subclass {} >>>=20 >>>=20 >>> The benefit is that the application code can still consume = "standard" >>> classes, such as Library_Subclass and not need to know or care about = the >>> extended functionality. >>>=20 >>>=20 >>> Going back to my concrete example, my code could then still use >>> Zend_Form_Element_Text, but benefit from the modifications I added, >> without >>> me having to touch the library code. >>>=20 >>>=20 >>> I hope I've explained clearly what this could look like. I'm a = younger >>> developer, so forgive me if I'm rough on the terminology -perhaps >>> overload/underload is not the best word for this functionality. = Also, I'm >>> not sure if there are other class-based OO languages that allow this = kind >> of >>> behavior... Prototypal languages perhaps, as is the case with = javascript >> and >>> the Obj.prototype which (combined with anonymous functions) allows = you to >>> extend the "base" functionality of other objects that "extend" it. >>=20 >> Even though it might look appealing from a framework user = perspective, >> it looks fishy from a language design perspective. It sounds like >> you're trying to fix a framework design lack by a language trick. >>=20 >> For the fishy part: what happens to the old class? what about static >> method calls on that old class? What if two classes overwrites the >> same class? Basically it would mean there is no way to know at = compile >> time which class new Foo; is supposed to instantiate. >>=20 >>>=20 >>>=20 >>> Thank you for your comments and thoughts! >>>=20 >>>=20 >>> Chris Trahey >>>=20 >>> Web Applications Developer >>>=20 >>> Database Administrator >>>=20 >>> CSISD [Technology] >>>=20 >>>=20 >>> footnote: I sent this message from a different address and it did = not >> show >>> up. I tested sending to internals-help@lists.php.net and did not get = a >>> response -so I assume there is an outgoing issue on my other = server's >> side. >>> Forgive me if this message shows up again. >>>=20 >>=20 >>=20 >>=20 >> -- >> Etienne Kneuss >> http://www.colder.ch >>=20 -- Gwynne