Pre proposal for "Class extension functions"

php.internals

Andrey O Gromov

7 years ago
Hello. I want to do RFS proposal for new language concept - Class extension functions. Syntax will looks like: function DateTime->localTime() { return $this->format('H:i'); } $date = new DateTime(); echo $date->localTime(); Realisation draft already written ( https://github.com/rjhdby/php-src/commit/a54d7d3f8504d2e15908bb0e44de0b2f87683872 ) It is interesting or not?

Sara Golemon

7 years ago
On Mon, Sep 24, 2018 at 6:21 AM Andrey O Gromov <AGromov@alfabank.ru> wrote:
> > I want to do RFS proposal for new language concept - Class extension > functions. >
Bring a little Javascript into PHP? Hrmm, maybe. I can see some value, though I'd offer a few thoughts: 1. Consider requiring that a class opt in to allowing these methods. e.g. `class DateTime implements MethodExtensions {}`. I know that this cuts out the power of this feature considerable, but it also limits the unexpected damage from that power. 2. Consider the impact on scoping. If a mixin can suddently access private properties in a foreign class, that may violate assumptions made by that class. Maybe treat mixins as having public scope to avoid this problem, that would also avoid much of my worries expressed in #1. 3. Pure bikeshed, I would make the syntax use the :: delimiter rather than ->. e.g. function DateTime::localTime() { ... } But that's my C++ hat speaking. -Sara

Levi Morrison

7 years ago
On Mon, Sep 24, 2018 at 5:21 AM Andrey O Gromov <AGromov@alfabank.ru> wrote:
> > Hello. > > I want to do RFS proposal for new language concept - Class extension > functions. > > Syntax will looks like: > > function DateTime->localTime() { > return $this->format('H:i'); > } > > $date = new DateTime(); > > echo $date->localTime(); > > > Realisation draft already written ( > https://github.com/rjhdby/php-src/commit/a54d7d3f8504d2e15908bb0e44de0b2f87683872 > ) > > It is interesting or not?
Definitely interesting. The patch doesn't seem to handle inheritance conflicts, though. For instance, if I add something to a base class that ends up conflicting with a sub-class that is already defined. It may not need to handle it in any particular way, but should be specified at least.

Stephen Reay

7 years ago
> On 24 Sep 2018, at 6:21 pm, Andrey O Gromov <AGromov@alfabank.ru> wrote: > > Hello. > > I want to do RFS proposal for new language concept - Class extension > functions. > > Syntax will looks like: > > function DateTime->localTime() { > return $this->format('H:i'); > } > > $date = new DateTime(); > > echo $date->localTime(); > > > Realisation draft already written ( > https://github.com/rjhdby/php-src/commit/a54d7d3f8504d2e15908bb0e44de0b2f87683872 > ) > > It is interesting or not?
From a user land perspective, I think this is a proverbial truck of boxes of cans of worms. For reference: monkey patching methods onto built-in classes is what gives you shenanigans like the discussion about `[].smoosh` in Javascript. This just opens up a ridiculously wide scope for “we can’t add method X because of a BC break in userland code”. The *only* way I could get behind this, is if it’s made clear in the docs/RFC/wiki/written in the sky/etched on the moon via laser, that literally no future RFC will ever consider “a user land BC break because of ‘class extension functions’ in the wild" a valid reason to reject the RFC. The only officially supported use of this, should be for the one good use of monkey patching in JS: polyfills for missing functionality in older runtimes. For example, SplFileObject was added in PHP 5.1.0, but didn’t have an fread() method until 5.5.11. Cheers Stephen

Stas Malyshev

7 years ago
Hi!
> I want to do RFS proposal for new language concept - Class extension > functions. > > Syntax will looks like: > > function DateTime->localTime() { > return $this->format('H:i'); > }
I feel this is inviting trouble. If you need additional functionality, why not extend the class? Or write a function that accepts DateTime as an argument? This encourages a style of programming where you never know which object does what. Even in JS, as far as I know, it's not exactly the recommended style. But in PHP I don't think we should be doing this. Moreover, if your method accesses private variables (that's the only reason why external method can't do the same) then your code needs to change if private structure of the class changes, which violates encapsulation. And on top of that we have the same namespacing problems we've had when we had no namespaces - what if two packages get a bright idea to define localTime on DateTime? What if they do it in a very slightly different way? I think this wouldn't add much what we already can do, but will invite style of programming that is best avoided.
-- Stas Malyshev smalyshev@gmail.com

Christoph Becker

7 years ago
On 25.09.2018 at 08:50, Stanislav Malyshev wrote:
>> I want to do RFS proposal for new language concept - Class extension >> functions. >> >> Syntax will looks like: >> >> function DateTime->localTime() { >> return $this->format('H:i'); >> } > > I think this wouldn't add much what we already can do, […]
Actually, we can do this for a long time (by using runkit_method_add[1] or uopz_add_function[2]); it would just add a syntactic sugar for it.
> […] but will invite > style of programming that is best avoided.
ACK. [1] <http://php.net/manual/en/function.runkit-method-add.php> [2] <http://php.net/manual/en/function.uopz-add-function.php>
-- Christoph M. Becker

Stas Malyshev

7 years ago
Hi!
> I want to do RFS proposal for new language concept - Class extension > functions. > > Syntax will looks like: > > function DateTime->localTime() { > return $this->format('H:i'); > }
I feel this is inviting trouble. If you need additional functionality, why not extend the class? Or write a function that accepts DateTime as an argument? This encourages a style of programming where you never know which object does what. Even in JS, as far as I know, it's not exactly the recommended style. But in PHP I don't think we should be doing this. Moreover, if your method accesses private variables (that's the only reason why external method can't do the same) then your code needs to change if private structure of the class changes, which violates encapsulation. And on top of that we have the same namespacing problems we've had when we had no namespaces - what if two packages get a bright idea to define localTime on DateTime? What if they do it in a very slightly different way? I think this wouldn't add much what we already can do, but will invite style of programming that is best avoided.
-- Stas Malyshev smalyshev@gmail.com

Sara Golemon

7 years ago
On Tue, Sep 25, 2018 at 1:50 AM Stanislav Malyshev <smalyshev@gmail.com> wrote:
> > I want to do RFS proposal for new language concept - Class extension > > functions. > > > > Syntax will looks like: > > > > function DateTime->localTime() { > > return $this->format('H:i'); > > } > > I feel this is inviting trouble. If you need additional functionality, > why not extend the class? Or write a function that accepts DateTime as > an argument? This encourages a style of programming where you never know > which object does what. Even in JS, as far as I know, it's not exactly > the recommended style. But in PHP I don't think we should be doing this. >
I've been back-burnering this for a few days and I'm with Stas. I don't like this proposal because it adds complexity with relatively little benefit. If I wanted to add utility functions, I could create a proxy class which encapsulates the target and has a getter for passing into typehinted interfaces. You get all the functionality in any existing version of PHP without the added parser/engine complexity. Even static properties (which sadly lack get/set accessors) could be proxied using references so long as you know the statics ahead of time. -Sara

Sebastian Bergmann

7 years ago
On 9/25/18 10:48 PM, Sara Golemon wrote:
> I've been back-burnering this for a few days and I'm with Stas. I > don't like this proposal because it adds complexity with relatively > little benefit.
I only see problems (mostly due to added complexity) and no benefits. -1 from me.