Skip to content

Cutting off an empty body of a function #8420

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
3 of 6 tasks
roxblnfk opened this issue Apr 21, 2022 · 8 comments
Closed
3 of 6 tasks

Cutting off an empty body of a function #8420

roxblnfk opened this issue Apr 21, 2022 · 8 comments

Comments

@roxblnfk
Copy link

roxblnfk commented Apr 21, 2022

Roadmap

RFC Draft:

Introduction

Since PHP 8.0 we have the Constructor Property Promotion feature.

Often, using this feature, we get a constructor with an empty body:

class Point {
    public function __construct(
        public float $x = 0.0,
        public float $y = 0.0,
        public float $z = 0.0,
    ) {
    }
}

Sometimes we need to make constructor private. Just try to find this fragment in the vendor dir of any your project.

final class Foo {
    private function __construct()
    {
    }
}

Sometimes we also need to describe empty methods because an interface or an abstract class requires it.

namespace Monolog\Handler;

interface HandlerInterface
{
    // ...
    public function close(): void;
}

abstract class Handler implements HandlerInterface
{
    // ...
    public function close(): void
    {
    }
}

All these extra brackets could be replaced by semicolons, just as we can do now in loops:

foreach ($generator as $_);
while (Loop::handle());
for (;$g(););

// instead of

foreach ($generator as $_) {
    // do nothing
}
while (Loop::handle()) {
    // do nothing
}
for (;$g();) {
    // do nothing
}

A similar topic has been raised before [2]. The opinions of the participants differed, but the RFC was never created. At least, I didn't find it.

In that discussion Nikita Popov mentioned that quite a few people suggested adding this functionality.

I can reinforce these words: many developers in my environment, including myself, expected a similar syntax already in PHP 8.0, 8.1 and then in PHP 8.2.

Some people may think that the change should be in the coding standard, but not in the language. However, I believe it would be a positive change in terms of development experience (DX). You can move the braces to one line, but the ugliness will not go anywhere.

final class Dto {
    public function __construct(
        public int $x,
        public int $y,
        public int $z,
    ) {}
}

Among other things, there is an opinion that there is a difference between a marked empty method body and a semicolon: in the first case, the developer explicitly declares that the method does nothing, while in the second, the implementation is not yet defined. This is specific to some other languages, but our language already has the abstract keyword for it. Feel free to correct me if I'm wrong.

Proposal

Add the ability to replace an empty function body with a semicolon:

class Point {
    public function __construct(
        public float $x = 0.0,
        public float $y = 0.0,
        public float $z = 0.0,
    );
}

Not only for constructors, but also for regular class methods that have the void return type:

class Foo {
    public function foo(): void;
    public static function bar(int $baz): void;
}

(new Foo())->foo();
Foo::bar(42);

All other cases when the return type is defined and it differs from the void are not covered by this RFC. They are invalid.

class Foo() {
    // Ambiguous values
    public function a(): int;
    public function b(): string;
    public function c(): Foo&Bar;
    public function d(): iterable;
    public function e(): array;
    public function f(): self;
    public function g(): static;
    public function h(): ?Foo;
    public function h(): mixed;
    // ...
    // And unambiguous
    public function x(): null;
    public function y(): false;
    public function z(): true;
}

Backward incompatible changes

This RFC doesn't contain any backwards incompatible changes.

Proposed PHP version

PHP 8.3

RFC impact

The error text "Non-abstract method %s::%s() must contain body" might be changed.

The effect on the opcache I have not investigated.

Open issues

Body-less methods without return type

Should we allow trimming the empty body of methods that have no returning type? On the one hand, we want more consistency, because the constructor doesn't have a return type either. On the other hand, we want more strictness.

class Foo {
    public function bar();
}

Body-less methods in abstract classes

There is a concern that if the developer put a semicolon, he forgot to specify the method as abstract. I'm not sure if this is a language problem, but there is a solution: disallow body-less methods in abstract classes. If necessary, this constraint can be removed in a next minor version of PHP.

abstract class Foo {
    public function bar(): mixed; // Exception will be thrown
}

The constraint is questionable because it violates the consistency between abstract and non-abstract classes.

Future scope

Body-less classes

This would be a good precedent for an RFC about body-less classes.

class DefaultMyLibraryException extends \RuntimeException implements MyLibraryException;

// instead of

class DefaultMyLibraryException extends \RuntimeException implements MyLibraryException
{
}

Body-less methods with returning types

Given that the return values of functions can be uniquely defined through their types (null, false [3], true [4]) we can talk about the possibility of such syntactic sugar:

interface User {
    function isAdmin(): bool;
    function getFoo(): ?Foo;
}

class Admin implemets User
{
    function isAdmin(): true
    {
        return true;
    }
    function getFoo(): null
    {
        return null;
    }
}

// can be replaced with

class Admin extends User
{
    function isAdmin(): true;
    function getFoo(): null;
}

This is not the same as short functions from declined [5], because no expressions are used, types only.

Patches and Tests

I made the patch (and tests) [6] that adds ability to describe body-less methods in abstract and non-abstract classes that are:

  • constructor
  • methods with the void return type
  • methods without return type

I will make adjustments after the open issues are resolved.

References

  1. PHP RFC: Constructor Property Promotion
  2. External discussion: Body-less __construct
  3. PHP RFC: Allow null and false as stand-alone types
  4. PHP RFC: Add true type
  5. PHP RFC: Short Functions
  6. Branch with patch (will be replaced with PR)
@iluuu1994
Copy link
Member

This was discussed before here and implemented here. There wasn't consensus in the discussion and thus this would require an RFC.

@iluuu1994
Copy link
Member

An RFC similar to your future scope was voted on not too long ago and declined.
https://wiki.php.net/rfc/short-functions

@roxblnfk
Copy link
Author

@iluuu1994 I tried to send an email about RFC draft to [email protected] according to these instructions.
However, I found this mailing list archived.
Could you tell me please how I can send a draft and get feedback and RFC karma?

@iluuu1994
Copy link
Member

@roxblnfk You need to be properly subscribed to the mailing list before you can send any e-mails to it: https://www.php.net/mailing-lists.php You also need to use the mailing list to request RFC karma, so this will be a prerequisite.

@github-actions
Copy link

github-actions bot commented Nov 5, 2022

There has not been any recent activity in this feature request. It will automatically be closed in 14 days if no further action is taken. Please see https://github.com/probot/stale#is-closing-stale-issues-really-a-good-idea to understand why we auto-close stale feature requests.

@github-actions github-actions bot added the Stale label Nov 5, 2022
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Nov 20, 2022
@faizanakram99
Copy link

@roxblnfk I see that you never sent this to the mailing list, there has been a recent interest in such a feature https://externals.io/message/124466#124466

@roxblnfk
Copy link
Author

roxblnfk commented Jul 28, 2024

@roxblnfk I see that you never sent this to the mailing list, there has been a recent interest in such a feature externals.io/message/124466#124466

Hi. Thanks for letting me know.

Regarding "you never sent this to the mailing list": I was sure I did (https://externals.io/message/117771), but I didn't receive enough feedback or interest to continue working on it.

I think I can allocate time to work on the RFC if there is interest from the community.


At one point, @pronskiy suggested that I split this draft into two parts: first, implement only the constructor without the body, and then propose this for regular methods as well. He might be right, and this is the way.


Reading the thread, I see that @Crell expresses the opposite opinion that if such changes are to be made to the language, they should be done together with other common-pattern optimizations. This could correlate with the "Future scope / Body-less methods with returning types" section of the draft. 🤔

@Crell
Copy link
Contributor

Crell commented Jul 28, 2024

Of note for the proposal text, the

{
}

construct is not mandated by PHP. It was an implicit expectation of older coding standards (PSR-2, PSR-12), and has since been changed in PER-CS 2.0 to recommend using {} instead. So any comparison examples should use that inline style instead, to be a fair and accurate comparison.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants