RFC proposal : "new" keyword shorthand

php.internals

Benoît Condaminet

2 years ago
Hello, Following the RFC process, I'm sending this to propose a PHP change. More precisely a new zend language token. This is somehow linked to the recently accepted RFC called "new MyClass()->method() without parentheses", the goal is to introduce a shorthand for the "new" keyword. *Motivations :* The new keyword sometime has a bad DX, for example when chaining Class instantiation like this : $foobar = new Foo( new Bar(), new Etc()); We can quickly have very long class object construction in some case. In lot of Framework, to improve DX, static function construct are often used to avoid the new keyword, some create additional object builders, etc. As a first try, I start updated code to completely make the new keyword optional, like in Dart language for example, but it require very big change, with lot of impact (collision with function). So here is *my proposal : * Add a "new" shorthand, using the tilde character : "~" I made a POC, and it works well, declaring a new language token T_SHORT_NEW that simply reuse ZEND_AST_NEW under the hood. Here are some example of what it may look like for userland, through some tests I wrote : --TEST-- New keyword shorthand --FILE-- <?php class A { public function b() { echo "I'm B"; } } ~A()->b(); ?> --EXPECT-- I'm B Other with nested : --TEST-- New keyword shorthand encapsulation --FILE-- <?php class Foo { public function __construct( public string $name ) {} } class Bar { public function __construct( public Foo $foo ) {} } $bar = ~Bar(~Foo("I'm foo in bar")); echo $bar->foo->name; ?> --EXPECT-- I'm foo in bar As a last word, just wanted to add it will work on nested Attribute too, so for example this nested Attribute used in Doctrine : #[AttributeOverrides([ new AttributeOverride( name: "id", column: new Column(name: "guest_id", type: "integer", length: 140) ), new AttributeOverride( name: "name", column: new Column(name: "guest_name", nullable: false, unique: true, length: 240) )] )] Will also work like this : #[AttributeOverrides([ ~AttributeOverride( name: "id", column: new Column(name: "guest_id", type: "integer", length: 140) ), ~AttributeOverride( name: "name", column: new Column(name: "guest_name", nullable: false, unique: true, length: 240) )] )] About implementation, it should'n have any impact on SAPI or extension, the new keyword will still exist, it's just a new shorthand. I think you get the point, is it something that some of you would be interested in? I would be happy to make a proper RFC proposal. Just registered a wiki account : benconda Thank you,
-- Cordialement, Benoit Condaminet

John Bafford

2 years ago
Hi Benoît,
> On Jun 7, 2024, at 12:03, Benoît Condaminet <condaminet.benoit@gmail.com> wrote: > > As a first try, I start updated code to completely make the new keyword optional, like in Dart language for example, but it require very big change, with lot of impact (collision with function). > > So here is my proposal : > > Add a "new" shorthand, using the tilde character : "~" > I made a POC, and it works well, declaring a new language token T_SHORT_NEW that simply reuse ZEND_AST_NEW under the hood.
I would point out that ~ is an existing operator, bitwise not. Is there not the same ambiguity with that as with not having the new keyword at all? Because PHP has classes and functions in different namespaces ~SomeClass() looks exactly the same as ~SomeFunction(), and ~$someVar() would be just as ambiguous. I would prefer to see the new keyword go away as well, but as long as functions and classes are in separate namespaces, that might be difficult. -John

Rob Landers

2 years ago
On Fri, Jun 7, 2024, at 18:03, Benoît Condaminet wrote:
> Hello, > > Following the RFC process, I'm sending this to propose a PHP change. More precisely a new zend language token. > > This is somehow linked to the recently accepted RFC called "new MyClass()->method() without parentheses", the goal is to introduce a shorthand for the "new" keyword. > > *Motivations :* > The new keyword sometime has a bad DX, for example when chaining Class instantiation like this : > $foobar = new Foo( new Bar(), new Etc()); > > We can quickly have very long class object construction in some case. > > In lot of Framework, to improve DX, static function construct are often used to avoid the new keyword, some create additional object builders, etc. > > As a first try, I start updated code to completely make the new keyword optional, like in Dart language for example, but it require very big change, with lot of impact (collision with function). > > So here is *my proposal : * > > Add a "new" shorthand, using the tilde character : "~" > I made a POC, and it works well, declaring a new language token T_SHORT_NEW that simply reuse ZEND_AST_NEW under the hood. > > Here are some example of what it may look like for userland, through some tests I wrote : > --TEST-- > New keyword shorthand > --FILE-- > <?php > class A { > public function b() { > echo "I'm B"; > } > } > > ~A()->b(); > > ?> > --EXPECT-- > I'm B > Other with nested : > > --TEST-- > New keyword shorthand encapsulation > --FILE-- > <?php > class Foo { > public function __construct( > public string $name > ) {} > } > > class Bar { > public function __construct( > public Foo $foo > ) {} > } > > $bar = ~Bar(~Foo("I'm foo in bar")); > echo $bar->foo->name; > > ?> > --EXPECT-- > I'm foo in bar > As a last word, just wanted to add it will work on nested Attribute too, so for example this nested Attribute used in Doctrine : > > #[AttributeOverrides([ > new AttributeOverride( > name: "id", > column: new Column(name: "guest_id", type: "integer", length: 140) > ), > new AttributeOverride( > name: "name", > column: new Column(name: "guest_name", nullable: false, unique: true, length: 240) > )] > )] > > Will also work like this : > #[AttributeOverrides([ > ~AttributeOverride( > name: "id", > column: new Column(name: "guest_id", type: "integer", length: 140) > ), > ~AttributeOverride( > name: "name", > column: new Column(name: "guest_name", nullable: false, unique: true, length: 240) > )] > )] > > About implementation, it should'n have any impact on SAPI or extension, the new keyword will still exist, it's just a new shorthand. > > I think you get the point, is it something that some of you would be interested in? I would be happy to make a proper RFC proposal. > > Just registered a wiki account : benconda > > Thank you, > > -- > Cordialement, > Benoit Condaminet
Instead of ~ (which reminds me of the pendulum of symbols to written to symbols and back again every 10ish years; “or” vs “||”), why not make a shorthand way to write a function that calls a constructor (kinda sorta like C# extension methods)? Something kinda like: class MyClass implements Invocable { public function __construct($i) {} } MyClass($i); Where the Invocable interface defines a function of the same class name in the namespace that is an alias for a new objects and forwards args to the constructor. This could be quite handy for value objects. I’m not necessarily a fan of magic or symbols, but just tossing it out there to spark ideas. — Rob

Unnamed Person

2 years ago
On 6/7/24 10:35, Rob Landers wrote:
> > On Fri, Jun 7, 2024, at 18:03, Benoît Condaminet wrote: >> Hello, >> >> Following the RFC process, I'm sending this to propose a PHP change. >> More precisely a new zend language token. >> >> This is somehow linked to the recently accepted RFC called "new >> MyClass()->method() without parentheses", the goal is to introduce a >> shorthand for the "new" keyword. >> >> *Motivations :* >> The new keyword sometime has a bad DX, for example when chaining >> Class instantiation like this : >> $foobar = new Foo( new Bar(), new Etc()); >> >> We can quickly have very long class object construction in some case. >> >> In lot of Framework, to improve DX, static function construct are >> often used to avoid the new keyword, some create additional object >> builders, etc. >> >> As a first try, I start updated code to completely make the new >> keyword optional, like in Dart language for example, but it require >> very big change, with lot of impact (collision with function). >> >> So here is *my proposal : * >> >> Add a "new" shorthand, using the tilde character : "~" >> I made a POC, and it works well, declaring a new language >> token T_SHORT_NEW that simply reuse ZEND_AST_NEW under the hood. >> >> Here are some example of what it may look like for userland, through >> some tests I wrote : >> --TEST-- New keyword shorthand >> --FILE-- <?php class A { public function b() { echo "I'm B"; } } >> ~A()->b(); ?> >> --EXPECT-- I'm B >> Other with nested : >> >> --TEST-- New keyword shorthand encapsulation >> --FILE-- <?php class Foo { public function __construct( public string >> $name ) {} } class Bar { public function __construct( public Foo $foo >> ) {} } $bar = ~Bar(~Foo("I'm foo in bar")); echo $bar->foo->name; ?> >> --EXPECT-- I'm foo in bar >> As a last word, just wanted to add it will work on nested Attribute >> too, so for example this nested Attribute used in Doctrine : >> >> #[AttributeOverrides([ >>     new AttributeOverride( >>         name: "id", >>         column: new Column(name: "guest_id", type: "integer", length: >> 140) >>     ), >>     new AttributeOverride( >>         name: "name", >>         column: new Column(name: "guest_name", nullable: false, >> unique: true, length: 240) >>     )] >> )] >> >> Will also work like this : >> #[AttributeOverrides([ >>     ~AttributeOverride( >>         name: "id", >>         column: new Column(name: "guest_id", type: "integer", length: >> 140) >>     ), >>     ~AttributeOverride( >>         name: "name", >>         column: new Column(name: "guest_name", nullable: false, >> unique: true, length: 240) >>     )] >> )] >> >> About implementation, it should'n have any impact on SAPI or >> extension, the new keyword will still exist, it's just a new shorthand. >> >> I think you get the point, is it something that some of you would be >> interested in? I would be happy to make a proper RFC proposal. >> >> Just registered a wiki account : benconda >> >> Thank you, >> >> -- >> Cordialement, >> Benoit Condaminet > > Instead of ~ (which reminds me of the pendulum of symbols to written > to symbols and back again every 10ish years; “or” vs “||”), why not > make a shorthand way to write a function that calls a constructor > (kinda sorta like C# extension methods)? Something kinda like: > > class MyClass implements Invocable { >   public function __construct($i) {} > } > > MyClass($i); > > Where the Invocable interface defines a function of the same class > name in the namespace that is an alias for a new objects and forwards > args to the constructor. This could be quite handy for value objects. > > I’m not necessarily a fan of magic or symbols, but just tossing it out > there to spark ideas. > > — Rob
-- I'm not a fan of using ~ for this shorthand, due to the same issues that have been brought up elsewhere (i.e. it already has meaning). But the idea of a new interface auto-defining a function of the same name is attractive. It's something I've done manually to mirror code in PHP from other implementations existing in Scala leveraging case classes. https://docs.scala-lang.org/tour/case-classes.html for anyone unfamiliar with the construct: ``` case class Book(isbn: String) val frankenstein = Book("978-0486282114") ``` Doing something like this in PHP is a bit more ... verbose today: ``` class Book {     public function __construct(public string $isbn) {} } function Book(string $isbn): Book {     return new Book($isbn); } $frankenstein = Book("978-0486282114") ``` That's a lot of boilerplate for the shorthand to not require a `new` keyword. Which is to say, I both agree in principle with the RFC and think this would add value (particularly if I could extend the default behavior of this kind of interface to support immutability, comparison, etc similar to Scala case classes). I'm just not a fan of the current ~ proposal. ~Eric

Larry Garfield

2 years ago
On Fri, Jun 7, 2024, at 5:56 PM, ericmann@php.net wrote:
>> Instead of ~ (which reminds me of the pendulum of symbols to written to symbols and back again every 10ish years; “or” vs “||”), why not make a shorthand way to write a function that calls a constructor (kinda sorta like C# extension methods)? Something kinda like: >> >> class MyClass implements Invocable { >> public function __construct($i) {} >> } >> >> MyClass($i); >> >> Where the Invocable interface defines a function of the same class name in the namespace that is an alias for a new objects and forwards args to the constructor. This could be quite handy for value objects. >> >> I’m not necessarily a fan of magic or symbols, but just tossing it out there to spark ideas. >> >> — Rob > -- > > I'm not a fan of using ~ for this shorthand, due to the same issues > that have been brought up elsewhere (i.e. it already has meaning). But > the idea of a new interface auto-defining a function of the same name > is attractive. It's something I've done manually to mirror code in PHP > from other implementations existing in Scala leveraging case classes. > > https://docs.scala-lang.org/tour/case-classes.html for anyone > unfamiliar with the construct: > > ``` > case class Book(isbn: String) > > val frankenstein = Book("978-0486282114") > ``` > > Doing something like this in PHP is a bit more ... verbose today: > > ``` > class Book > { > public function __construct(public string $isbn) {} > } > > function Book(string $isbn): Book > { > return new Book($isbn); > } > > $frankenstein = Book("978-0486282114") > ``` > > That's a lot of boilerplate for the shorthand to not require a `new` > keyword. Which is to say, I both agree in principle with the RFC and > think this would add value (particularly if I could extend the default > behavior of this kind of interface to support immutability, comparison, > etc similar to Scala case classes). I'm just not a fan of the current ~ > proposal. > > ~Eric
The issue with auto-generating a function constructor for a class is that we still don't have function autoloading. Which means this: // Point.php #[MakeFactoryFunction] (or whatever) class Point { public function __construct(public int $x, public int $y) {} } // index.php $p = Point(4, 5); will look for a function named "Point", not find one defined yet, and fatal. If we had function autoloading, that would work, assuming a reasonable generic autoloader for that case could be written. Who was it that's been talking about that for a while? :-) Or if we had some marker to indicate "this function call is a wrapper for a class so autoload it like a class", that could then trigger the class autoloader. But... that's basically what the original ~ proposal is, in the end. Though I agree that ~ is not a great symbol for it. PHP has, sadly, run out of unused symbols. (I've run into this a couple of times now.) --Larry Garfield

Andreas Hennings

2 years ago
On Fri, 7 Jun 2024 at 20:31, Larry Garfield <larry@garfieldtech.com> wrote:
> > On Fri, Jun 7, 2024, at 5:56 PM, ericmann@php.net wrote: > > >> Instead of ~ (which reminds me of the pendulum of symbols to written to symbols and back again every 10ish years; “or” vs “||”), why not make a shorthand way to write a function that calls a constructor (kinda sorta like C# extension methods)? Something kinda like: > >> > >> class MyClass implements Invocable { > >> public function __construct($i) {} > >> } > >> > >> MyClass($i); > >> > >> Where the Invocable interface defines a function of the same class name in the namespace that is an alias for a new objects and forwards args to the constructor. This could be quite handy for value objects. > >> > >> I’m not necessarily a fan of magic or symbols, but just tossing it out there to spark ideas. > >> > >> — Rob > > -- > > > > I'm not a fan of using ~ for this shorthand, due to the same issues > > that have been brought up elsewhere (i.e. it already has meaning). But > > the idea of a new interface auto-defining a function of the same name > > is attractive. It's something I've done manually to mirror code in PHP > > from other implementations existing in Scala leveraging case classes. > > > > https://docs.scala-lang.org/tour/case-classes.html for anyone > > unfamiliar with the construct: > > > > ``` > > case class Book(isbn: String) > > > > val frankenstein = Book("978-0486282114") > > ``` > > > > Doing something like this in PHP is a bit more ... verbose today: > > > > ``` > > class Book > > { > > public function __construct(public string $isbn) {} > > } > > > > function Book(string $isbn): Book > > { > > return new Book($isbn); > > } > > > > $frankenstein = Book("978-0486282114") > > ``` > > > > That's a lot of boilerplate for the shorthand to not require a `new` > > keyword. Which is to say, I both agree in principle with the RFC and > > think this would add value (particularly if I could extend the default > > behavior of this kind of interface to support immutability, comparison, > > etc similar to Scala case classes). I'm just not a fan of the current ~ > > proposal. > > > > ~Eric > > The issue with auto-generating a function constructor for a class is that we still don't have function autoloading. Which means this: > > // Point.php > > #[MakeFactoryFunction] (or whatever) > class Point { > public function __construct(public int $x, public int $y) {} > } > > // index.php > > $p = Point(4, 5); > > will look for a function named "Point", not find one defined yet, and fatal. > > If we had function autoloading, that would work, assuming a reasonable generic autoloader for that case could be written. Who was it that's been talking about that for a while? :-) > > Or if we had some marker to indicate "this function call is a wrapper for a class so autoload it like a class", that could then trigger the class autoloader. But... that's basically what the original ~ proposal is, in the end. Though I agree that ~ is not a great symbol for it. PHP has, sadly, run out of unused symbols. (I've run into this a couple of times now.) > > --Larry Garfield
Hello Benoit. others already pointed out problems with the `$obj = ~C();` syntax, but also with the other option, `$obj = C();`. Personally I would prefer a suffix operator that would look similar to a static method call. This would make it a lot easier to switch between calling a static factory and "new." Unfortunately, `$obj = C::new();` is not an option, because "new" is a legal method name, so there could already be existing methods with that name. Also, `$obj = C::__construct();` would be just wrong. But if we can find anything in that direction, I would much prefer it over a prefix operator. E.g. `$obj = C::+();` is currently not valid syntax, so it would be a candidate, even though I don't really like it. -- Andreas

Rob Landers

2 years ago
On Fri, Jun 7, 2024, at 21:02, Andreas Hennings wrote:
> On Fri, 7 Jun 2024 at 20:31, Larry Garfield <larry@garfieldtech.com> wrote: > > > > On Fri, Jun 7, 2024, at 5:56 PM, ericmann@php.net wrote: > > > > >> Instead of ~ (which reminds me of the pendulum of symbols to written to symbols and back again every 10ish years; “or” vs “||”), why not make a shorthand way to write a function that calls a constructor (kinda sorta like C# extension methods)? Something kinda like: > > >> > > >> class MyClass implements Invocable { > > >> public function __construct($i) {} > > >> } > > >> > > >> MyClass($i); > > >> > > >> Where the Invocable interface defines a function of the same class name in the namespace that is an alias for a new objects and forwards args to the constructor. This could be quite handy for value objects. > > >> > > >> I’m not necessarily a fan of magic or symbols, but just tossing it out there to spark ideas. > > >> > > >> — Rob > > > -- > > > > > > I'm not a fan of using ~ for this shorthand, due to the same issues > > > that have been brought up elsewhere (i.e. it already has meaning). But > > > the idea of a new interface auto-defining a function of the same name > > > is attractive. It's something I've done manually to mirror code in PHP > > > from other implementations existing in Scala leveraging case classes. > > > > > > https://docs.scala-lang.org/tour/case-classes.html for anyone > > > unfamiliar with the construct: > > > > > > ``` > > > case class Book(isbn: String) > > > > > > val frankenstein = Book("978-0486282114") > > > ``` > > > > > > Doing something like this in PHP is a bit more ... verbose today: > > > > > > ``` > > > class Book > > > { > > > public function __construct(public string $isbn) {} > > > } > > > > > > function Book(string $isbn): Book > > > { > > > return new Book($isbn); > > > } > > > > > > $frankenstein = Book("978-0486282114") > > > ``` > > > > > > That's a lot of boilerplate for the shorthand to not require a `new` > > > keyword. Which is to say, I both agree in principle with the RFC and > > > think this would add value (particularly if I could extend the default > > > behavior of this kind of interface to support immutability, comparison, > > > etc similar to Scala case classes). I'm just not a fan of the current ~ > > > proposal. > > > > > > ~Eric > > > > The issue with auto-generating a function constructor for a class is that we still don't have function autoloading. Which means this: > > > > // Point.php > > > > #[MakeFactoryFunction] (or whatever) > > class Point { > > public function __construct(public int $x, public int $y) {} > > } > > > > // index.php > > > > $p = Point(4, 5); > > > > will look for a function named "Point", not find one defined yet, and fatal. > > > > If we had function autoloading, that would work, assuming a reasonable generic autoloader for that case could be written. Who was it that's been talking about that for a while? :-) > > > > Or if we had some marker to indicate "this function call is a wrapper for a class so autoload it like a class", that could then trigger the class autoloader. But... that's basically what the original ~ proposal is, in the end. Though I agree that ~ is not a great symbol for it. PHP has, sadly, run out of unused symbols. (I've run into this a couple of times now.) > > > > --Larry Garfield > > > > Hello Benoit. > others already pointed out problems with the `$obj = ~C();` syntax, > but also with the other option, `$obj = C();`. > > Personally I would prefer a suffix operator that would look similar to > a static method call. > This would make it a lot easier to switch between calling a static > factory and "new." > > Unfortunately, `$obj = C::new();` is not an option, because "new" is a > legal method name, so there could already be existing methods with > that name. > Also, `$obj = C::__construct();` would be just wrong. > > But if we can find anything in that direction, I would much prefer it > over a prefix operator. > E.g. `$obj = C::+();` is currently not valid syntax, so it would be a > candidate, even though I don't really like it. > > -- Andreas >
If we wanted a suffix, why not just use an empty ::? $frankenstein = Book::($isbn); — Rob

Andreas Hennings

2 years ago
On Fri, 7 Jun 2024 at 21:17, Rob Landers <rob@bottled.codes> wrote:
> > > > On Fri, Jun 7, 2024, at 21:02, Andreas Hennings wrote: > > On Fri, 7 Jun 2024 at 20:31, Larry Garfield <larry@garfieldtech.com> wrote: > > > > On Fri, Jun 7, 2024, at 5:56 PM, ericmann@php.net wrote: > > > > >> Instead of ~ (which reminds me of the pendulum of symbols to written to symbols and back again every 10ish years; “or” vs “||”), why not make a shorthand way to write a function that calls a constructor (kinda sorta like C# extension methods)? Something kinda like: > > >> > > >> class MyClass implements Invocable { > > >> public function __construct($i) {} > > >> } > > >> > > >> MyClass($i); > > >> > > >> Where the Invocable interface defines a function of the same class name in the namespace that is an alias for a new objects and forwards args to the constructor. This could be quite handy for value objects. > > >> > > >> I’m not necessarily a fan of magic or symbols, but just tossing it out there to spark ideas. > > >> > > >> — Rob > > > -- > > > > > > I'm not a fan of using ~ for this shorthand, due to the same issues > > > that have been brought up elsewhere (i.e. it already has meaning). But > > > the idea of a new interface auto-defining a function of the same name > > > is attractive. It's something I've done manually to mirror code in PHP > > > from other implementations existing in Scala leveraging case classes. > > > > > > https://docs.scala-lang.org/tour/case-classes.html for anyone > > > unfamiliar with the construct: > > > > > > ``` > > > case class Book(isbn: String) > > > > > > val frankenstein = Book("978-0486282114") > > > ``` > > > > > > Doing something like this in PHP is a bit more ... verbose today: > > > > > > ``` > > > class Book > > > { > > > public function __construct(public string $isbn) {} > > > } > > > > > > function Book(string $isbn): Book > > > { > > > return new Book($isbn); > > > } > > > > > > $frankenstein = Book("978-0486282114") > > > ``` > > > > > > That's a lot of boilerplate for the shorthand to not require a `new` > > > keyword. Which is to say, I both agree in principle with the RFC and > > > think this would add value (particularly if I could extend the default > > > behavior of this kind of interface to support immutability, comparison, > > > etc similar to Scala case classes). I'm just not a fan of the current ~ > > > proposal. > > > > > > ~Eric > > > > The issue with auto-generating a function constructor for a class is that we still don't have function autoloading. Which means this: > > > > // Point.php > > > > #[MakeFactoryFunction] (or whatever) > > class Point { > > public function __construct(public int $x, public int $y) {} > > } > > > > // index.php > > > > $p = Point(4, 5); > > > > will look for a function named "Point", not find one defined yet, and fatal. > > > > If we had function autoloading, that would work, assuming a reasonable generic autoloader for that case could be written. Who was it that's been talking about that for a while? :-) > > > > Or if we had some marker to indicate "this function call is a wrapper for a class so autoload it like a class", that could then trigger the class autoloader. But... that's basically what the original ~ proposal is, in the end. Though I agree that ~ is not a great symbol for it. PHP has, sadly, run out of unused symbols. (I've run into this a couple of times now.) > > > > --Larry Garfield > > > > Hello Benoit. > others already pointed out problems with the `$obj = ~C();` syntax, > but also with the other option, `$obj = C();`. > > Personally I would prefer a suffix operator that would look similar to > a static method call. > This would make it a lot easier to switch between calling a static > factory and "new." > > Unfortunately, `$obj = C::new();` is not an option, because "new" is a > legal method name, so there could already be existing methods with > that name. > Also, `$obj = C::__construct();` would be just wrong. > > But if we can find anything in that direction, I would much prefer it > over a prefix operator. > E.g. `$obj = C::+();` is currently not valid syntax, so it would be a > candidate, even though I don't really like it. > > -- Andreas > > > If we wanted a suffix, why not just use an empty ::? > > $frankenstein = Book::($isbn); > > — Rob
I am not strictly opposed to `$obj = C::()`. One problem I can imagine is `$obj = C::{$method}();`, where for some reason null or empty string '' is passed as $method. Currently, php will fail if this happens. But with the C::() syntax, it would then silently create a new instance. The same would happen if an unlucky find/replace removes the method name. Not sure if that's a blocker. -- Andreas

Benoît Condaminet

2 years ago
Le ven. 7 juin 2024, 21:31, Larry Garfield <larry@garfieldtech.com> a écrit :
> On Fri, Jun 7, 2024, at 5:56 PM, ericmann@php.net wrote: > > >> Instead of ~ (which reminds me of the pendulum of symbols to written to > symbols and back again every 10ish years; “or” vs “||”), why not make a > shorthand way to write a function that calls a constructor (kinda sorta > like C# extension methods)? Something kinda like: > >> > >> class MyClass implements Invocable { > >> public function __construct($i) {} > >> } > >> > >> MyClass($i); > >> > >> Where the Invocable interface defines a function of the same class name > in the namespace that is an alias for a new objects and forwards args to > the constructor. This could be quite handy for value objects. > >> > >> I’m not necessarily a fan of magic or symbols, but just tossing it out > there to spark ideas. > >> > >> — Rob > > -- > > > > I'm not a fan of using ~ for this shorthand, due to the same issues > > that have been brought up elsewhere (i.e. it already has meaning). But > > the idea of a new interface auto-defining a function of the same name > > is attractive. It's something I've done manually to mirror code in PHP > > from other implementations existing in Scala leveraging case classes. > > > > https://docs.scala-lang.org/tour/case-classes.html for anyone > > unfamiliar with the construct: > > > > ``` > > case class Book(isbn: String) > > > > val frankenstein = Book("978-0486282114") > > ``` > > > > Doing something like this in PHP is a bit more ... verbose today: > > > > ``` > > class Book > > { > > public function __construct(public string $isbn) {} > > } > > > > function Book(string $isbn): Book > > { > > return new Book($isbn); > > } > > > > $frankenstein = Book("978-0486282114") > > ``` > > > > That's a lot of boilerplate for the shorthand to not require a `new` > > keyword. Which is to say, I both agree in principle with the RFC and > > think this would add value (particularly if I could extend the default > > behavior of this kind of interface to support immutability, comparison, > > etc similar to Scala case classes). I'm just not a fan of the current ~ > > proposal. > > > > ~Eric > > The issue with auto-generating a function constructor for a class is that > we still don't have function autoloading. Which means this: > > // Point.php > > #[MakeFactoryFunction] (or whatever) > class Point { > public function __construct(public int $x, public int $y) {} > } > > // index.php > > $p = Point(4, 5); > > will look for a function named "Point", not find one defined yet, and > fatal. > > If we had function autoloading, that would work, assuming a reasonable > generic autoloader for that case could be written. Who was it that's been > talking about that for a while? :-) > > Or if we had some marker to indicate "this function call is a wrapper for > a class so autoload it like a class", that could then trigger the class > autoloader. But... that's basically what the original ~ proposal is, in > the end. Though I agree that ~ is not a great symbol for it. PHP has, > sadly, run out of unused symbols. (I've run into this a couple of times > now.) > > --Larry Garfield >
Thank you all for these answer, I miss the not bitwise operator... Sorry about that. Totally agree, look like we run out of unused symbol. And that it's maybe not the ideal solution to add a new one or combination of existing. Benoit.

Pierre

2 years ago
Le 07/06/2024 à 18:03, Benoît Condaminet a écrit :
> Hello, > > Following the RFC process, I'm sending this to propose a PHP change. > More precisely a new zend language token. > > This is somehow linked to the recently accepted RFC called "new > MyClass()->method() without parentheses", the goal is to introduce a > shorthand for the "new" keyword. > > *Motivations :* > The new keyword sometime has a bad DX, for example when chaining Class > instantiation like this : > $foobar = new Foo( new Bar(), new Etc()); > > We can quickly have very long class object construction in some case. > > In lot of Framework, to improve DX, static function construct are > often used to avoid the new keyword, some create additional object > builders, etc. > > As a first try, I start updated code to completely make the new > keyword optional, like in Dart language for example, but it require > very big change, with lot of impact (collision with function). > > So here is *my proposal : * > > Add a "new" shorthand, using the tilde character : "~" > I made a POC, and it works well, declaring a new language > token T_SHORT_NEW that simply reuse ZEND_AST_NEW under the hood. >
Hello, I sincerely do not want to see a new operator for replacing the "new" operator, because then we would have two different syntaxes which would be semantically equivalent. Creating a new object, in most API design, is not something you do very often, especially when working in a framework that does it for you (dependency injection, etc...). And, moreover, when I'm searching who what where was created an specific class instance, I regex grep for "new\s+ClassName" and in most case, it works like a charm. If you add an operator for this, it simply will create a huge cognitive dissonance for simply no added value at all. "New" is working fine, adding a shortcut for the sake of adding a shortcut to something you don't write that much doesn't worth it in my opinion: there are much more disadvantages that benefits. Best regards, Pierre

Larry Garfield

2 years ago
On Fri, Jun 7, 2024, at 7:20 PM, Pierre wrote:
> I sincerely do not want to see a new operator for replacing the "new" > operator, because then we would have two different syntaxes which would > be semantically equivalent. > > Creating a new object, in most API design, is not something you do very > often, especially when working in a framework that does it for you > (dependency injection, etc...).
This is not entirely true. Creating a new service object, yes, you rarely never do that yourself. Creating a new data object (value object, struct object, DTO, and a dozen other terms) is something that should happen more than most PHP developers currently do, because most of us have primitive obsession. (Or array obsession.) Consider attributes: Any time you want to have an object as the value for one of the arguments to an attribute, you need a "new." Any time you create a value object for a more strongly typed parameter than the horrid $options array, you'll be using "new." So I'm sympathetic to making that syntax easier, and would be OK with it if a workable syntax was found. But so far in this thread, a workable syntax has not been found. I agree it's not the greatest usability concern in PHP right now, though. --Larry Garfield

Pierre

2 years ago
Le 07/06/2024 à 21:38, Larry Garfield a écrit :
> On Fri, Jun 7, 2024, at 7:20 PM, Pierre wrote: > >> I sincerely do not want to see a new operator for replacing the "new" >> operator, because then we would have two different syntaxes which would >> be semantically equivalent. >> >> Creating a new object, in most API design, is not something you do very >> often, especially when working in a framework that does it for you >> (dependency injection, etc...). > This is not entirely true. Creating a new service object, yes, you rarely never do that yourself. Creating a new data object (value object, struct object, DTO, and a dozen other terms) is something that should happen more than most PHP developers currently do, because most of us have primitive obsession. (Or array obsession.) > > Consider attributes: Any time you want to have an object as the value for one of the arguments to an attribute, you need a "new." Any time you create a value object for a more strongly typed parameter than the horrid $options array, you'll be using "new." > > So I'm sympathetic to making that syntax easier, and would be OK with it if a workable syntax was found. But so far in this thread, a workable syntax has not been found. > > I agree it's not the greatest usability concern in PHP right now, though. > > --Larry Garfield
I understand your point, but why replacing "new" which is basically an operator, with another operator ? I do agree with you that when you use value objects, you need it a lot, but I'd much prefer having a JS like value objects initializer syntax, such as `Point {x: 1, y: 2}` syntax than creating another way to call the constructor, which already has a mastered and comprehensive syntax which is simply `new`. As you said, it's not the greatest usability concern in PHP right now. Pierre

Erick de Azevedo Lima

2 years ago
Hi all.
> Em sex., 7 de jun. de 2024 às 17:53, Pierre <pierre-php@processus.org>
escreveu:
> I do agree with you that when you use value objects, you need it a lot, > but I'd much prefer having a JS like value objects initializer syntax, > such as `Point {x: 1, y: 2}` syntax than creating another way to call > the constructor, which already has a mastered and comprehensive syntax > which is simply `new`.
I also think that `new `(4 chars, if we count the blank space) is short enough. But a JS-like syntax that's already known for representing objects could be used. I'm sympathetic to something like this (changing the OP examples): class A { public function b() { echo "I'm B"; } } A::{}->b(); class Foo { public function __construct( public string $name ) {} } class Bar { public function __construct( public Foo $foo ) {} } $bar = Bar::{ Foo::{ "I'm foo in bar" } }; echo $bar->foo->name; #[AttributeOverrides([ AttributeOverride::{ name: "id", column: Column::{ name: "guest_id", type: "integer", length: 140 } }, AttributeOverride::{ name: "name", column: Column::{ name: "guest_name", nullable: false, unique: true, length: 240 } }] )] #[AttributeOverrides([ AttributeOverride::{ name: "id", column: Column::{ name: "guest_id", type: "integer", length: 140 } }, AttributeOverride::{ name: "name", column: Column::{ name: "guest_name", nullable: false, unique: true, length: 240 } }] )]
-- Erick

Larry Garfield

2 years ago
On Fri, Jun 7, 2024, at 9:34 PM, Erick de Azevedo Lima wrote:
> Hi all. > >> Em sex., 7 de jun. de 2024 às 17:53, Pierre <pierre-php@processus.org> escreveu: >> I do agree with you that when you use value objects, you need it a lot, >> but I'd much prefer having a JS like value objects initializer syntax, >> such as `Point {x: 1, y: 2}` syntax than creating another way to call >> the constructor, which already has a mastered and comprehensive syntax >> which is simply `new`. > > I also think that `new `(4 chars, if we count the blank space) is short > enough. > But a JS-like syntax that's already known for representing objects > could be used. > I'm sympathetic to something like this (changing the OP examples): > > class A { > public function b() { > echo "I'm B"; > } > } > > A::{}->b(); > > > class Foo { > public function __construct( > public string $name > ) {} > } > > class Bar { > public function __construct( > public Foo $foo > ) {} > } > > $bar = Bar::{ Foo::{ "I'm foo in bar" } }; > echo $bar->foo->name; > > > #[AttributeOverrides([ > AttributeOverride::{ > name: "id", > column: Column::{ name: "guest_id", type: "integer", length: > 140 } > }, > AttributeOverride::{ > name: "name", > column: Column::{ name: "guest_name", nullable: false, unique: > true, length: 240 } > }] > )] > > > #[AttributeOverrides([ > AttributeOverride::{ > name: "id", > column: Column::{ name: "guest_id", type: "integer", length: > 140 } > }, > AttributeOverride::{ > name: "name", > column: Column::{ name: "guest_name", nullable: false, unique: > true, length: 240 } > }] > )] > > -- > Erick
We already have named arguments, which gives nearly the same syntax. Writing directly to properties like that makes no sense in a language that has class-private properties and internal constructors. It's fine in Rust or Go that don't have internal constructors, but it's just not a good fit in a PHP-like language. And new Foo(a: 'A", b: 'B") is already perfectly readable and self-documenting. Yet another constructor-invoke syntax on top of that would offer nothing. --Larry Garfield

Lynn

2 years ago
On Fri, Jun 7, 2024 at 11:50 PM Larry Garfield <larry@garfieldtech.com> wrote:
> On Fri, Jun 7, 2024, at 9:34 PM, Erick de Azevedo Lima wrote: > > Hi all. > > > >> Em sex., 7 de jun. de 2024 às 17:53, Pierre <pierre-php@processus.org> > escreveu: > >> I do agree with you that when you use value objects, you need it a lot, > >> but I'd much prefer having a JS like value objects initializer syntax, > >> such as `Point {x: 1, y: 2}` syntax than creating another way to call > >> the constructor, which already has a mastered and comprehensive syntax > >> which is simply `new`. > > > > I also think that `new `(4 chars, if we count the blank space) is short > > enough. > > But a JS-like syntax that's already known for representing objects > > could be used. > > I'm sympathetic to something like this (changing the OP examples): > > > > class A { > > public function b() { > > echo "I'm B"; > > } > > } > > > > A::{}->b(); > > > > > > class Foo { > > public function __construct( > > public string $name > > ) {} > > } > > > > class Bar { > > public function __construct( > > public Foo $foo > > ) {} > > } > > > > $bar = Bar::{ Foo::{ "I'm foo in bar" } }; > > echo $bar->foo->name; > > > > > > #[AttributeOverrides([ > > AttributeOverride::{ > > name: "id", > > column: Column::{ name: "guest_id", type: "integer", length: > > 140 } > > }, > > AttributeOverride::{ > > name: "name", > > column: Column::{ name: "guest_name", nullable: false, unique: > > true, length: 240 } > > }] > > )] > > > > > > #[AttributeOverrides([ > > AttributeOverride::{ > > name: "id", > > column: Column::{ name: "guest_id", type: "integer", length: > > 140 } > > }, > > AttributeOverride::{ > > name: "name", > > column: Column::{ name: "guest_name", nullable: false, unique: > > true, length: 240 } > > }] > > )] > > > > -- > > Erick > > We already have named arguments, which gives nearly the same syntax. > Writing directly to properties like that makes no sense in a language that > has class-private properties and internal constructors. It's fine in Rust > or Go that don't have internal constructors, but it's just not a good fit > in a PHP-like language. > > And new Foo(a: 'A", b: 'B") is already perfectly readable and > self-documenting. Yet another constructor-invoke syntax on top of that > would offer nothing. > > --Larry Garfield >
Currently there are 3 ways that I mostly see to create objects: - `new Reponse(...)`, through a public `__construct` - `Response::create(...)`, some static constructor that can be named anything - `response(...)`, where it's basically just a function making the object I personally don't really use functions for this, it's not for me. I do however often create static constructors and this means that I basically have 2 ways of creating objects. Sometimes I wish `Response::new()` would call the `__construct` variant, just so I could have all my constructors use the same syntax. I could make the default constructor private and force a second static function, but that feels like a lot of extra useless work.

Bilge

2 years ago
On 07/06/2024 22:34, Erick de Azevedo Lima wrote:
> I also think that `new `(4 chars, if we count the blank space) is > short enough.
Strongly agree. This solves a problem nobody has. Feel free to carry on regardless, though; curious to see where this ends up going. Bilge

John Coggeshall

2 years ago
> So here is my proposal : > > Add a "new" shorthand, using the tilde character : "~"
-10. Please, don't make PHP as unreadable as Perl. IMO It's two extra characters at worst and would be solved much more elegantly by removing the new keyword entirely. J

Erick de Azevedo Lima

2 years ago
> Please, don't make PHP as unreadable as Perl. IMO It's two extra
characters at worst and would be solved much more elegantly by removing the new keyword entirely. The new keyword is meaningful and everyone knows what's being done just by looking at it. Removing it would make the language less readable. But it's a BC so big that I don't think it can be done anyway.
-- Erick

John Coggeshall

2 years ago
On Jun 7 2024, at 8:49 pm, Erick de Azevedo Lima <ericklima.comp@gmail.com> wrote:
> The new keyword is meaningful and everyone knows what's being done just by looking at it. Removing it would make the language less readable. But it's a BC so big that I don't think it can be done anyway. > >
FWIW Languages like Dart are very readable without the extra new keyword (it supports instance creation with new or without it). I haven't put any thought into the engine changes that would be necessary to implement a similar syntax where new becomes optional, but I wouldn't be opposed to such a change if there was a PR out there for it. But I'm with you -- I think new is fine. I 100% don't want to see it replaced with some sort of confusing shorthand, but I might be able to be convinced to make the keyword optional. I also think in terms of value, cycles would be better spent on other things than to new or not to new . J