Straw poll: Places to allow function calls in constant expressions

  108630
February 17, 2020 02:08 tysonandre775@hotmail.com (tyson andre)
Hi internals,

I've created a straw poll at https://wiki.php.net/rfc/calls_in_constant_expressions_poll , to measure interest in allowing calls in different types of constant expressions.
If there aren't any problems with the poll structure or rules preventing creating a poll, I was going to add it to the rfc index page and move it to voting.

This poll was created to gather opinions on which of the below statement types would be desirable to change, and in which ways, before rewriting https://wiki.php.net/rfc/calls_in_constant_expressions .
It seems desirable to change some of these expression types (e.g. parameter defaults, static properties, static variable defaults) in different ways from others.
(e.g. forbidding static property declaration expression results from containing objects seems like a completely unnecessary limitation from trying to reuse the implementation, in retrospect).
This poll was created for feedback on whether changes to the following places had support, and what types of changes there were interest in.

  - Initial values of static or instance properties. This poll only addresses static properties.
  - Parameter defaults of functions, methods, and closures.
  - Class constant values.
  - Global constant values.
  - Static variable default values.

I'd asked earlier about creating a poll in https://externals.io/message/108430 , but didn't receive a response.

Thanks,
- Tyson
  108632
February 17, 2020 02:42 marandall@php.net (Mark Randall)
On 17/02/2020 02:08, tyson andre wrote:
> I've created a straw poll at https://wiki.php.net/rfc/calls_in_constant_expressions_poll , to measure interest in allowing calls in different types of constant expressions. I've yet to make my mind up for most circumstances, although I'm leaning
towards a general "No". What I can't express on this strawpoll though, is that I would unequivocally vote against "any function or method call" in all circumstances. -- Mark Randall marandall@php.net
  108683
February 19, 2020 17:58 tysonandre775@hotmail.com (tyson andre)
Hi internals,

> I've created a straw poll at https://wiki.php.net/rfc/calls_in_constant_expressions_poll , to measure interest in allowing calls in different types of constant expressions. > If there aren't any problems with the poll structure or rules preventing creating a poll, I was going to add it to the rfc index page and move it to voting.
This straw poll has been moved to voting and added to the rfc index page. The poll will be closed on March 4th. Thanks, - Tyson
  108686
February 19, 2020 19:00 bishop@php.net (Bishop Bettini)
On Wed, Feb 19, 2020 at 12:58 PM tyson andre <tysonandre775@hotmail.com>
wrote:

> Hi internals, > > > I've created a straw poll at > https://wiki.php.net/rfc/calls_in_constant_expressions_poll , to measure > interest in allowing calls in different types of constant expressions. > > If there aren't any problems with the poll structure or rules preventing > creating a poll, I was going to add it to the rfc index page and move it to > voting. > > This straw poll has been moved to voting and added to the rfc index page. > The poll will be closed on March 4th. >
The original motivation was, IIRC, to initialize class constants with an expression. Following KISS, I feel we should constrain our efforts to that scope, and that's how I voted: "Yes" on class constants and static members, "No" on everything else. As for implementation, we must manage the complexity. I'm a hard "No" on restricting use to an arbitrary, variable list of blessed functions. It's a dev UX nightmare to include a bevy of array_* functions but no str* functions. Consequently, the only way to safely initialize class constants and static members is at run-time, and I can only think of one way to do it. Apologies if this has already been suggested: taking a cue from C#, a static class constructor ([1]) would allow us to have expression-initialized constants and static members. url; self::$mtime = filemtime('config.json'); } public function reload() { if (self::$mtime < filemtime('config.json')) self::__constructStatic(); } } } echo Config::URL; // assert: runtime has already called _constructStatic $config = new Config; // assert: __constructStatic called only once by runtime $config->reload(); // instance may call its own static constructor ?> Trying to do the same for global constants, static variables, or function default parameters resists a similar initialization mechanism because we don't have defined common entry point analogues. If we had a main(), or if we had framed @before decorators, we could do something similar, but we don't -- so I feel we should leave these off the table. Thank you, Tyson, for taking the time to progress this feature. [1]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors
  108687
February 19, 2020 19:21 mike@newclarity.net (Mike Schinkel)
> On Feb 19, 2020, at 2:00 PM, Bishop Bettini <bishop@php.net> wrote: > > Consequently, the only way to safely initialize class constants and static > members is at run-time, and I can only think of one way to do it. Apologies > if this has already been suggested: taking a cue from C#, a static class > constructor ([1]) would allow us to have expression-initialized constants > and static members. > > class Config { > public const URL = null; // compile time initialization > protected static $mtime = null; // compile time initialization > private static function __constructStatic() { > $env = json_decode(file_get_contents('config.json')); > self::URL = $env->url; > self::$mtime = filemtime('config.json'); > } > public function reload() { > if (self::$mtime < filemtime('config.json')) > self::__constructStatic(); > } > } > } > > echo Config::URL; // assert: runtime has already called _constructStatic > $config = new Config; // assert: __constructStatic called only once by > runtime > $config->reload(); // instance may call its own static constructor > ?> > > Trying to do the same for global constants, static variables, or function > default parameters resists a similar initialization mechanism because we > don't have defined common entry point analogues. If we had a main(), or if > we had framed @before decorators, we could do something similar, but we > don't -- so I feel we should leave these off the table.
For different reasons than this RFC I have wanted a static class constructor for a really long time. I hope this is something we can seriously consider. Thanks Bishop for proposing it. -Mike
  108723
February 23, 2020 02:01 tysonandre775@hotmail.com (tyson andre)
> The original motivation was, IIRC, to initialize class constants with an expression. > Following KISS, I feel we should constrain our efforts to that scope, and that's how I voted: > "Yes" on class constants and static members, "No" on everything else.
I'd also personally found the `static $x = null; if ($x === null) { $x = some_fn(); }` pattern inconvenient and wanted that to be just `static $x = some_fn();` to make the initial value `some_fn()` if possible. It also seemed more readable (e.g. doesn't matter if some_fn() can be constant). My personal use case for parameter defaults and global constants isn't as strong (especially with define()), but it's still something I'd want. - I'd be able to use `private const FOO_DEFAULT = array_keys(...); function foo($x = FOO_DEFAULT) {}` if constants did pass, so that's less off a concern, and ensures&makes clear that the expression is only evaluated once, so it might be a better place to start with.
> As for implementation, we must manage the complexity. > I'm a hard "No" on restricting use to an arbitrary, variable list of blessed functions. > It's a dev UX nightmare to include a bevy of array_* functions but no str* functions.
If the RFC succeeded with a whitelist, I'd planned to create RFCs to add to the whitelist. Locale dependency of string functions was the reason for leaving it out initially, since that may also be a hard "no" for others.
> Consequently, the only way to safely initialize class constants and static members is at run-time, and I can only think of one way to do it. > Apologies if this has already been suggested: taking a cue from C#, a static class constructor ([1]) > would allow us to have expression-initialized constants and static members. > class Config { > public const URL = null; // compile time initialization > protected static $mtime = null; // compile time initialization > private static function __constructStatic() { > $env = json_decode(file_get_contents('config.json')); > self::URL = $env->url; > self::$mtime = filemtime('config.json'); > } > public function reload() { > if (self::$mtime < filemtime('config.json')) > self::__constructStatic(); > } > } > } > > echo Config::URL; // assert: runtime has already called _constructStatic > $config = new Config; // assert: __constructStatic called only once by runtime > $config->reload(); // instance may call its own static constructor ?>
This seems to allow the same functionality my RFC would allow, in a slightly different way. I didn't go with that syntax because it'd move the values of the constants/properties away from the declaration. Also, if `json_decode()` threw, then there would never be a way for a PHP implementation to initialize `self::$mtime` in that example, even though they're unrelated in how they're initialized there. Allowing calling `__constructStatic` multiple times (thus assigning to the **const** `self::URL` multiple times) would be a significant change to php internals, and out of the scope of this RFC https://wiki.php.net/rfc/calls_in_constant_expressions_poll ("Put the RFC(Poll) URL into all your replies.") - Tyson
  108829
March 3, 2020 15:14 nikita.ppv@gmail.com (Nikita Popov)
On Mon, Feb 17, 2020 at 3:09 AM tyson andre <tysonandre775@hotmail.com>
wrote:

> Hi internals, > > I've created a straw poll at > https://wiki.php.net/rfc/calls_in_constant_expressions_poll , to measure > interest in allowing calls in different types of constant expressions. > If there aren't any problems with the poll structure or rules preventing > creating a poll, I was going to add it to the rfc index page and move it to > voting. > > This poll was created to gather opinions on which of the below statement > types would be desirable to change, and in which ways, before rewriting > https://wiki.php.net/rfc/calls_in_constant_expressions . > It seems desirable to change some of these expression types (e.g. > parameter defaults, static properties, static variable defaults) in > different ways from others. > (e.g. forbidding static property declaration expression results from > containing objects seems like a completely unnecessary limitation from > trying to reuse the implementation, in retrospect). > This poll was created for feedback on whether changes to the following > places had support, and what types of changes there were interest in. > > - Initial values of static or instance properties. This poll only > addresses static properties. > - Parameter defaults of functions, methods, and closures. > - Class constant values. > - Global constant values. > - Static variable default values. > > I'd asked earlier about creating a poll in > https://externals.io/message/108430 , but didn't receive a response. > > Thanks, > - Tyson >
Hey Tyson, I feel like the results of this poll aren't going to be particularly meaningful, because it gets too caught up in the details and loses track of the big picture. If you ask people whether they want to allow function test($param = some_call()) { } they're going to to tell you "no", because that seems pretty esoteric and most people likely do not see a use-case for it. If you ask the same people whether they want to write function test(Dep $optionalDep = new Dep()) { } instead of function test(Dep $optionalDep = null) { if ($optionalDep === null) { $optionalDep = new Dep(); } } a lot of them are probably going to tell you "yes" now. The question didn't really change (new Dep is just a different type of "function call"), but the perception changes a lot. This is also why I think the focus on plain function calls in particular is somewhat detrimental. This is one of the cases where going for a paradigm shift (constant expression -> any expression) is "simpler" than doing an incremental change (extending constant expressions to allow function calls, and all the subtleties that entails.) Regards, Nikita
  108832
March 3, 2020 18:34 tysonandre775@hotmail.com (tyson andre)
> I feel like the results of this poll aren't going to be particularly > meaningful, because it gets too caught up in the details and loses track of > the big picture.
I'd definitely agree. If I was writing the RFC for calls in constant expressions again, I'd focus more on adding concrete examples of where function calls/other expressions would make code easier to understand, rather than focusing on implementation details. At the time of writing the RFC, I thought a major objection would be whether or not it was actually feasible to implement, and many people would be familiar with use cases where function calls in expressions would have made code more straightforward.
> If you ask people whether they want to allow > > function test($param = some_call()) { > } > > they're going to to tell you "no", because that seems pretty esoteric and > most people likely do not see a use-case for it. > > If you ask the same people whether they want to write > > function test(Dep $optionalDep = new Dep()) { > } > > instead of > > function test(Dep $optionalDep = null) { > if ($optionalDep === null) { > $optionalDep = new Dep(); > } > } > a lot of them are probably going to tell you "yes" now. The question didn't > really change (new Dep is just a different type of "function call"), but > the perception changes a lot.
Good example, I hadn't thought of mentioning `new` as an example for the "as many expression types as possible". That also lets functions clearly enforce arguments are non-null.
> This is also why I think the focus on plain function calls in particular is > somewhat detrimental. This is one of the cases where going for a paradigm > shift (constant expression -> any expression) is "simpler" than doing an > incremental change (extending constant expressions to allow function calls, > and all the subtleties that entails.)
The point of https://wiki.php.net/rfc/calls_in_constant_expressions_poll was to measure interest in "any expression", but did a poor job of mentioning arguments in favor of it or how it'd simplify common examples. With better arguments and examples, though, I'm still not certain if it'd be a 2/3 majority for any option. A straw poll or RFC arguing *only* in favor of a paradigm shift with better arguments and examples might see different results. - Tyson