kphp icon indicating copy to clipboard operation
kphp copied to clipboard

Immutable classes with pure constructor and same constant args as single object

Open mkornaukhov opened this issue 2 years ago • 6 comments

In case of

$a = new A(CONST_ONE, CONST_TWO);
$b = new A(CONST_ONE, CONST_TWO);

we want

  1. Constructor of class A with parameters CONST_ONE, CONST_TWO to be called once and transpiled as global variable that is initialized only once
  2. Each invocation of new A(CONST_ONE, CONST_TWO) to be replaced with such a variable

It would allow use some constructions such as

const c = new A(CONST_ONE, CONST_TWO);

with the following restrictions on class A:

  • Marked as @kphp-immutable-class
  • Has constructor that marked as @kphp-pure-function
  • CONST_ONE, CONST_TWO are constant expressions

It would possibly improve performance and definitely help to implement enums in a natural way.

mkornaukhov avatar Feb 21 '23 14:02 mkornaukhov

I strongly disagree about this change. Two independent calls of the constructor MUST return two independent instances, but suggested feature just breaks this rule and affects runtime.

In fact, this issue introduces some kind of compile-time singleton, but in a very implicit way (counterintuitive, in fact). Two identical objects, even immutable ones, are still not the same object in general case, so singletonization must be done in user code explicitly.

So this in not an optimization, but a breaking change.

vkaverin avatar Feb 26 '23 18:02 vkaverin

I strongly disagree about this change. Two independent calls of the constructor MUST return two independent instances, but suggested feature just breaks this rule and affects runtime.

In fact, this issue introduces some kind of compile-time singleton, but in a very implicit way (counterintuitive, in fact). Two identical objects, even immutable ones, are still not the same object in general case, so singletonization must be done in user code explicitly.

So this in not an optimization, but a breaking change.

Thank you for the comment. Naturally, it's internal compiler change and it should not affect on current code bases because all constructors are not @kphp-pure-function-ed. According to the idea, it doesn't matter for kphp-user how such classes are transpiled.

Could you give an example of breaking cases, please?

mkornaukhov avatar Feb 26 '23 18:02 mkornaukhov

Could you give an example of breaking cases, please?

I missed the fact that @kphp-pure-function is currently supported only for built-in functions, so you're right, current behaviour won't change. Is the issue about implementing the annotation for constructors (and other user-code functions) as well?


By the way, such behaviour can't be achieved in pure PHP, so there will be inconsistency between PHP and KPHP.

vkaverin avatar Feb 26 '23 18:02 vkaverin

Is the issue about implementing the annotation for constructors (and other user-code functions) as well?

Not really. Actually, this annotation is implemented, but behavior is not guaranteed. There's going to be another issue about dealing with @kphp-pure-function.

For now, the most motivated example is enum implementation.

mkornaukhov avatar Feb 27 '23 07:02 mkornaukhov

Do you mean it's gonna be kind of workaround while there's no real enum, like for PHP <= 8.1? Or this blocks #730 in some way?

vkaverin avatar Mar 01 '23 10:03 vkaverin

Do you mean it's gonna be kind of workaround while there's no real enum, like for PHP <= 8.1? Or this blocks #730 in some way?

We decided to change a little bit initial idea. For now, we implemented a part of https://www.php.net/releases/8.1/en.php#new_in_initializers, namely it's possible to use objects in constant definition. See https://github.com/VKCOM/kphp/pull/814. Besides, we decided to (later) introduce new phpdoc for classes that forces to store every instance of this class which are constructed with same constant parameters in the same constant object.

mkornaukhov avatar May 12 '23 13:05 mkornaukhov