Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:103370 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 55474 invoked from network); 22 Oct 2018 22:40:58 -0000 Received: from unknown (HELO mail-wm1-f67.google.com) (209.85.128.67) by pb1.pair.com with SMTP; 22 Oct 2018 22:40:58 -0000 Received: by mail-wm1-f67.google.com with SMTP id b203-v6so450484wme.5 for ; Mon, 22 Oct 2018 11:55:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language; bh=yk6YbhwUOOSGWz1TuWoT+BllDdctrrD0ceyf/IbdsXA=; b=J01vS3yeePPeK4lCuxHn6T7Dbfb0ZWpsI7j4RJCflI+x0t1sh2ucFvXeoK+hHVlz3d LWAbWLJK4xLJtFo3pIevN5dudDRBWziCDPivBy/6OkOpALGC4fqc67T1vHtkvk1jkTwP bj6pR9hMpxZGwVsWkVP8j0l4Xd5KF36DHqtOJeaZy5wtGPX64/SJY8Vguc9ICA4FqDSD Ra2AjZ3KH7XX6zT7O1BOebhoihW40kf2hBpkKsjY8BfT8451EHGvseBKrHZzubaJoLqQ CpGRHffVPEC0elclr2Lrypa3szoiIqX2T/j42sWeyyglNNjOZWaErkL1Svp/1y0KtJwm vsjw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language; bh=yk6YbhwUOOSGWz1TuWoT+BllDdctrrD0ceyf/IbdsXA=; b=h7NEIXezY4+4aQGlbRjHu29YZr5hvuiaPxnBEHWgp8vTNW7iyb7eVTq7DvZ2jMXZaE FX5gATdJXT5iQqzx59OctKHc3oFQ/cqxtLp5rTYBBe4pXS1ZpvJIvSJbp0HO877EDQwT dfK81un11WfJ1rTrVRlZOZk+7Q/ecWtcOsgd8RN4k1JBLm0rZuwjTOmNM1JdWLfgTQ91 mHvLnaxTRXF/E4x0bzFVXe54MCalUffJncF8H948sF0+pFUIZkArfkKxkuKqwRrbag3o /to9Tynx1xFOFDxpbkGzPmJ82uiUORCJMVoGItMS8bDMuX92FuGupPSk8S+JW4EijiZX 0BuA== X-Gm-Message-State: ABuFfogP34ljoYYS3wfrZ8OOyBEp9ea6xbAgaeiumR19cw4/jHeBiigG MTfAmXo+xlpB2CvChADV4r9ZJ8eB X-Google-Smtp-Source: ACcGV62j66snGwv9UzktO9NM3t8xYjXFzGZPAZDSLSVQaECWRk4MmNHQfkTbYSn8pIS/FtBewdtXpA== X-Received: by 2002:a1c:bce:: with SMTP id 197-v6mr16335208wml.15.1540234539264; Mon, 22 Oct 2018 11:55:39 -0700 (PDT) Received: from [192.168.0.14] (cpc84253-brig22-2-0-cust114.3-3.cable.virginm.net. [81.108.141.115]) by smtp.googlemail.com with ESMTPSA id k14-v6sm3334899wrq.7.2018.10.22.11.55.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 22 Oct 2018 11:55:38 -0700 (PDT) To: Marco Pivetta Cc: PHP Internals List References: <0047f3c7-3e9e-ef6f-2d7a-e58c316ea751@gmail.com> Message-ID: Date: Mon, 22 Oct 2018 19:55:35 +0100 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) Gecko/20100101 Thunderbird/60.2.1 MIME-Version: 1.0 In-Reply-To: Content-Type: multipart/alternative; boundary="------------F3A24F7C94BC2D21184F7D1D" Content-Language: en-GB Subject: Re: [PHP-DEV] Composition over inheritance: native support for "delegating" methods? From: rowan.collins@gmail.com (Rowan Collins) --------------F3A24F7C94BC2D21184F7D1D Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Hi Marco, Thanks for the response. On 21/10/2018 22:42, Marco Pivetta wrote: >  * If you need to proxy and add behavior, userland libraries already > exist (mostly `doctrine/common` at > https://github.com/doctrine/common/tree/a210246d286c77d2b89040f8691ba7b3a713d2c1/lib/Doctrine/Common/Proxy, > `goaop/framework` at https://github.com/goaop/framework/tree/2.2.0 and > `ocramius/proxy-manager` at > https://github.com/Ocramius/ProxyManager/tree/2.2.2): if you aren't > happy with those, a bit of `ReflectionClass#getMethods()` grunt work > is just fine. We're still talking about edge cases anyway. These are certainly interesting, but they feel rather too "heavyweight" for every day use. Imagine if you had to include a library which used reflection to generate a string and pass it to eval() every time you wanted to sub-class something! Native AOP might come closer to what I was thinking about, but seems to be a very different way of thinking about code structure, rather than something that can be easily mixed with an existing architecture. >  * If you are proposing this syntax for performance reasons, most > current delegation code has almost no noticeable overhead besides a > new stack frame (possibly something the engine could optimise), and > when it is present, it is to avoid I/O (much heavier anyway) My main aim is to make composition feel more like a natural choice in the language. If I may cheekily use your own words against you: > There will be less stuffing functionality in existing code via inheritance, which, in my opinion, is a symptom of haste combined with feature creep. I have often heard it said that "it's a shame languages provide more features for inheritance than composition"; I was thinking about what features might redress that balance. > One problem with delegating calls this way, is that any new method > implemented by an ancestor will not be delegated by default. A better > solution would be to have a single `delegate` keyword that intercepts > all method calls for methods not declared in this class, as if > `__call` was implicitly implemented: This is deliberate; implicitly copying everything from another class would just be reinventing (multiple) inheritance. If the delegated class adds a new public method, it should be a conscious decision whether to a) transparently delegate it; b) explicitly wrap it with custom functionality; or c) completely ignore it. > If you don't do it this way, you end up with a BC break any time an > ancestor defines new public API. Yes, in this case these are > interfaces, so it would already count as BC break, but if the parent > is a class... The point is not that the *ancestors* are interfaces, it's that the proxy is targeting an interface. Consider this scenario: class LibraryImplementation implements FrameworkInterface, LibrarySpecificInterface {     public function thingRequiredByFramework() {}     public function additonalThing() {} } class UserlandWrapper implements FrameworkInterface {     public LibraryImplementation $inner delegate { thingRequiredByFramework }; } Although the wrapper is tied to a particular implementation (for whatever reason), it's only used in the context of the framework. If FrameworkInterface changes, then every class implementing it needs fixing, and that includes the UserlandWrapper (e.g, it might need to wrap a new method call with custom logic); but if LibrarySpecificInterface changes, and LibraryImplementation is updated, there's no relevance to UserlandWrapper. LibraryImplementationis just a tool being used to implement FrameworkInterface; its other abilities are irrelevant. > Anyway, I do think that: > >  1. the language already has all the tooling required to implement > decorators correctly >  2. the addition of a `delegate` functionality would cause more > confusion for something that is already really trivial to > implement/test/read I think the existence of userland libraries like ProxyManager is rather good evidence that the language *doesn't* have very powerful tools for this. But yes, any new feature like this has to be useful enough to justify the extra complexity and learning curve; it may be that the version presented here isn't powerful enough to pass that bar. Regards, -- Rowan Collins [IMSoP] --------------F3A24F7C94BC2D21184F7D1D--