RFC: Single-Expression functions

php.internals

Dmitry Derepko

1 year ago
Hi, Internals! I hope this message finds you well. I would like to respectfully propose single-expression functions for PHP: https://wiki.php.net/rfc/single-expression-functions I've had extensive experience working with Kotlin, which offers a modern approach to Java development and enables cleaner, more intuitive code. Through this experience, I've encountered various concise syntax features, and I believe one of them—single-expression functions—could be a valuable addition to PHP. I'm aware that Larry Garfield previously proposed a similar feature several years ago, though it unfortunately didn't pass the voting stage. I would like to respectfully suggest that using "=" instead of "=>" to separate declaration and implementation might be a better approach. I believe this proposal aligns well with PHP's current modernization efforts and the ongoing initiative to simplify various language constructs. PHP has been consistently improving developer experience through features like property promotion, arrow functions, the nullsafe operator, getters/setters, and other syntax enhancements. This single-expression function syntax would be a natural continuation of this trend, further streamlining the developer workflow and making PHP more pleasant to write. The primary motivation is to help streamline "data classes" by eliminating the need for "{", "return", and "}", which can sometimes account for up to 30% of the code in such classes. This improvement would be particularly timely as it directly enhances developer experience—a key focus of PHP's recent evolution. I would greatly appreciate your thoughts and feedback on this proposal, and I'm looking forward to engaging in constructive discussion with the community. Thank you for your time and consideration. --- Dmitriy Derepko

Anton Smirnov

1 year ago
Hi Dmitriy On 22/05/2025 12:24, Dmitry Derepko wrote:
> I'm aware that Larry Garfield previously proposed a similar feature > several years ago, though it unfortunately didn't pass the voting stage. > I would like to respectfully suggest that using "=" instead of "=>" to > separate declaration and implementation might be a better approach.
That looks like the weakest part of the proposition because we already have two places where inline bodies are used: the mentioned arrow functions and property hooks public string $foo { get => 'dynamic value'; } No sense in introducing a new syntax for basically just another case of inline function body.
> // oneline > function handle(string $input): string = func1($input) |> func2(...)
|> func3(...) |> func4(...); That looks like a callable assignment like you know $f = fn ($bar) => $this->bar + $bar; class Foo { private $bar; public function bar() = $f; } that may confuse users, another argument for =>
-- Anton

Larry Garfield

1 year ago
On Thu, May 22, 2025, at 8:53 PM, Anton Smirnov wrote:
> Hi Dmitriy > > On 22/05/2025 12:24, Dmitry Derepko wrote: > > I'm aware that Larry Garfield previously proposed a similar feature > > several years ago, though it unfortunately didn't pass the voting stage. > > I would like to respectfully suggest that using "=" instead of "=>" to > > separate declaration and implementation might be a better approach.
> That looks like the weakest part of the proposition because we already > have two places where inline bodies are used: the mentioned arrow > functions and property hooks > > public string $foo { get => 'dynamic value'; } > > No sense in introducing a new syntax for basically just another case of > inline function body. > > > // oneline > > function handle(string $input): string = func1($input) |> func2(...) > |> func3(...) |> func4(...); > > That looks like a callable assignment like you know > > $f = fn ($bar) => $this->bar + $bar; > > class Foo { > private $bar; > > public function bar() = $f; > } > > that may confuse users, another argument for => > > -- > Anton
Like Anton, I believe the arguments for using => and not = are strong, as detailed in the original RFC. Other than that, I am unsurprisingly in favor of short-function syntax. If memory serves, the main argument against last time was "it doesn't actually do anything." It's purely sugar. Which is true, but IMO also not a fully compelling argument. Constructor promotion is purely sugar, but it absolutely makes life better. The short-hooks syntax is purely sugar, but makes life better. The question is whether the QoL improvement of the sugar justifies the engine complexity + conceptual complexity (for readers) that every feature comes with. In this case, the engine complexity is not zero, but pretty close to it. The conceptual complexity is also low, especially if using =>. It is already established to mean "evaluates to", which is exactly what is described here. So the overall cost of this change would be quite low. While the QoL benefit is not as large as it was for constructor promotion (which was huge), I do believe it is large enough to justify the fairly low cost. Especially as we integrate more and more expression-oriented features over time (pipes, null-safe methods, match(), throwable expressions, etc), which increases the surface area where the benefits will be felt. --Larry Garfield

Dmitry Derepko

1 year ago
Thanks for your replies. There is no big deal for me to use `=>` instead of `=`. Just used to use `=`. I’ll change it then. Thought there would be more thoughts against the RFC, but the voting will show these votes. Could someone help me with the RFC process? Should I open the vote? ---------- Dmitrii Derepko. @xepozz

Tim Düsterhus

1 year ago
Hi On 5/26/25 20:14, Dmitry Derepko wrote:
> Could someone help me with the RFC process? Should I open the vote?
Please find https://wiki.php.net/rfc/howto for an explanation of the process. An RFC needs *at least* two weeks of discussion, depending on the complexity of the RFC it should probably be longer to give everyone sufficient time to read the RFC and think it through. Personally I did not yet have time to carefully read and understand the RFC to provide proper feedback. Best regards Tim Düsterhus

Larry Garfield

1 year ago
On Mon, May 26, 2025, at 1:14 PM, Dmitry Derepko wrote:
> Thanks for your replies. > > There is no big deal for me to use `=>` instead of `=`. Just used to > use `=`. I’ll change it then. > > Thought there would be more thoughts against the RFC, but the voting > will show these votes. > Could someone help me with the RFC process? Should I open the vote?
As Tim said, it needs at least a 2 week discussion period. It's also good practice to give it a few days after the last meaningful change, and announce an intent to open the vote a day or three in advance. Did I miss it or did I not see a PR linked from the RFC? While technically having an implementation is not a prerequisite of an RFC, it is strongly recommended. (Also, having written the original patch, I'm curious if you're doing it the same way I did. It also may be sensible to use the compile step rather than strictly the lexer; moving pipes from strictly lexer to a compile step was a very smart move, for instance, as it simplified a lot of the ancillary behavior around debugging and error messages.) --Larry Garfield

Dmitry Derepko

1 year ago
As Tim said, it needs at least a 2 week discussion period. Could you share the reference? Did I miss it or did I not see a PR linked from the RFC? While technically having an implementation is not a prerequisite of an RFC, it is strongly recommended. (Also, having written the original patch, I'm curious if you're doing it the same way I did. It also may be sensible to use the compile step rather than strictly the lexer; moving pipes from strictly lexer to a compile step was a very smart move, for instance, as it simplified a lot of the ancillary behavior around debugging and error messages.) Here it is. I've added the link to the RFC. It was one of my first PRs in PHP, so I did the things I only learned from there. Lexer still should be adjusted to accept `=>` syntax. ---------- Best regards, Dmitrii Derepko. @xepozz

Tim Düsterhus

1 year ago
Hi Am 2025-05-27 09:08, schrieb Dmitry Derepko:
> As Tim said, it needs at least a 2 week discussion period. > > > Could you share the reference?
I already did in my email: https://wiki.php.net/rfc/howto (“When discussion ends, and a minimum period of two weeks has passed”).
> Here it is. I've added the link to the RFC. >
It took me a while to find the link in the “References” section, because that's not where I expected it based on other RFCs. Overall the RFC diverges from the RFC template quite a bit. As an example, the “RFC Impact” section is entirely missing. The “Voting Choices” section is as well. The “Metadata” section at the top is formatted differently for no reason (and still indicates that the RFC is a Draft). As far as I can tell it's also not listed in the RFC overview at https://wiki.php.net/rfc either. As a first-time RFC author, I would recommend you strictly following the template and the “RFC How-To” to make sure that the RFC is complete and follows proper process. Best regards Tim Düsterhus

Dmitry Derepko

1 year ago
Thanks Tim for the answer. Your replies went to the Spam folder. I don't know why. I'll change the template as you suggested as soon as possible. On Tue, May 27, 2025 at 1:11 PM Tim Düsterhus <tim@bastelstu.be> wrote:
> Hi > > Am 2025-05-27 09:08, schrieb Dmitry Derepko: > > As Tim said, it needs at least a 2 week discussion period. > > > > > > Could you share the reference? > > I already did in my email: https://wiki.php.net/rfc/howto (“When > discussion ends, and a minimum period of two weeks has passed”). > > > Here it is. I've added the link to the RFC. > > > > It took me a while to find the link in the “References” section, because > that's not where I expected it based on other RFCs. Overall the RFC > diverges from the RFC template quite a bit. As an example, the “RFC > Impact” section is entirely missing. The “Voting Choices” section is as > well. The “Metadata” section at the top is formatted differently for no > reason (and still indicates that the RFC is a Draft). As far as I can > tell it's also not listed in the RFC overview at > https://wiki.php.net/rfc either. > > As a first-time RFC author, I would recommend you strictly following the > template and the “RFC How-To” to make sure that the RFC is complete and > follows proper process. > > Best regards > Tim Düsterhus >
-- Dmitriy Derepko

Dmitry Derepko

1 year ago
I've changed the structure, followed the rfc template now. The voting section isn't available now, because the RFC is under discussion. On Tue, May 27, 2025 at 10:58 PM Dmitry Derepko <xepozzd@gmail.com> wrote:
> Thanks Tim for the answer. > > Your replies went to the Spam folder. I don't know why. > > I'll change the template as you suggested as soon as possible. > > On Tue, May 27, 2025 at 1:11 PM Tim Düsterhus <tim@bastelstu.be> wrote: > >> Hi >> >> Am 2025-05-27 09:08, schrieb Dmitry Derepko: >> > As Tim said, it needs at least a 2 week discussion period. >> > >> > >> > Could you share the reference? >> >> I already did in my email: https://wiki.php.net/rfc/howto (“When >> discussion ends, and a minimum period of two weeks has passed”). >> >> > Here it is. I've added the link to the RFC. >> > >> >> It took me a while to find the link in the “References” section, because >> that's not where I expected it based on other RFCs. Overall the RFC >> diverges from the RFC template quite a bit. As an example, the “RFC >> Impact” section is entirely missing. The “Voting Choices” section is as >> well. The “Metadata” section at the top is formatted differently for no >> reason (and still indicates that the RFC is a Draft). As far as I can >> tell it's also not listed in the RFC overview at >> https://wiki.php.net/rfc either. >> >> As a first-time RFC author, I would recommend you strictly following the >> template and the “RFC How-To” to make sure that the RFC is complete and >> follows proper process. >> >> Best regards >> Tim Düsterhus >> > > > -- > Dmitriy Derepko >
-- Best regards, Dmitrii Derepko. @xepozz

Larry Garfield

1 year ago
On Tue, Jun 3, 2025, at 12:11 PM, Dmitry Derepko wrote:
> I've changed the structure, followed the rfc template now. > > The voting section isn't available now, because the RFC is under discussion.
Hi Dmitrii. Are you going to continue this? If you want to bring it to a vote for this release, it needs to be done very soon. :-) (I'm happy to help if I can. Feel free to ping me off-list or in the PHPC Discord.) --Larry Gafield

Ilija Tovilo

1 year ago
Hi Dmitry Thanks for your interest in improving PHP. On Thu, May 22, 2025 at 11:25 AM Dmitry Derepko <xepozzd@gmail.com> wrote:
> > https://wiki.php.net/rfc/single-expression-functions
In the "Single-Expression functions in other languages" section, at least the Rust and Swift examples are wrong, as such a syntax does not exist for either of them. In case you got this info from an LLM, you should always fact-check whatever an AI tells you. Ilija

Dmitry Derepko

1 year ago
On May 26, 2025, at 11:05 PM, tovilo.ilija <tovilo.ilija@gmail.com> wrote: In the "Single-Expression functions in other languages" section, at least the Rust and Swift examples are wrong, as such a syntax does not exist for either of them. In case you got this info from an LLM, you should always fact-check whatever an AI tells you. Sure I did. Seems like I was confused by specifying a variable type along with the assigned value: Documentation <https://docs.swift.org/swift-book/documentation/the-swift-programming-language/functions/#Using-Function-Types> docs.swift.org <https://docs.swift.org/swift-book/documentation/the-swift-programming-language/functions/#Using-Function-Types> [image: favicon.ico] <https://docs.swift.org/swift-book/documentation/the-swift-programming-language/functions/#Using-Function-Types> <https://docs.swift.org/swift-book/documentation/the-swift-programming-language/functions/#Using-Function-Types> var mathFunction: (Int, Int) -> Int = addTwoInts I’ve double checked examples and removed Swift and Rust. Thanks for that. ---------- Best regards, Dmitrii Derepko. @xepozz

Tim Düsterhus

1 year ago
Hi Am 2025-05-22 11:24, schrieb Dmitry Derepko:
> I hope this message finds you well. I would like to respectfully > propose > single-expression functions for PHP: > https://wiki.php.net/rfc/single-expression-functions
Thank you for updating the RFC to match the template. I've read through it and have some comments: 1. In the implementation I'm seeing that `$a = function() => 123;` will also become legal (“short closures with function instead of fn”). This is not mentioned in the RFC text. It also raises the question how that variant will interact with variable capturing. 2. An AST printing test in the implementation would be useful to have. You can do that with `assert(false && new class { });` (using an anonymous class). 3. I believe the reasoning given is not a fair comparison. The RFC says that `getName() "Name"` would be the relevant information, which I can agree with. But this is not what the proposed syntax looks like. A fair comparison would be: function getName() { return "Name"; } function getName() => "Name"; And when compared like this, it becomes clear that you are trading `{}` for `=>` and effectively only save the `return`, which to me provides little incremental value. Especially when comparing the signatures from the Calculator example: public function multiply(int $a, int $b): int => $a * $b; public function multiply(int $a, int $b): int { return $a * $b; } I also don't like how the actual implementation is pushed to the right of the line. This makes it harder for me to scan for it. The linebreaks that the RFC states “create cognitive overhead” guide the eye for me. So perhaps we should also compare: public function multiply(int $a, int $b): int => $a * $b; public function multiply(int $a, int $b): int { return $a * $b; } So basically the only thing we gain is the removal of a keyword in some situations. When trying to extend the logic in a function to more than one expression (which is not unlikely for methods), I would be forced to make multiple “boilerplate” changes instead of just adding my logic, effectively undoing any benefit the syntax might've provided. Thus I'm very skeptical that the RFC provides sufficient value to justify the impact on the ecosystem (e.g. IDEs, static analyzers, documentation, confusion regarding another closure syntax, …). Best regards Tim Düsterhus

Dmitry Derepko

1 year ago
Hi Tim, Great questions, I’ll try to answer them all. Sorry for the late answer, looked like there are no interest in the RFC and I almost forgot about it.
> On Jun 4, 2025, at 12:23 PM, Tim Düsterhus <tim@bastelstu.be> wrote: > > In the implementation I'm seeing that `$a = function() => 123;` will also become legal (“short closures with function instead of fn”). This is not mentioned in the RFC text. It also raises the question how that variant will interact with variable capturing.
Nope. Anonymous functions won’t become available. Use arrow functions with auto-capturing instead. RFC propose classic function and class methods become available be one-liners
> An AST printing test in the implementation would be useful to have. You can do that with `assert(false && new class { });` (using an anonymous class).
Sure, when RFC successfully pass Voting stage, alright?
> I believe the reasoning given is not a fair comparison. The RFC says that `getName() "Name"` would be the relevant information, which I can agree with. But this is not what the proposed syntax looks like. A fair comparison would be: > > function getName() { return "Name"; } > function getName() => "Name"; > > And when compared like this, it becomes clear that you are trading `{}` for `=>` and effectively only save the `return`, which to me provides little incremental value. Especially when comparing the signatures from the Calculator example: > > public function multiply(int $a, int $b): int => $a * $b; > public function multiply(int $a, int $b): int { return $a * $b; }
Cool point. I’ve updated examples.
> I also don't like how the actual implementation is pushed to the right of the line. This makes it harder for me to scan for it. The linebreaks that the RFC states “create cognitive overhead” guide the eye for me. So perhaps we should also compare: > > public function multiply(int $a, int $b): int > => $a * $b; > public function multiply(int $a, int $b): int { > return $a * $b; > }
I don’t think it’s correct comparison. Why the linebreak should be there? If it is set by an editor, it’s not programmer/language issue. Set your editor to: - Single expression function becomes regular when the line is greater than 180 chars AND/OR Vice-versa - Same above, but ignore instead of breaking the line - Other
> So basically the only thing we gain is the removal of a keyword in some situations. When trying to extend the logic in a function to more than one expression (which is not unlikely for methods), I would be forced to make multiple “boilerplate” changes instead of just adding my logic, effectively undoing any benefit the syntax might've provided.
Correct point, almost. Intellij IDEA provides quick action for Kotlin SEF’s, so you may turn SEF -> Regular and vice-versa calling CTRL+ENTER, Chose correct option, Enter. Usually, we read code tens times often then write. ---------- Best regards, Dmitrii Derepko. @xepozz