On Tue, Oct 27, 2020, at 1:35 AM, Mike Schinkel wrote:
> 
> 
> > On Oct 26, 2020, at 10:23 AM, Michał Marcin Brzuchalski 
> > <michal.brzuchal...@gmail.com> wrote:
> > 
> > Hi Larry,
> > 
> > I'm wondering why we hadn't thought yet about reducing the need for $this
> > in this syntax.
> > Since arrow functions have an ability to capture variables defined in
> > parent scope why not
> > think of the same for class properties which will automatically reduce
> > short methods verbosity.
> > 
> > class X {
> >    public function __construct(private int $foo, private int $bar) {}
> >    public function getFoo(): int => $foo;
> >    public function getBar(): int => $bar;
> > }
> > 
> > And then going further why not removing = from arrow which indicated that
> > there is no return value for void functions:
> > 
> > class X {
> >    public function __construct(private int $foo, private int $bar) {}
> >    public function getFoo(): int => $foo;
> >    public function setFoo(int $value): void > $foo = $value;
> >    public function getBar(): int => $bar;
> >    public function setBar(int $value): void > $bar = $value;
> > }
> > 
> > The use of > instead of => could if possible indicate the method being void
> > and reduce even more:
> > 
> > class X {
> >    public function __construct(private int $foo, private int $bar) {}
> >    public function getFoo(): int => $foo;
> >    public function setFoo(int $value) > $foo = $value;
> >    public function getBar(): int => $bar;
> >    public function setBar(int $value) > $bar = $value;
> > }
> > 
> > Would it be possible?
> > 
> > If not I think we should reanimate property accessors.
> 
> Which brings us back to https://externals.io/message/64469 
> <https://externals.io/message/64469> from 7 years ago.  And there is 
> this: 
> https://www.reddit.com/r/PHP/comments/budr7q/php_74_setters_and_getters_have_died/
>  
> <https://www.reddit.com/r/PHP/comments/budr7q/php_74_setters_and_getters_have_died/>
> 
> With getters/setters, it would seem Larry's proposal might allow for 
> more conciseness than it can with all other current syntax being the 
> same as PHP 8.0 per Nikita. 
> 
> Consider this, as one straw man type of new syntax:
> 
> class TimePeriod {
>       private int $Seconds = 3600;
>       public float $Hours {
>               get():float => $this->Seconds / 3600;
>               set(int $v) => $this->Seconds = intval($v*3600);
>       }
> }
> 
> Or for a different use-case with different straw man syntax that could 
> possibly work in addition to above syntax, where externally $Balance is 
> readonly whereas internally Balance is treated like it is private so it 
> can be set (I also used Michal's ">" to indicate void, although I am 
> not sure that using a greater-than in a different context is a good 
> idea):
> 
> class Account {
>       public get int $Balance;
>       public function Deposit(int $amount) > $this->Balance += $amount;
>       public function Withdraw(int $amount) > $this->Balance -= $amount;
> }

Responding to several things at once here:

Honestly, getters is not my primary target with this RFC.  They're more a nice 
side effect, given how common they are.  I am more interested in "expression 
functions": functions that are just a pure input->output map.  Sometimes those 
are methods, but frequently they're just functions.

A shortened setter is not really what I'm after, therefore.  If anything, I'd 
prefer to make an expression that returns a new object with one change that can 
then be returned by this syntax, making with-er methods easier.  That would fit 
better with value objects.  

And, in fact, named parameters already gives us something very very close in 
8.0:

class Point {
    public function __construct(private int $x, private int $y) {}

    protected function modClone(...$args): static {
        $new = clone($this);
        foreach ($args as $k => $v) {
            $new->$k = $v;
        }
        return $new;
    }
    
    public function moveUp(int $amt) { 
        return $this->modClone(y: $this->y + $amt);
    } 
}

$p1 = new Point(3, 5);

$p2 = $p1->moveUp(4);

https://3v4l.org/lg4Ac

That allows for a single-expression with-er method with no additional syntax, 
just one simple utility method.  Which, with this RFC, could be shortened to:

class Point {
    public function __construct(private int $x, private int $y) {}

    protected function modClone(...$args): static {
        $new = clone($this);
        foreach ($args as $k => $v) {
            $new->$k = $v;
        }
        return $new;
    }
    
    public function x(): => $this->x;
    public function y(): => $this->y;

    public function distFromOrigin() => sqrt($this->x ** 2 + $this->y ** 2);

    public function moveUp(int $amt): static => $this->modClone(y: $this->y + 
$amt);
}

Which... I actually really like, now that I look at it.  I'd rather look at how 
to make modClone() more trivial or even included natively than a dedicated 
setter syntax.  But that's for another RFC.

That's also why I don't really want to consider auto-scoping to $this.  That's 
unnecessary magic that would, if anything, make converting between a short and 
long function harder.  At this point I can type $this-> from pure muscle memory 
in a fraction of a second so I'm not too bothered by it. :-)

To Nikita's point about visual confusion in a class, that's fair.  However, as 
noted I think it's more useful for functions anyway.  Also, the problem goes 
away if you cluster your code effectively, which is already a good (albeit not 
universal) practice, and if you can use a with-er style method as above.

viz:

class User {
  public function __construct(
    private int $id, 
    private string $username, 
    private string $role, 
    private string $firstName, 
    private string $lastName,
  ) {}

  public function getId(): int => $this->id;
  public function getUserName(): string => $this->username;
  public function getRole(): string => $this->role;
  public function getFullName(): string => sprintf(%s %s', $this->firstName, 
$this->lastName);

  public function setUserName(string $name): static => 
$this->modClone(username: $name);
  public function setRole(string $role): static => $this->modClone(role: $role);

  public function rehashPassword(): void {
    // ... Stuff here.
  }
}

That looks quite readable to me, and even encourages putting all the simple 
getters together, both those that are raw getters and the "pseudo-property" 
ones like getFullName().  Looking at it, I quite like it both visually and for 
what it encourages.

--Larry Garfield

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to