Morning internals,
Since we have our answer on nullable types, typed properties can now go
to vote.
https://wiki.php.net/rfc/typed-properties#vote
Note that, support for nullability as RFC'd will be merged when the
implementation for nullable_types is merged into master.
Please participate.
Cheers
Joe
Morning internals,
Since we have our answer on nullable types, typed properties can now go
to vote.
https://wiki.php.net/rfc/typed-properties#vote Note that, support for nullability as RFC'd will be merged when the
implementation for nullable_types is merged into master.
Please participate.
Cheers
Joe
I don't get a vote, but I will say "endorse!"
--Larry Garfield
Morning internals,
Since we have our answer on nullable types, typed properties can now go
to vote.
https://wiki.php.net/rfc/typed-properties#vote Note that, support for nullability as RFC'd will be merged when the
implementation for nullable_types is merged into master.
I have just realised exactly why I have a problem with most of this ...
Domain! Used as an 'OtherThing'
This is ALSO attributes, since an SQL domain defines all of the
attributes that I need to handle in relation to variables. 'int' on it's
own does very little since one still needs to add all the other checks,
but adding 'types' as a properly formatted domain solves all the
problems I'm looking at ... and leaves plenty of room for others to
abuse the in their own way?
Note such elements as [<array_dim>] to allow for arrays of a datatype
although that still leaves the handling of mix arrays.
Some of the conditions may seem irreverent, but if the domain is a set
of keys for an array that logic then makes sense?
I can even see the addition of a 'read only' flag to solve that problem
while still constraining the initial setting of a domain.
But this is simply user land code and does not need a small subset of
elements of it added to the code base?
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
Joe, I fixed a minor typo in the RFC, hope you didn't mind. =)
Morning internals,
Since we have our answer on nullable types, typed properties can now
go
to vote.
https://wiki.php.net/rfc/typed-properties#vote Note that, support for nullability as RFC'd will be merged when the
implementation for nullable_types is merged into master.
I have just realised exactly why I have a problem with most of this ...
Domain! Used as an 'OtherThing'This is ALSO attributes, since an SQL domain defines all of the
attributes that I need to handle in relation to variables. 'int' on it's
own does very little since one still needs to add all the other checks,
but adding 'types' as a properly formatted domain solves all the
problems I'm looking at ... and leaves plenty of room for others to
abuse the in their own way?Note such elements as [<array_dim>] to allow for arrays of a datatype
although that still leaves the handling of mix arrays.Some of the conditions may seem irreverent, but if the domain is a set
of keys for an array that logic then makes sense?I can even see the addition of a 'read only' flag to solve that problem
while still constraining the initial setting of a domain.But this is simply user land code and does not need a small subset of
elements of it added to the code base?--
Lester Caine - G8HFLContact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk--
--
Guilherme Blanco
Lead Architect at E-Block
Morning internals,
Since we have our answer on nullable types, typed properties can now go
to vote.
https://wiki.php.net/rfc/typed-properties#vote Note that, support for nullability as RFC'd will be merged when the
implementation for nullable_types is merged into master.
Please participate.
I lack suffrage but I have a question about coercion and strictness.
When I assign a value to a property declared with scalar type, is it the
strictness of the file containing the assignment that controls if
coercion happens or not? And is the strictness of the file containing
the declaration irrelevant?
I guess yes on both to be consistent with coercion on function
invocation but I couldn't find this mentioned in the RFC.
Tom
> I guess yes on both to be consistent with coercion on function invocation
but I couldn't find this mentioned in the RFC.
Correct. I only made brief mention that the rules for coercion and
strictness are reused.
Cheers
Joe
>
>
>> Morning internals,
>>
>> Since we have our answer on nullable types, typed properties can now
>> go
>> to vote.
>>
>> https://wiki.php.net/rfc/typed-properties#vote
>>
>> Note that, support for nullability as RFC'd will be merged when the
>> implementation for nullable_types is merged into master.
>>
>> Please participate.
>>
>
> I lack suffrage but I have a question about coercion and strictness.
>
> When I assign a value to a property declared with scalar type, is it the
> strictness of the file containing the assignment that controls if coercion
> happens or not? And is the strictness of the file containing the
> declaration irrelevant?
>
> I guess yes on both to be consistent with coercion on function invocation
> but I couldn't find this mentioned in the RFC.
>
> Tom
The patch "corrupts" opcache shared memory.
PHP crashes with opcache.protect_memory=1.
$ USE_ZEND_ALLOC=0 valgrind sapi/cli/php -d opcache.protect_memory=1 ../Zend/tests/type_declarations/typed_properties_027.php
==900== Memcheck, a memory error detector
==900== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==900== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==900== Command: sapi/cli/php ../Zend/tests/type_declarations/typed_properties_027.php
==900==
==900==
==900== Process terminating with default action of signal 11 (SIGSEGV)
==900== Bad permissions for mapped region at address 0xF00FFBC8
==900== at 0x86391FE: zend_verify_weak_scalar_type_hint (zend_execute.c:725)
==900== by 0x8639833: zend_verify_scalar_property_type (zend_execute.c:869)
==900== by 0x8639C2B: zend_verify_property_type (zend_execute.c:938)
==900== by 0x862E46D: zend_std_write_property (zend_object_handlers.c:753)
==900== by 0x8685102: ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DATA_CONST_HANDLER (zend_vm_execute.h:42160)
==900== by 0x863F91D: execute_ex (zend_vm_execute.h:426)
==900== by 0x863F9D2: zend_execute (zend_vm_execute.h:471)
==900== by 0x85F38B4: zend_execute_scripts (zend.c:1427)
==900== by 0x85832B7: php_execute_script (main.c:2492)
==900== by 0x86AE2D8: do_cli (php_cli.c:982)
==900== by 0x86AEF42: main (php_cli.c:1352)
==900==
Hi Joe,
The performance effect of this implementation is terrible.
Assignment to typed property is 2.3 times slower.
Assignment to untyped property in a class with typed properties is 1.8 times slower.
See the benchmark
https://gist.github.com/dstogov/1b678712adeee51665cdd829195bb800
Thanks. Dmitry.
From: Joe Watkins pthreads@pthreads.org
Sent: Friday, May 20, 2016 9:05:34 AM
To: PHP internals; Phil Sturgeon
Subject: [PHP-DEV] [RFC][Vote] Typed Properties
Morning internals,
Since we have our answer on nullable types, typed properties can now go
to vote.
https://wiki.php.net/rfc/typed-properties#vote
Note that, support for nullability as RFC'd will be merged when the
implementation for nullable_types is merged into master.
Please participate.
Cheers
Joe
Hi!
The performance effect of this implementation is terrible.
Assignment to typed property is 2.3 times slower.
Assignment to untyped property in a class with typed properties is 1.8 times slower.See the benchmark
https://gist.github.com/dstogov/1b678712adeee51665cdd829195bb800
This is not good. I wonder why these tests weren't made before the vote
and results wheren't added in the RFC. Should we make it a standard
practice to do so? Having 2x slowdown on each property access sounds
like a bad idea.
Stas Malyshev
smalyshev@gmail.com
On Mon, May 23, 2016 at 11:09 AM, Stanislav Malyshev
smalyshev@gmail.com wrote:
Hi!
The performance effect of this implementation is terrible.
Assignment to typed property is 2.3 times slower.
Assignment to untyped property in a class with typed properties is 1.8 times slower.See the benchmark
https://gist.github.com/dstogov/1b678712adeee51665cdd829195bb800This is not good. I wonder why these tests weren't made before the vote
and results wheren't added in the RFC. Should we make it a standard
practice to do so? Having 2x slowdown on each property access sounds
like a bad idea.
The question is :
- should the vote be an idea-based vote, or integrate the code into the vote ?
My vote did not integrate the code, but the feature.
The idea is that if the RFC passes, then the feature is agreed, and we
still have some time to find a better implementation.
If we could not find one, then the feature should be abandoned or
post-poned until a new patch. If the new patch changes the
implementation, then the RFC should be reopened.
My thoughts.
Julien.Pauli
Morning internals,
I have improved the performance of the patch a little, here's the
results of a bad run:
krakjoe@fiji:/usr/src/php-src$ sapi/cli/php -n prop.php
empty_loop 0.064
write_prop1() 0.088 0.025
write_prop2() 0.079 0.016
write_prop3() 0.082 0.018
------------------------
Total 0.314
There is going to be overhead, not the kind we can't minimize, or
justify though.
Dmitry has said he'll review, and I'm hoping at least Laruence, Nikita,
and Bob will do the same ...
We have many weeks to improve the implementation, I'm not going to
merge anything that's obviously bad :)
Cheers
Joe
On Mon, May 23, 2016 at 11:09 AM, Stanislav Malyshev
smalyshev@gmail.com wrote:Hi!
The performance effect of this implementation is terrible.
Assignment to typed property is 2.3 times slower.
Assignment to untyped property in a class with typed properties is 1.8
times slower.See the benchmark
https://gist.github.com/dstogov/1b678712adeee51665cdd829195bb800This is not good. I wonder why these tests weren't made before the vote
and results wheren't added in the RFC. Should we make it a standard
practice to do so? Having 2x slowdown on each property access sounds
like a bad idea.The question is :
- should the vote be an idea-based vote, or integrate the code into the
vote ?My vote did not integrate the code, but the feature.
The idea is that if the RFC passes, then the feature is agreed, and we
still have some time to find a better implementation.
If we could not find one, then the feature should be abandoned or
post-poned until a new patch. If the new patch changes the
implementation, then the RFC should be reopened.My thoughts.
Julien.Pauli
Hi!
The performance effect of this implementation is terrible.
Assignment to typed property is 2.3 times slower.
Assignment to untyped property in a class with typed properties is 1.8
times slower.See the benchmark
https://gist.github.com/dstogov/1b678712adeee51665cdd829195bb800This is not good. I wonder why these tests weren't made before the vote
and results wheren't added in the RFC. Should we make it a standard
practice to do so? Having 2x slowdown on each property access sounds
like a bad idea.
Agreed. We added a performance impact section to the rfc template for this
exact reason.
We do not enforce it. Maybe we should.
Morning internals,
Since we have our answer on nullable types, typed properties can now go
to vote.
https://wiki.php.net/rfc/typed-properties#vote Note that, support for nullability as RFC'd will be merged when the
implementation for nullable_types is merged into master.
Please participate.
Cheers
Joe
I'm surprised at how popular this RFC has been; not because I think it's
a bad thing per se, but I thought it would be more controversial.
I do still think PHP should have a proper road map for typing features,
though. The issues around typed references in this RFC are a good
example of how having an increasing number of silos where type
enforcement takes place leads to odd inconsistencies and limitations. It
would be nice to have some idea of what the eventual aim is - even if we
don't know how yet, is the aim in people's minds for "optional typing"
to extend throughout the language?
This would also help with performance considerations - if type-checking
is going to become a more important concept in the language, the engine
should move in a direction which will make that easier, and that may
affect optimisation decisions.
Regards,
Rowan Collins
[IMSoP]
Should this work?
<?php
class C {
public double $x;
}
$o = new C;
$o->x = 5;
?>
Currently this leads to PHP Fatal error: Uncaught TypeError: Typed property C::$x must be an instance of double, integer used in /home/dmitry/php/php-master/CGI-DEBUG/prop.php:6
Dmitry Stogov dmitry@zend.com schrieb am Mo., 23. Mai 2016 14:48:
Should this work?
<?php
class C {
public double $x;
}
$o = new C;
$o->x = 5;
?>Currently this leads to PHP Fatal error: Uncaught TypeError: Typed
property C::$x must be an instance of double, integer used in
/home/dmitry/php/php-master/CGI-DEBUG/prop.php:6
Do you mean "float"?
From: Joe Watkins pthreads@pthreads.org
Sent: Friday, May 20, 2016 9:05:34 AM
To: PHP internals; Phil Sturgeon
Subject: [PHP-DEV] [RFC][Vote] Typed PropertiesMorning internals,
Since we have our answer on nullable types, typed properties can now go
to vote.
https://wiki.php.net/rfc/typed-properties#vote Note that, support for nullability as RFC'd will be merged when the
implementation for nullable_types is merged into master.
Please participate.
Cheers
Joe
Hi Joe,
I've add implementation for nullable typed properties (as they fit into the patch design), but RFC missed any description of nullable properties.
See tests Zend/tests/type_declarations/typed_properties_047.phpt, Zend/tests/type_declarations/typed_properties_048.phpt, Zend/tests/type_declarations/typed_properties_049.phpt
I'm not sure, if this is what the voters expect. At least I don't like the facts that "?int $foo;" declares uninitialized property; "?int $foo = NULL" may be unset() and became uninitialized; and it's an open question if "int $foo = NULL;" should be supported as nullable. Inheritance rules for typed nullable properties are also missed.
Personally, I think the RFC was moved into voting state too early (without good enough implementation, and with missing topics).
The current implementation is better (performance penalty reduced to ~2%), but still have unsolved problems.
May be it's better to cancel voting, solve problems, finish the implementation and add missing questions into RFC...
I'm going to help with implementation in any case, but we should agree on what we are doing.
Thanks. Dmitry.
Morning Dmitry,
There's no section for nullables, but there is mention of them,
specifically in relation to your query:
While parameters allow null to be accepted as the default value, null
is only a valid value for nullable properties.
Is there something wrong with that rule ?
Having explicit nullability means the declaration tells you all you need
to know, all the time.
Being able to set null any typed property means you can never be sure of
the type; You can't tell by looking at the declaration what type the
variable will be because anything is allowed to set it null.
We waited for explicit nullability to avoid this.
You'll have to have a really good reason for me to change that rule :)
Inheritance rules for typed nullable properties are also missed.
That's true, but shouldn't they use the same rules as nullable
parameters, will discussion change how they should work ?
but still have unsolved problems.
If you have discussed these somewhere, can you send/show the transcript
? (I missed all comms after yesterday morning, due to illness).
If it emerges that the RFC needs to be modified heavily, then I'm happy
to stop the voting.
But, so far, we haven't actually deviated from the RFC, only changed
implementation details that are not part of the design of the feature.
Sorry if it seems like I'm missing information, I don't know what you
and Bob found out yet ...
I super appreciate you guys working on it, obviously. Thanks for that :)
Cheers
Joe
Hi Joe,
I've add implementation for nullable typed properties (as they fit into
the patch design), but RFC missed any description of nullable properties.
See tests Zend/tests/type_declarations/typed_properties_047.phpt,
Zend/tests/type_declarations/typed_properties_048.phpt,
Zend/tests/type_declarations/typed_properties_049.phptI'm not sure, if this is what the voters expect. At least I don't like the
facts that "?int $foo;" declares uninitialized property; "?int $foo = NULL"
may be unset() and became uninitialized; and it's an open question if "int
$foo = NULL;" should be supported as nullable. Inheritance rules for typed
nullable properties are also missed.Personally, I think the RFC was moved into voting state too early (without
good enough implementation, and with missing topics).
The current implementation is better (performance penalty reduced to ~2%),
but still have unsolved problems.May be it's better to cancel voting, solve problems, finish the
implementation and add missing questions into RFC...
I'm going to help with implementation in any case, but we should agree on
what we are doing.Thanks. Dmitry.
From: Joe Watkins pthreads@pthreads.org
Sent: Friday, May 20, 2016 9:05:34 AM
To: PHP internals; Phil Sturgeon
Subject: [PHP-DEV] [RFC][Vote] Typed PropertiesMorning internals,
Since we have our answer on nullable types, typed properties can now go
to vote.
https://wiki.php.net/rfc/typed-properties#vote Note that, support for nullability as RFC'd will be merged when the
implementation for nullable_types is merged into master.
Please participate.
Cheers
Joe
Morning Dmitry,
There's no section for nullables, but there is mention of them,
specifically in relation to your query:While parameters allow null to be accepted as the default value,
null is only a valid value for nullable properties.Is there something wrong with that rule ?
It's OK. This just should be defined and it's defined in RFC (I missed)
Having explicit nullability means the declaration tells you all you
need to know, all the time.Being able to set null any typed property means you can never be
sure of the type; You can't tell by looking at the declaration what
type the variable will be because anything is allowed to set it null.We waited for explicit nullability to avoid this.
You'll have to have a really good reason for me to change that rule :)
Inheritance rules for typed nullable properties are also missed.
That's true, but shouldn't they use the same rules as nullable
parameters, will discussion change how they should work ?
I made this check(s) to be invariant. You may like to do this differently...
It's better to define this in RFC, check implementation and add tests.
but still have unsolved problems.
If you have discussed these somewhere, can you send/show the
transcript ? (I missed all comms after yesterday morning, due to illness).
We are working with Bob, trying to improve the patch. I added new tests
fixing the problems, and also added few comments o github.
If it emerges that the RFC needs to be modified heavily, then I'm
happy to stop the voting.
RFC doesn't define how uninitialized nullable typed properties should
behave.
class C {
public $a;
public int $b;
public ?int $c;
}
$obj = new C;
var_dump($obj->a); // NULL
var_dump($obj->b); // throw Error("")
var_dump($obj->c); // first or second??? (currently throw Error("")).
$obj->$a = null;
$obj->$b = null; // throw Error("")
$obj->$c = null;
var_dump($obj->a); // NULL
var_dump($obj->b); // throw Error("")
var_dump($obj->c); // NULL
unset($obj->$a);
unset($obj->$b);
unset($obj->$c);
var_dump($obj->a); // notice + NULL
var_dump($obj->b); // throw Error("")
var_dump($obj->c); // first or second??? (currently throw Error("")).
This should be defined.
But, so far, we haven't actually deviated from the RFC, only
changed implementation details that are not part of the design of the
feature.
I'm not so sure.
Anyway, I hope you are better and we will able to speak today or tomorrow.
Thanks. Dmitry.
Sorry if it seems like I'm missing information, I don't know what
you and Bob found out yet ...I super appreciate you guys working on it, obviously. Thanks for
that :)Cheers
JoeOn Tue, May 24, 2016 at 8:04 PM, Dmitry Stogov <dmitry@zend.com
mailto:dmitry@zend.com> wrote:Hi Joe, I've add implementation for nullable typed properties (as they fit into the patch design), but RFC missed any description of nullable properties. See tests Zend/tests/type_declarations/typed_properties_047.phpt, Zend/tests/type_declarations/typed_properties_048.phpt, Zend/tests/type_declarations/typed_properties_049.phpt I'm not sure, if this is what the voters expect. At least I don't like the facts that "?int $foo;" declares uninitialized property; "?int $foo = NULL" may be unset() and became uninitialized; and it's an open question if "int $foo = NULL;" should be supported as nullable. Inheritance rules for typed nullable properties are also missed. Personally, I think the RFC was moved into voting state too early (without good enough implementation, and with missing topics). The current implementation is better (performance penalty reduced to ~2%), but still have unsolved problems. May be it's better to cancel voting, solve problems, finish the implementation and add missing questions into RFC... I'm going to help with implementation in any case, but we should agree on what we are doing. Thanks. Dmitry. ________________________________________ From: Joe Watkins <pthreads@pthreads.org <mailto:pthreads@pthreads.org>> Sent: Friday, May 20, 2016 9:05:34 AM To: PHP internals; Phil Sturgeon Subject: [PHP-DEV] [RFC][Vote] Typed Properties Morning internals, Since we have our answer on nullable types, typed properties can now go to vote. https://wiki.php.net/rfc/typed-properties#vote Note that, support for nullability as RFC'd will be merged when the implementation for nullable_types is merged into master. Please participate. Cheers Joe
Morning Dmitry,
I made this check(s) to be invariant. You may like to do this
differently...
I think this is what everyone expects, isn't it ?
I did omit to mention that part ...
RFC doesn't define how uninitialized nullable typed properties should
behave.
It does:
Nullable typed properties will not raise an exception when accessed
before initialization.
It's the only bold text in the document :)
It seems correct to me; We raise uninitialized exceptions to prohibit the
return of null to user land, for nullable properties we don't need to do
that.
It does mean that ?int $foo; has an implicit default value of null, but I
can't see anything wrong with that, for a nullable property.
I'm open to being persuaded that is wrong.
I will review comments and current patch this morning ...
Cheers
Joe
Morning Dmitry,
There's no section for nullables, but there is mention of them,
specifically in relation to your query:While parameters allow null to be accepted as the default value, null
is only a valid value for nullable properties.Is there something wrong with that rule ?
It's OK. This just should be defined and it's defined in RFC (I missed)
Having explicit nullability means the declaration tells you all you
need to know, all the time.Being able to set null any typed property means you can never be sure
of the type; You can't tell by looking at the declaration what type the
variable will be because anything is allowed to set it null.We waited for explicit nullability to avoid this.
You'll have to have a really good reason for me to change that rule :)
Inheritance rules for typed nullable properties are also missed.
That's true, but shouldn't they use the same rules as nullable
parameters, will discussion change how they should work ?I made this check(s) to be invariant. You may like to do this
differently...
It's better to define this in RFC, check implementation and add tests.but still have unsolved problems.
If you have discussed these somewhere, can you send/show the transcript
? (I missed all comms after yesterday morning, due to illness).We are working with Bob, trying to improve the patch. I added new tests
fixing the problems, and also added few comments o github.If it emerges that the RFC needs to be modified heavily, then I'm happy
to stop the voting.RFC doesn't define how uninitialized nullable typed properties should
behave.class C {
public $a;
public int $b;
public ?int $c;
}
$obj = new C;
var_dump($obj->a); //NULL
var_dump($obj->b); // throw Error("")
var_dump($obj->c); // first or second??? (currently throw Error("")).
$obj->$a = null;
$obj->$b = null; // throw Error("")
$obj->$c = null;
var_dump($obj->a); //NULL
var_dump($obj->b); // throw Error("")
var_dump($obj->c); //NULL
unset($obj->$a);
unset($obj->$b);
unset($obj->$c);
var_dump($obj->a); // notice +NULL
var_dump($obj->b); // throw Error("")
var_dump($obj->c); // first or second??? (currently throw Error("")).This should be defined.
But, so far, we haven't actually deviated from the RFC, only changed
implementation details that are not part of the design of the feature.I'm not so sure.
Anyway, I hope you are better and we will able to speak today or tomorrow.Thanks. Dmitry.
Sorry if it seems like I'm missing information, I don't know what you
and Bob found out yet ...I super appreciate you guys working on it, obviously. Thanks for that :)
Cheers
JoeHi Joe,
I've add implementation for nullable typed properties (as they fit into
the patch design), but RFC missed any description of nullable properties.
See tests Zend/tests/type_declarations/typed_properties_047.phpt,
Zend/tests/type_declarations/typed_properties_048.phpt,
Zend/tests/type_declarations/typed_properties_049.phptI'm not sure, if this is what the voters expect. At least I don't like
the facts that "?int $foo;" declares uninitialized property; "?int $foo =
NULL" may be unset() and became uninitialized; and it's an open question if
"int $foo = NULL;" should be supported as nullable. Inheritance rules for
typed nullable properties are also missed.Personally, I think the RFC was moved into voting state too early
(without good enough implementation, and with missing topics).
The current implementation is better (performance penalty reduced to
~2%), but still have unsolved problems.May be it's better to cancel voting, solve problems, finish the
implementation and add missing questions into RFC...
I'm going to help with implementation in any case, but we should agree on
what we are doing.Thanks. Dmitry.
From: Joe Watkins pthreads@pthreads.org
Sent: Friday, May 20, 2016 9:05:34 AM
To: PHP internals; Phil Sturgeon
Subject: [PHP-DEV] [RFC][Vote] Typed PropertiesMorning internals,
Since we have our answer on nullable types, typed properties can now
go
to vote.https://wiki.php.net/rfc/typed-properties#vote Note that, support for nullability as RFC'd will be merged when the
implementation for nullable_types is merged into master.
Please participate.
Cheers
Joe
Morning Dmitry,
I made this check(s) to be invariant. You may like to do this
differently...I think this is what everyone expects, isn't it ?
I did omit to mention that part ...
RFC doesn't define how uninitialized nullable typed properties
should behave.It does:
Nullable typed properties will not raise an exception when
accessed before initialization.It's the only bold text in the document :)
It seems correct to me; We raise uninitialized exceptions to
prohibit the return of null to user land, for nullable properties we
don't need to do that.It does mean that ?int $foo; has an implicit default value of null,
but I can't see anything wrong with that, for a nullable property.
OK. This is the same that I like. I'll change implementation accordingly.
But what should unset() do?
Currently it makes property uninitialized and then it can't accessed.
I suppose it should emit notice and return NULL.
I'll change this as well (in an hour).
Thanks. Dmitry.
I'm open to being persuaded that is wrong.
I will review comments and current patch this morning ...
Cheers
JoeOn Wed, May 25, 2016 at 8:06 AM, Dmitry Stogov <dmitry@zend.com
mailto:dmitry@zend.com> wrote:Morning Dmitry, There's no section for nullables, but there is mention of them, specifically in relation to your query: > While parameters allow null to be accepted as the default value, null is only a valid value for nullable properties. Is there something wrong with that rule ?
It's OK. This just should be defined and it's defined in RFC (I missed)
Having explicit nullability means the declaration tells you all you need to know, all the time. Being able to set null any typed property means you can never be sure of the type; You can't tell by looking at the declaration what type the variable will be because anything is allowed to set it null. We waited for explicit nullability to avoid this. You'll have to have a really good reason for me to change that rule :) > Inheritance rules for typed nullable properties are also missed. That's true, but shouldn't they use the same rules as nullable parameters, will discussion change how they should work ?
I made this check(s) to be invariant. You may like to do this differently... It's better to define this in RFC, check implementation and add tests.
> but still have unsolved problems. If you have discussed these somewhere, can you send/show the transcript ? (I missed all comms after yesterday morning, due to illness).
We are working with Bob, trying to improve the patch. I added new tests fixing the problems, and also added few comments o github.
If it emerges that the RFC needs to be modified heavily, then I'm happy to stop the voting.
RFC doesn't define how uninitialized nullable typed properties should behave. class C { public $a; public int $b; public ?int $c; } $obj = new C; var_dump($obj->a); // `NULL` var_dump($obj->b); // throw Error("") var_dump($obj->c); // first or second??? (currently throw Error("")). $obj->$a = null; $obj->$b = null; // throw Error("") $obj->$c = null; var_dump($obj->a); // `NULL` var_dump($obj->b); // throw Error("") var_dump($obj->c); // `NULL` unset($obj->$a); unset($obj->$b); unset($obj->$c); var_dump($obj->a); // notice + `NULL` var_dump($obj->b); // throw Error("") var_dump($obj->c); // first or second??? (currently throw Error("")). This should be defined.
But, so far, we haven't actually deviated from the RFC, only changed implementation details that are not part of the design of the feature.
I'm not so sure. Anyway, I hope you are better and we will able to speak today or tomorrow. Thanks. Dmitry.
Sorry if it seems like I'm missing information, I don't know what you and Bob found out yet ... I super appreciate you guys working on it, obviously. Thanks for that :) Cheers Joe On Tue, May 24, 2016 at 8:04 PM, Dmitry Stogov <dmitry@zend.com <mailto:dmitry@zend.com>> wrote: Hi Joe, I've add implementation for nullable typed properties (as they fit into the patch design), but RFC missed any description of nullable properties. See tests Zend/tests/type_declarations/typed_properties_047.phpt, Zend/tests/type_declarations/typed_properties_048.phpt, Zend/tests/type_declarations/typed_properties_049.phpt I'm not sure, if this is what the voters expect. At least I don't like the facts that "?int $foo;" declares uninitialized property; "?int $foo = NULL" may be unset() and became uninitialized; and it's an open question if "int $foo = NULL;" should be supported as nullable. Inheritance rules for typed nullable properties are also missed. Personally, I think the RFC was moved into voting state too early (without good enough implementation, and with missing topics). The current implementation is better (performance penalty reduced to ~2%), but still have unsolved problems. May be it's better to cancel voting, solve problems, finish the implementation and add missing questions into RFC... I'm going to help with implementation in any case, but we should agree on what we are doing. Thanks. Dmitry. ________________________________________ From: Joe Watkins <pthreads@pthreads.org <mailto:pthreads@pthreads.org>> Sent: Friday, May 20, 2016 9:05:34 AM To: PHP internals; Phil Sturgeon Subject: [PHP-DEV] [RFC][Vote] Typed Properties Morning internals, Since we have our answer on nullable types, typed properties can now go to vote. https://wiki.php.net/rfc/typed-properties#vote Note that, support for nullability as RFC'd will be merged when the implementation for nullable_types is merged into master. Please participate. Cheers Joe
Morning Dmitry,
> I suppose it should emit notice and return NULL.
Yes, as untyped properties do (they would also invoke magic for unset,
but defined property).
> I'll change this as well (in an hour).
Thanks ...
Nullable property support was missing from the implementation,
completely, because it wasn't merged at the time, but I did mention it
would be added.
It seems like we are changing details that should have been mentioned,
we're not in some cases, just clarifying them ... but I admit it's
clarification that should have been included in the RFC in some cases.
I would like to know what others think about halting the vote, and
reopening in a few days when we have finalized the implementation, and
possibly put some finishing touches on the RFC.
If a few people want that to happen, happy to do it ... personally, I
don't think we've deviated from the RFC.
Cheers
Joe
Morning Dmitry,
I made this check(s) to be invariant. You may like to do this
differently...I think this is what everyone expects, isn't it ?
I did omit to mention that part ...
RFC doesn't define how uninitialized nullable typed properties should
behave.It does:
Nullable typed properties will not raise an exception when accessed
before initialization.It's the only bold text in the document :)
It seems correct to me; We raise uninitialized exceptions to prohibit
the return of null to user land, for nullable properties we don't need to
do that.It does mean that ?int $foo; has an implicit default value of null, but
I can't see anything wrong with that, for a nullable property.OK. This is the same that I like. I'll change implementation accordingly.
But what should unset() do?
Currently it makes property uninitialized and then it can't accessed.
I suppose it should emit notice and return NULL.
I'll change this as well (in an hour).Thanks. Dmitry.
I'm open to being persuaded that is wrong.
I will review comments and current patch this morning ...
Cheers
JoeMorning Dmitry,
There's no section for nullables, but there is mention of them,
specifically in relation to your query:While parameters allow null to be accepted as the default value,
null is only a valid value for nullable properties.Is there something wrong with that rule ?
It's OK. This just should be defined and it's defined in RFC (I missed)
Having explicit nullability means the declaration tells you all you
need to know, all the time.Being able to set null any typed property means you can never be sure
of the type; You can't tell by looking at the declaration what type the
variable will be because anything is allowed to set it null.We waited for explicit nullability to avoid this.
You'll have to have a really good reason for me to change that rule :)
Inheritance rules for typed nullable properties are also missed.
That's true, but shouldn't they use the same rules as nullable
parameters, will discussion change how they should work ?I made this check(s) to be invariant. You may like to do this
differently...
It's better to define this in RFC, check implementation and add tests.but still have unsolved problems.
If you have discussed these somewhere, can you send/show the
transcript ? (I missed all comms after yesterday morning, due to illness).We are working with Bob, trying to improve the patch. I added new tests
fixing the problems, and also added few comments o github.If it emerges that the RFC needs to be modified heavily, then I'm
happy to stop the voting.RFC doesn't define how uninitialized nullable typed properties should
behave.class C {
public $a;
public int $b;
public ?int $c;
}
$obj = new C;
var_dump($obj->a); //NULL
var_dump($obj->b); // throw Error("")
var_dump($obj->c); // first or second??? (currently throw Error("")).
$obj->$a = null;
$obj->$b = null; // throw Error("")
$obj->$c = null;
var_dump($obj->a); //NULL
var_dump($obj->b); // throw Error("")
var_dump($obj->c); //NULL
unset($obj->$a);
unset($obj->$b);
unset($obj->$c);
var_dump($obj->a); // notice +NULL
var_dump($obj->b); // throw Error("")
var_dump($obj->c); // first or second??? (currently throw Error("")).This should be defined.
But, so far, we haven't actually deviated from the RFC, only changed
implementation details that are not part of the design of the feature.I'm not so sure.
Anyway, I hope you are better and we will able to speak today or tomorrow.Thanks. Dmitry.
Sorry if it seems like I'm missing information, I don't know what you
and Bob found out yet ...I super appreciate you guys working on it, obviously. Thanks for that
:)Cheers
JoeOn Tue, May 24, 2016 at 8:04 PM, Dmitry Stogov < dmitry@zend.com
dmitry@zend.com> wrote:Hi Joe,
I've add implementation for nullable typed properties (as they fit into
the patch design), but RFC missed any description of nullable properties.
See tests Zend/tests/type_declarations/typed_properties_047.phpt,
Zend/tests/type_declarations/typed_properties_048.phpt,
Zend/tests/type_declarations/typed_properties_049.phptI'm not sure, if this is what the voters expect. At least I don't like
the facts that "?int $foo;" declares uninitialized property; "?int $foo =
NULL" may be unset() and became uninitialized; and it's an open question if
"int $foo = NULL;" should be supported as nullable. Inheritance rules for
typed nullable properties are also missed.Personally, I think the RFC was moved into voting state too early
(without good enough implementation, and with missing topics).
The current implementation is better (performance penalty reduced to
~2%), but still have unsolved problems.May be it's better to cancel voting, solve problems, finish the
implementation and add missing questions into RFC...
I'm going to help with implementation in any case, but we should agree
on what we are doing.Thanks. Dmitry.
From: Joe Watkins < pthreads@pthreads.orgpthreads@pthreads.org>
Sent: Friday, May 20, 2016 9:05:34 AM
To: PHP internals; Phil Sturgeon
Subject: [PHP-DEV] [RFC][Vote] Typed PropertiesMorning internals,
Since we have our answer on nullable types, typed properties can now
go
to vote.https://wiki.php.net/rfc/typed-properties#vote Note that, support for nullability as RFC'd will be merged when the
implementation for nullable_types is merged into master.
Please participate.
Cheers
Joe
Morning Dmitry,
I made this check(s) to be invariant. You may like to do this
differently...I think this is what everyone expects, isn't it ?
I did omit to mention that part ...
RFC doesn't define how uninitialized nullable typed properties should
behave.It does:
Nullable typed properties will not raise an exception when accessed
before initialization.
I don't agree with this choice, for three reasons:
a) This unnecessarily restricts what can be expressed in the type system.
With these semantics it will no longer be possible to express that a
property should be nullable, but have no default value. This situation is
not uncommon in practice, in particular anytime you have a nullable
constructor argument, you will want the corresponding property to be
nullable without a default, to ensure that it is explicitly initialized.
b) This directly contradicts the meaning of ?Type for parameters. For
parameters ?Type means that it's a nullable parameter without a default
value. That's the very thing that distinguishes it from the Type $prop =
null syntax. And now ?Type for properties should mean the exact opposite?
c) If you view this in a larger scope of union types, this special case
becomes even more weird. Why does the particular union Type|null get
special treatment, while all other unions don't? Or is it actually not
specific to "null", but to single value types? E.g. if we also allowed
Type|false, would that also receive an implicit false default value? What
about the type null|false? Does that get an implicit default, and if so,
which? I realize this is not quite in scope for type properties, but the
further evolution of the type system should be kept in mind.
Please keep things consistent: If there is not default, there is no default.
Nikita
Morning Nikita,
That's pretty persuasive ...
Dmitry, what are your thoughts on those points ?
Cheers
Joe
On Wed, May 25, 2016 at 10:30 AM, Joe Watkins pthreads@pthreads.org
wrote:Morning Dmitry,
I made this check(s) to be invariant. You may like to do this
differently...I think this is what everyone expects, isn't it ?
I did omit to mention that part ...
RFC doesn't define how uninitialized nullable typed properties should
behave.It does:
Nullable typed properties will not raise an exception when accessed
before initialization.I don't agree with this choice, for three reasons:
a) This unnecessarily restricts what can be expressed in the type system.
With these semantics it will no longer be possible to express that a
property should be nullable, but have no default value. This situation is
not uncommon in practice, in particular anytime you have a nullable
constructor argument, you will want the corresponding property to be
nullable without a default, to ensure that it is explicitly initialized.b) This directly contradicts the meaning of ?Type for parameters. For
parameters ?Type means that it's a nullable parameter without a default
value. That's the very thing that distinguishes it from the Type $prop =
null syntax. And now ?Type for properties should mean the exact opposite?c) If you view this in a larger scope of union types, this special case
becomes even more weird. Why does the particular union Type|null get
special treatment, while all other unions don't? Or is it actually not
specific to "null", but to single value types? E.g. if we also allowed
Type|false, would that also receive an implicit false default value? What
about the type null|false? Does that get an implicit default, and if so,
which? I realize this is not quite in scope for type properties, but the
further evolution of the type system should be kept in mind.Please keep things consistent: If there is not default, there is no
default.Nikita
Hi,
Nikita Popov wrote:
> *Nullable typed properties will not raise an exception when accessed
before initialization.*
I don't agree with this choice, for three reasons:
a) This unnecessarily restricts what can be expressed in the type system.
With these semantics it will no longer be possible to express that a
property should be nullable, but have no default value. This situation is
not uncommon in practice, in particular anytime you have a nullable
constructor argument, you will want the corresponding property to be
nullable without a default, to ensure that it is explicitly initialized.
I agree with you here. In some cases, there are three potential
meaningful states for a property:
- uninitialised - the constructor (or indeed, other code) is yet to set it
- null - the property is left intentionally empty
- some other value - the property is intentionally given a value
A simple example might be a Lisp-style linked list cell:
class LinkedList
{
public int $head;
public ?LinkedList $tail;
}
In a properly initialised LinkedList, the $head is some value, and the
$tail is either another linked list (the remainder of the list), or null
(we're at the end of the list).
Before the LinkedList is initialised, ideally both properties would be
undefined. That way, if we make a mistake and fail to explicitly set
either in our code, PHP will give us an error message.
However, the currently proposed behaviour would mean that this will only
happen for $head, and PHP will fill in null for $tail for us. Notice
that in this class, we aren't using null to mean a property that hasn't
yet been set. Instead, we're using it to mean a property that's been
deliberately left unfilled. So PHP has assumed for us that if we forget
to set $tail, the remainder of the list is empty. Yet PHP assumed that
if we forget to set $head, that's a mistake and must produce an error.
This inconsistency of assumptions is unhelpful, and I don't see how this
follows from the types I declared.
I don't understand why nullable properties have to behave differently
here, anyway. Doesn't it add complexity to the implementation to handle
them differently from non-nullable typed properties? Doesn't it
introduce inconsistency to assume a default value for nullable typed
properties, but not for non-nullable ones?
b) This directly contradicts the meaning of ?Type for parameters. For
parameters ?Type means that it's a nullable parameter without a default
value. That's the very thing that distinguishes it from the Type $prop =
null syntax. And now ?Type for properties should mean the exact opposite?
Given typed properties look much like typed parameters, it would be
reasonable for users to expect that they behave the same, so this is a
good point.
c) If you view this in a larger scope of union types, this special case
becomes even more weird. Why does the particular union Type|null get
special treatment, while all other unions don't? Or is it actually not
specific to "null", but to single value types? E.g. if we also allowed
Type|false, would that also receive an implicit false default value? What
about the type null|false? Does that get an implicit default, and if so,
which? I realize this is not quite in scope for type properties, but the
further evolution of the type system should be kept in mind.
This bothers me also.
Thanks!
Andrea Faulds
https://ajf.me/
Hi!
- uninitialised - the constructor (or indeed, other code) is yet to set it
- null - the property is left intentionally empty
For declared properties, this always has been the same, and I'm not sure
why would we want to change that. This also has a potential to be a huge
BC break if we change it not to be the same, since pretty much all the
code assumes it is the same. We'd essentially have to invent another
null, which is exactly the same as null but isn't null. I don't see a
reason to do this.
- some other value - the property is intentionally given a value
A simple example might be a Lisp-style linked list cell:
class LinkedList { public int $head; public ?LinkedList $tail; }
In a properly initialised LinkedList, the $head is some value, and the
$tail is either another linked list (the remainder of the list), or null
(we're at the end of the list).
This is a very weird list, as it can't be empty.
Stas Malyshev
smalyshev@gmail.com
Hi Stas,
Stanislav Malyshev wrote:
Hi!
- uninitialised - the constructor (or indeed, other code) is yet to set it
- null - the property is left intentionally empty
For declared properties, this always has been the same, and I'm not sure
why would we want to change that. This also has a potential to be a huge
BC break if we change it not to be the same, since pretty much all the
code assumes it is the same. We'd essentially have to invent another
null, which is exactly the same as null but isn't null. I don't see a
reason to do this.
It'd be a BC break if we changed untyped properties' behaviour, yeah. We
wouldn't be inventing a new null, though, we'd be leaving the property
undefined until it's initialised, which we already have support for
(properties, and indeed all variables can be unset()).
- some other value - the property is intentionally given a value
A simple example might be a Lisp-style linked list cell:
class LinkedList { public int $head; public ?LinkedList $tail; }
In a properly initialised LinkedList, the $head is some value, and the
$tail is either another linked list (the remainder of the list), or null
(we're at the end of the list).This is a very weird list, as it can't be empty.
The empty list is represented by null in this arrangement.
Thanks.
--
Andrea Faulds
https://ajf.me/
Hi!
It'd be a BC break if we changed untyped properties' behaviour, yeah. We
It's not that simple. Lots of code operates on sets of properties or
dynamic properties, not one specific property. That code now assumes
properties default to null. If there's another default, then all that
code will have to be changed in case somebody somewhere defines a typed
property.
The impact is that as soon as one typed property appears anywhere in the
code, pretty much all the code that deals with properties (within
affected property set) has to be changed to accommodate it. Unlike
parameters, which are local to function, properties are important across
big chunks of the code.
wouldn't be inventing a new null, though, we'd be leaving the property
undefined until it's initialised, which we already have support for
(properties, and indeed all variables can be unset()).
unset() now causes the property to disappear - as if it were never
defined. But you probably expect something different? So what isset()
would return for such property? What would is_null()
return? What would
gettype()
return?
A simple example might be a Lisp-style linked list cell:
class LinkedList { public int $head; public ?LinkedList $tail; }
In a properly initialised LinkedList, the $head is some value, and the
$tail is either another linked list (the remainder of the list), or null
(we're at the end of the list).This is a very weird list, as it can't be empty.
The empty list is represented by null in this arrangement.
null and empty list are very different thing. null is nothing, empty
list is an object of type LinkedList which just happens to not contain
any values. You can call methods on empty list - e.g. add elements to it
or check if it's empty or compare or concatenate with other list, etc. -
but you can't do it on null. Making assumption that null and an empty
container is the same is not a good idea usually.
--
Stas Malyshev
smalyshev@gmail.com
Hi,
Stanislav Malyshev wrote:
wouldn't be inventing a new null, though, we'd be leaving the property
undefined until it's initialised, which we already have support for
(properties, and indeed all variables can be unset()).unset() now causes the property to disappear - as if it were never
defined. But you probably expect something different? So what isset()
would return for such property? What wouldis_null()
return? What would
gettype()
return?
Why do you say "now"? unset() has done this for a long time, so far as I
know.
Thanks.
--
Andrea Faulds
https://ajf.me/
Hi!
Why do you say "now"? unset() has done this for a long time, so far as I
know.
True. But I don't see how would it work for typed properties - what
exactly would happen after unset? Would it be - as it is now - that it
is as if the property was never defined, or would it be something else?
--
Stas Malyshev
smalyshev@gmail.com
Hi!
Why do you say "now"? unset() has done this for a long time, so far as I
know.True. But I don't see how would it work for typed properties - what
exactly would happen after unset? Would it be - as it is now - that it
is as if the property was never defined, or would it be something else?
In my opinion it should simply vanish along with its definition. I mean,
isn't that the definition of unset in general.
--
Richard "Fleshgrinder" Fussenegger
2016-05-25 20:39 GMT+02:00 Fleshgrinder php@fleshgrinder.com:
In my opinion it should simply vanish along with its definition. I mean,
Usually, yes. But suddenly private Type $foo
isn't reliable anymore if
unset is supported for typed properties, because the following would just
remove all type info / enforcement:
$backup = $this->foo;
unset($this->foo);
$this->foo = $backup;
Unset can reset it to the default value, but wiping type information is
probably
not an option here.
Regards, Niklas
2016-05-25 20:39 GMT+02:00 Fleshgrinder php@fleshgrinder.com:
In my opinion it should simply vanish along with its definition. I mean,
Usually, yes. But suddenly
private Type $foo
isn't reliable anymore if
unset is supported for typed properties, because the following would just
remove all type info / enforcement:$backup = $this->foo;
unset($this->foo);
$this->foo = $backup;Unset can reset it to the default value, but wiping type information is
probably
not an option here.Regards, Niklas
I had to check because I never tried this once in my life (why would one
need it anyways) ...
class A {
private $foo = "foo";
function get() {
return $this->foo;
}
function unset() {
unset($this->foo);
}
}
$a = new A;
echo $a->get(); // foo
$a->unset();
echo $a->get(); // Notice: Undefined property: A::$foo
$a->foo = "foo";
// Fatal error: Uncaught Error: Cannot access private property A::$foo
In other words, unset is not really unset already!
QED: Preserving all attributes of a property is the only consistent
way. However, preserving its value is not.
I do not think that there is a problem together with the typed
properties, nullability, and unset simply because the property is not
explicitly assigned null by unset, it is being undefined.
I think internally null is actually assigned and it's not IS_UNDEF,
right? However, from a userland perspective it is definitely not defined
anymore and access should (as it does) result in an error (in our case
E_INFO) plus null is being returned but only because undefined does not
exist in PHP userland.
I did not read up on all the history yet but I am on it ...
--
Richard "Fleshgrinder" Fussenegger
Le Wed, 25 May 2016 21:40:28 +0200, Fleshgrinder php@fleshgrinder.com a
écrit:
and unset simply because the property is not
explicitly assigned null by unset, it is being undefined.
Because null !== undefined. That's why you get an error after an
unset($this->var), and you don't get one after $this->var = null; . "$var
= null;" and "unset($var)" are totally different, it has been like that
for years. If you want to change this behavior, propose an RFC, and make
it approve. But meanwhile, you'll have to keep this in mind : "null" is a
value. While "unset" does not affect a value, it deletes the variable, it
deletes any references of the variable it targets, the variable doesn't
exist anymore. With unset, the variable is dead. With null, it has
amnesia. I can't find any better analogy.
Le Wed, 25 May 2016 21:40:28 +0200, Fleshgrinder php@fleshgrinder.com
a écrit:and unset simply because the property is not
explicitly assigned null by unset, it is being undefined.Because null !== undefined. That's why you get an error after an
unset($this->var), and you don't get one after $this->var = null; .
"$var = null;" and "unset($var)" are totally different, it has been like
that for years. If you want to change this behavior, propose an RFC, and
make it approve. But meanwhile, you'll have to keep this in mind :
"null" is a value. While "unset" does not affect a value, it deletes the
variable, it deletes any references of the variable it targets, the
variable doesn't exist anymore. With unset, the variable is dead. With
null, it has amnesia. I can't find any better analogy.
Which is exactly what I wrote and think is correct. ;)
--
Richard "Fleshgrinder" Fussenegger
In other words, unset is not really unset already!
QED: Preserving all attributes of a property is the only consistent
way. However, preserving its value is not.I do not think that there is a problem together with the typed
properties, nullability, and unset simply because the property is not
explicitly assigned null by unset, it is being undefined.
Am I missing something here? If I have any variable defined, it has a
current state which may or may not include a value. If I 'unset' that
variable then it's 'object' is simply removed from the list of
variables, so creating a new variable which happens to have the same
name is totally unrelated.
I would still prefer that all this gloss being added to a sub set of
variables was addressing the whole problem, but a variable is always a
name and a value which may or may not be set along with a 'now' few more
attributes to constrain what that value is restricted to contain.
unset simply removes that name and content from the list and leaving any
'trail' which prevents creating a totally clean use of the same name is
simply wrong?
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
Unset can reset it to the default value, but wiping type information is
probably
not an option here.
Wiping type info is indeed unwanted. As it currently stands, for example,
un-setting a property and then re-assigning it retains its visibility
properties, and doesn't destroy property information.
See https://3v4l.org/pCmTV for an example (copied here for reference):
<?php
class Foo
{
private $bar = 'baz';
public function __construct()
{
unset($this->bar);
}
public function getFooBar()
{
return $this->bar;
}
}
class Bar extends Foo
{
private $bar = 'baz';
public function __construct()
{
parent::__construct();
unset($this->bar);
}
public function getBarBar()
{
return $this->bar;
}
}
$bar = new Bar();
var_dump($bar->getFooBar()); // notice + null
var_dump($bar->getBarBar()); // notice + null
$rBarBar = new ReflectionProperty(Foo::class, 'bar');
$rBarBar->setAccessible(true);
$rBarBar->setValue($bar, LINE);
var_dump($bar->getFooBar()); // line no.
var_dump($bar->getBarBar()); // notice + null
Marco Pivetta
Hi!
True. But I don't see how would it work for typed properties - what
exactly would happen after unset? Would it be - as it is now - that it
is as if the property was never defined, or would it be something else?In my opinion it should simply vanish along with its definition. I mean,
isn't that the definition of unset in general.
Right, that would be the easiest way. But then you lose guarantee that
variable you marked as "int" is indeed always int - you could unset it
and then set it to whatever you want because it no longer has a definition!
OTOH, we do have precedent for properties that can not be unset -
namely, static properties can not be unset. They can be nulled-out, of
course, and they default to null. I have no idea how "static int $x;"
would work though. The current RFC doesn't implement it, which
definitely would be weird since people would expect if you can have
typed object property, you can have typed static property, but that's
not what the RFC says.
--
Stas Malyshev
smalyshev@gmail.com
OTOH, we do have precedent for properties that can not be unset -
namely, static properties can not be unset. They can be nulled-out, of
course, and they default to null. I have no idea how "static int $x;"
would work though. The current RFC doesn't implement it, which
definitely would be weird since people would expect if you can have
typed object property, you can have typed static property, but that's
not what the RFC says.
This was also a point that I found to be weird and I am absolutely sure
that this will cast confusion as you are.
--
Richard "Fleshgrinder" Fussenegger
On Wed, May 25, 2016 at 10:30 AM, Joe Watkins pthreads@pthreads.org
wrote:Morning Dmitry,
I made this check(s) to be invariant. You may like to do this
differently...I think this is what everyone expects, isn't it ?
I did omit to mention that part ...
RFC doesn't define how uninitialized nullable typed properties
should
behave.It does:
Nullable typed properties will not raise an exception when accessed
before initialization.I don't agree with this choice, for three reasons:
a) This unnecessarily restricts what can be expressed in the type system.
With these semantics it will no longer be possible to express that a
property should be nullable, but have no default value. This situation is
not uncommon in practice, in particular anytime you have a nullable
constructor argument, you will want the corresponding property to be
nullable without a default, to ensure that it is explicitly initialized.
I disagree here. Properties are always null by default. The current patch
disallows
access to uninitialized variables only if they're not nullable, since null
isn't a valid value then.
I don't think having to explicitly set them to null is the think we want.
And it's not what I'd expect given the current system.
b) This directly contradicts the meaning of ?Type for parameters. For
parameters ?Type means that it's a nullable parameter without a default
value. That's the very thing that distinguishes it from the Type $prop =
null syntax. And now ?Type for properties should mean the exact opposite?
These have always been different. private $foo
has always been null
by
default,
while function($foo)
doesn't have a default value.
c) If you view this in a larger scope of union types, this special case
becomes even more weird. Why does the particular union Type|null get
special treatment, while all other unions don't? Or is it actually not
specific to "null", but to single value types? E.g. if we also allowed
Type|false, would that also receive an implicit false default value? What
about the type null|false? Does that get an implicit default, and if so,
which? I realize this is not quite in scope for type properties, but the
further evolution of the type system should be kept in mind.
I think this is something unions should address. I'm personally still not a
fan of union types,
as they try to solve the wrong problem, mostly things like array not being
instance of Traversable.
Regards, Niklas
Please keep things consistent: If there is not default, there is no
default.Nikita
Hi Niklas,
Niklas Keller wrote:
I disagree here. Properties are always null by default. The current patch
disallows
access to uninitialized variables only if they're not nullable, since null
isn't a valid value then.I don't think having to explicitly set them to null is the think we want.
And it's not what I'd expect given the current system.
PHP's existing untyped properties are implicitly initialised to null,
and so yes, we would essentially only be copying our existing behaviour.
However, I think it is worth asking whether our existing behaviour is
useful before we preserve it here. From my perspective, it is unhelpful
that PHP does not warn you about using properties you haven't
initialised, and this applies to both typed and untyped properties. In
some cases (like in my linked list example in a previous email), null
might be a meaningful value and worth distinguishing from a property not
having being initialised yet.
We can't change the behaviour of our existing untyped properties (or at
least, that's beyond the scope of this RFC), but we could choose the
behaviour we find more useful for our typed properties.
Consider that we did something like this for parameters. Not providing
an untyped parameter gives an E_WARNING:
$ php -r 'function foo($a) {} foo();'
PHP Warning: Missing argument 1 for foo(), called in Command line code
on line 1 and defined in Command line code on line 1
But not providing a typed parameter gives a TypeError:
$ php -r 'function foo(int $a) {} foo();'
PHP Fatal error: Uncaught TypeError: Argument 1 passed to foo() must be
of the type integer, none given, called in Command line code on line 1
and defined in Command line code:1
Stack trace:
#0 Command line code(1): foo()
#1 {main}
thrown in Command line code on line 1
So there's a precedent for applying stricter rules when type
declarations are used.
Thanks!
--
Andrea Faulds
https://ajf.me/
This is a cool idea and continuation of the typing systems so I've been
sort of skimming this thread as its been discussed and this example and the
associated errors caught my attention.
class C {
public $a;
public int $b;
public ?int $c;
}
$obj = new C;
Excuse me if this has been addressed but to clarify, using that snippet,
would this also throw an error?
var_dump($obj);
If so, I see a lot of cursing in my future if this goes in. Like "what's
the bad data on this object that's getting in here? aww #$%^ that
deprecated property wasn't set so the whole thing blew up!" sort of
cursing. :(
Am 25.05.2016 um 17:57 schrieb James Gilliland neclimdul@gmail.com:
This is a cool idea and continuation of the typing systems so I've been
sort of skimming this thread as its been discussed and this example and the
associated errors caught my attention.class C {
public $a;
public int $b;
public ?int $c;
}
$obj = new C;Excuse me if this has been addressed but to clarify, using that snippet,
would this also throw an error?var_dump($obj);
If so, I see a lot of cursing in my future if this goes in. Like "what's
the bad data on this object that's getting in here? aww #$%^ that
deprecated property wasn't set so the whole thing blew up!" sort of
cursing. :(
These don't throw errors, they just won't appear upon foreach or print_r etc., just like other unset() properties.
var_dump()
/debug_zval_dump() are special casing it and display e.g. "uninitialized(int)" for $b.
Bob
Hi Niklas,
Niklas Keller wrote:
I disagree here. Properties are always null by default. The current patch
disallows
access to uninitialized variables only if they're not nullable, since null
isn't a valid value then.I don't think having to explicitly set them to null is the think we want.
And it's not what I'd expect given the current system.PHP's existing untyped properties are implicitly initialised to null, and
so yes, we would essentially only be copying our existing behaviour.However, I think it is worth asking whether our existing behaviour is
useful before we preserve it here. From my perspective, it is unhelpful
that PHP does not warn you about using properties you haven't initialised,
and this applies to both typed and untyped properties. In some cases (like
in my linked list example in a previous email), null might be a meaningful
value and worth distinguishing from a property not having being initialised
yet.
Null shouldn't have any meaning apart from "not set". It should never be a
meaningful value.
We can't change the behaviour of our existing untyped properties (or at
least, that's beyond the scope of this RFC), but we could choose the
behaviour we find more useful for our typed properties.Consider that we did something like this for parameters. Not providing an
untyped parameter gives an E_WARNING:$ php -r 'function foo($a) {} foo();'
PHP Warning: Missing argument 1 for foo(), called in Command line code on
line 1 and defined in Command line code on line 1But not providing a typed parameter gives a TypeError:
$ php -r 'function foo(int $a) {} foo();'
PHP Fatal error: Uncaught TypeError: Argument 1 passed to foo() must be
of the type integer, none given, called in Command line code on line 1 and
defined in Command line code:1
Stack trace:
#0 Command line code(1): foo()
#1 {main}
thrown in Command line code on line 1So there's a precedent for applying stricter rules when type declarations
are used.Thanks!
--
Andrea Faulds
https://ajf.me/
Hey Niklas,
Am 25.05.2016 um 18:21 schrieb Niklas Keller me@kelunik.com:
Hi Niklas,
Niklas Keller wrote:
I disagree here. Properties are always null by default. The current patch
disallows
access to uninitialized variables only if they're not nullable, since null
isn't a valid value then.I don't think having to explicitly set them to null is the think we want.
And it's not what I'd expect given the current system.PHP's existing untyped properties are implicitly initialised to null, and
so yes, we would essentially only be copying our existing behaviour.However, I think it is worth asking whether our existing behaviour is
useful before we preserve it here. From my perspective, it is unhelpful
that PHP does not warn you about using properties you haven't initialised,
and this applies to both typed and untyped properties. In some cases (like
in my linked list example in a previous email), null might be a meaningful
value and worth distinguishing from a property not having being initialised
yet.Null shouldn't have any meaning apart from "not set". It should never be a
meaningful value.We can't change the behaviour of our existing untyped properties (or at
least, that's beyond the scope of this RFC), but we could choose the
behaviour we find more useful for our typed properties.Consider that we did something like this for parameters. Not providing an
untyped parameter gives an E_WARNING:$ php -r 'function foo($a) {} foo();'
PHP Warning: Missing argument 1 for foo(), called in Command line code on
line 1 and defined in Command line code on line 1But not providing a typed parameter gives a TypeError:
$ php -r 'function foo(int $a) {} foo();'
PHP Fatal error: Uncaught TypeError: Argument 1 passed to foo() must be
of the type integer, none given, called in Command line code on line 1 and
defined in Command line code:1
Stack trace:
#0 Command line code(1): foo()
#1 {main}
thrown in Command line code on line 1So there's a precedent for applying stricter rules when type declarations
are used.Thanks!
--
Andrea Faulds
https://ajf.me/
There is a difference between not set and no meaningful value.
The former is literally unset(), the latter is null. The only semantics PHP exposes here is that not set can be upgraded to "no meaningful" value in form of null with a notice.
The difference thus is quite minor, but semantically important.
Hence to set the value, we need to explicitly set null.
If we don't do it this way, we won't have a way to explicitly set nullable properties to a value (null in this case). (without explicit unset in ctor).
Bob
There is a difference between not set and no meaningful value.
In PHP, there's no such difference for properties. And I think we should be
consistent with the existing behavior here.
The former is literally unset(), the latter is null. The only semantics
PHP exposes here is that not set can be upgraded to "no meaningful" value
in form of null with a notice.The difference thus is quite minor, but semantically important.
Hence to set the value, we need to explicitly set null.If we don't do it this way, we won't have a way to explicitly set
nullable properties to a value (null in this case). (without explicit unset
in ctor).Bob
Since there are so many questions about nullable state (the default, in
PHP), would it make sense to enforce nullable types, for now?
Specifically, the current RFC could be simplified until further clarity is
made on how non-nullability behaves:
- we'd enforce users to always have
private ?Type $foo;
in their
signatures for 7.1 - we'd allow
private Type $foo;
for 7.2, when the behavior of
non-nullable properties is fully clarified - until then,
private Type $foo;
will cause a parser error
I'm just trying to simplify things to get such a feature in, as type
checking on object properties is a huge and very beneficial addition.
Marco Pivetta
There is a difference between not set and no meaningful value.
In PHP, there's no such difference for properties. And I think we should be
consistent with the existing behavior here.The former is literally unset(), the latter is null. The only semantics
PHP exposes here is that not set can be upgraded to "no meaningful" value
in form of null with a notice.The difference thus is quite minor, but semantically important.
Hence to set the value, we need to explicitly set null.If we don't do it this way, we won't have a way to explicitly set
nullable properties to a value (null in this case). (without explicit
unset
in ctor).Bob
Hi Niklas,
Niklas Keller wrote:
There is a difference between not set and no meaningful value.
In PHP, there's no such difference for properties. And I think we should be
consistent with the existing behavior here.
That's not quite true, unset properties produce a notice when accessed,
properties set to null do not, and it is possible to check whether a
property is set or not versus just null. Likewise with variables, array
members, etc.
Thanks.
--
Andrea Faulds
https://ajf.me/
Andrea Faulds ajf@ajf.me schrieb am Mi., 25. Mai 2016 19:14:
Hi Niklas,
Niklas Keller wrote:
There is a difference between not set and no meaningful value.
In PHP, there's no such difference for properties. And I think we should
be
consistent with the existing behavior here.That's not quite true, unset properties produce a notice when accessed,
properties set to null do not, and it is possible to check whether a
property is set or not versus just null. Likewise with variables, array
members, etc.
We're talking about two different things. Once it's the default value after
declaring it with private ?Type $foo and on the other hand the behavior
after unser. IMO the first should default to null while unsetting a typed
property should fail.
Thanks.
--
Andrea Faulds
https://ajf.me/
Hey Niklas,
Am 25.05.2016 um 18:21 schrieb Niklas Keller me@kelunik.com:
Hi Niklas,
Niklas Keller wrote:
I disagree here. Properties are always null by default. The current
patch
disallows
access to uninitialized variables only if they're not nullable, since
null
isn't a valid value then.I don't think having to explicitly set them to null is the think we
want.
And it's not what I'd expect given the current system.PHP's existing untyped properties are implicitly initialised to null,
and
so yes, we would essentially only be copying our existing behaviour.However, I think it is worth asking whether our existing behaviour is
useful before we preserve it here. From my perspective, it is unhelpful
that PHP does not warn you about using properties you haven't
initialised,
and this applies to both typed and untyped properties. In some cases
(like
in my linked list example in a previous email), null might be a
meaningful
value and worth distinguishing from a property not having being
initialised
yet.Null shouldn't have any meaning apart from "not set". It should never be
a
meaningful value.We can't change the behaviour of our existing untyped properties (or at
least, that's beyond the scope of this RFC), but we could choose the
behaviour we find more useful for our typed properties.Consider that we did something like this for parameters. Not providing
an
untyped parameter gives an E_WARNING:$ php -r 'function foo($a) {} foo();'
PHP Warning: Missing argument 1 for foo(), called in Command line code
on
line 1 and defined in Command line code on line 1But not providing a typed parameter gives a TypeError:
$ php -r 'function foo(int $a) {} foo();'
PHP Fatal error: Uncaught TypeError: Argument 1 passed to foo() must be
of the type integer, none given, called in Command line code on line 1
and
defined in Command line code:1
Stack trace:
#0 Command line code(1): foo()
#1 {main}
thrown in Command line code on line 1So there's a precedent for applying stricter rules when type
declarations
are used.Thanks!
--
Andrea Faulds
https://ajf.me/There is a difference between not set and no meaningful value.
The former is literally unset(), the latter is null. The only semantics
PHP exposes here is that not set can be upgraded to "no meaningful" value
in form of null with a notice.The difference thus is quite minor, but semantically important.
Hence to set the value, we need to explicitly set null.
Adding a type shouldn't alter behavior, so setting it explicitly to null
shouldn't be required.
Regards, Niklas
If we don't do it this way, we won't have a way to explicitly set
nullable properties to a value (null in this case). (without explicit unset
in ctor).Bob
PHP's existing untyped properties are implicitly initialised to null,
and so yes, we would essentially only be copying our existing behaviour.However, I think it is worth asking whether our existing behaviour is
useful before we preserve it here. From my perspective, it is unhelpful
that PHP does not warn you about using properties you haven't
initialised, and this applies to both typed and untyped properties. In
some cases (like in my linked list example in a previous email), null
might be a meaningful value and worth distinguishing from a property not
having being initialised yet.We can't change the behaviour of our existing untyped properties (or at
least, that's beyond the scope of this RFC), but we could choose the
behaviour we find more useful for our typed properties.
We already have the differentiation between IS_NULL and IS_UNDEF, why
not expose the latter to userland? I mean, JavaScript has it too and
people are able to understand it.
class A {
public int $x;
public ?int $y = null;
public int $z = 42;
}
$a = new A;
var_dump($a->x); // undefined
var_dump($a->y); // null
var_dump($a->z); // 42
unset($a->z);
var_dump($a->z); // undefined + error
At least to me this makes sense and there would be no problem with
unset() anymore. Although I truly question the usefulness of its
functionality. Can anyone come up with a real world use case for unset()?
Or maybe not use /undefined/ but /unset/ as a term because it is already
baked in? (Well the constant IS_UNDEF should be renamed to IS_UNSET to
stay consistent in all layers.)
class A {
public int $x;
public ?int $y = null;
public int $z = 42;
}
$a = new A;
var_dump($a->x); // unset
var_dump($a->y); // null
var_dump($a->z); // 42
// NOT SURE IF THIS SHOULD BE POSSIBLE!!!!
$a->z = (unset) $a->z; // was null (PHP<7.1) would become unset
var_dump($a->z); // unset + error
$a->z = unset;
var_dump($a->z); // unset + error
unset($a->z);
var_dump($a->z); // unset + error
Of course this would also requires the introduction of an unset (and
UNSET) constant in userland.
class A {
private $x;
public function getX() {
if ($x === unset) {
$this->x = 42;
}
return $this->x;
}
}
I love the difference to null, this makes the code much more expressive.
There would be the following rules:
- Access always results in error.
- Usage as argument results in error.
- Usage as return results in error (could be void but BC).
- ... more errors ...
- Comparison is possible!
- The following existing operations would need to be changed to make use
of unset instead of null (possible BC):- unset()
- (unset) cast
- The following new operations would need to be introduced:
- is_unset()
- The following existing operations would need to be extended:
-
gettype()
-
settype()
-
--
Richard "Fleshgrinder" Fussenegger
Following "Type safety is the goal of this RFC, not validating objects.", it would be better to do implicit casting for uninitialized properties (whenever implicit casting is possible) or use null for nullable types:
class A {
public int $x;
public ?int $y = null;
public int $z = 42;
public ?int $u;
public ?datetime $v;
public datetime $w;
}
$a = new A;
var_dump($a->x); // 0 + notice
var_dump($a->y); // null
var_dump($a->z); // 42
unset($a->z);
var_dump($a->z); // 0 + notice
var_dump($a->u); // null + notice
var_dump($a->v); // null + notice
var_dump($a->w); // Fatal error, uninitialized...
Regards
Thomas
Fleshgrinder wrote on 25.05.2016 23:03:
PHP's existing untyped properties are implicitly initialised to null,
and so yes, we would essentially only be copying our existing behaviour.However, I think it is worth asking whether our existing behaviour is
useful before we preserve it here. From my perspective, it is unhelpful
that PHP does not warn you about using properties you haven't
initialised, and this applies to both typed and untyped properties. In
some cases (like in my linked list example in a previous email), null
might be a meaningful value and worth distinguishing from a property not
having being initialised yet.We can't change the behaviour of our existing untyped properties (or at
least, that's beyond the scope of this RFC), but we could choose the
behaviour we find more useful for our typed properties.We already have the differentiation between IS_NULL and IS_UNDEF, why
not expose the latter to userland? I mean, JavaScript has it too and
people are able to understand it.class A {
public int $x;
public ?int $y = null;
public int $z = 42;
}
$a = new A;
var_dump($a->x); // undefined
var_dump($a->y); // null
var_dump($a->z); // 42
unset($a->z);
var_dump($a->z); // undefined + errorAt least to me this makes sense and there would be no problem with
unset() anymore. Although I truly question the usefulness of its
functionality. Can anyone come up with a real world use case for unset()?Or maybe not use /undefined/ but /unset/ as a term because it is already
baked in? (Well the constant IS_UNDEF should be renamed to IS_UNSET to
stay consistent in all layers.)class A {
public int $x;
public ?int $y = null;
public int $z = 42;
}
$a = new A;
var_dump($a->x); // unset
var_dump($a->y); // null
var_dump($a->z); // 42// NOT SURE IF THIS SHOULD BE POSSIBLE!!!!
$a->z = (unset) $a->z; // was null (PHP<7.1) would become unset
var_dump($a->z); // unset + error$a->z = unset;
var_dump($a->z); // unset + errorunset($a->z);
var_dump($a->z); // unset + errorOf course this would also requires the introduction of an unset (and
UNSET) constant in userland.class A {
private $x;
public function getX() {
if ($x === unset) {
$this->x = 42;
}
return $this->x;
}}
I love the difference to null, this makes the code much more expressive.
There would be the following rules:
- Access always results in error.
- Usage as argument results in error.
- Usage as return results in error (could be void but BC).
- ... more errors ...
- Comparison is possible!
- The following existing operations would need to be changed to make use
of unset instead of null (possible BC):- unset()
- (unset) cast
- The following new operations would need to be introduced:
- is_unset()
- The following existing operations would need to be extended:
gettype()
settype()
--
Richard "Fleshgrinder" Fussenegger
Following "Type safety is the goal of this RFC, not validating objects.", it would be better to do implicit casting for uninitialized properties (whenever implicit casting is possible) or use null for nullable types:
class A {
public int $x;
public ?int $y = null;
public int $z = 42;
public ?int $u;
public ?datetime $v;
public datetime $w;
}$a = new A;
var_dump($a->x); // 0 + notice
var_dump($a->y); // null
var_dump($a->z); // 42
unset($a->z);
var_dump($a->z); // 0 + notice
var_dump($a->u); // null + notice
var_dump($a->v); // null + notice
var_dump($a->w); // Fatal error, uninitialized...
This was proposed many times but it renders checks whether something was
initialized or not completely useless and is not really a solution to
the problem at hand.
--
Richard "Fleshgrinder" Fussenegger
Hi!
var_dump($a->w); // Fatal error, uninitialized...
This means every read access to a property should be checked for it
being typed, and every access to a typed property should be checked for
it being initialized. I'm concerned there might be a performance hit for
this.
Also, this means no access for a property - even defined one - is safe,
and if you want to avoid fatal errors, you need to check every access,
at least if you suspect typed properties may be involved. And, of
course, there's no function in the RFC to actually check it.
Stas Malyshev
smalyshev@gmail.com
Am 25.05.2016 um 23:56 schrieb Stanislav Malyshev smalyshev@gmail.com:
Hi!
var_dump($a->w); // Fatal error, uninitialized...
This means every read access to a property should be checked for it
being typed, and every access to a typed property should be checked for
it being initialized. I'm concerned there might be a performance hit for
this.Also, this means no access for a property - even defined one - is safe,
and if you want to avoid fatal errors, you need to check every access,
at least if you suspect typed properties may be involved. And, of
course, there's no function in the RFC to actually check it.Stas Malyshev
smalyshev@gmail.com
Hey Stas,
this is pretty much a non-issue (perf-wise) as we anyway need to check against IS_UNDEF to emit a notice and return null, even with normal properties.
Also, property access never was safe. Consider:
$obj = new class {
public $foo;
function __construct() {
unset($this->foo);
}
function __get($prop) {
throw new Exception("No $prop for you today!");
}
};
var_dump($obj->foo); // exception.
isset() checks will continue to work. It's just about getting a value. (and to check whether it's a typed property, there's Reflection support in the RFC.)
This definitely is no problem.
Bob
Hi!
Also, property access never was safe. Consider:
$obj = new class {
public $foo;
function __construct() {
unset($this->foo);
}
function __get($prop) {
throw new Exception("No $prop for you today!");
}
};
var_dump($obj->foo); // exception.
This is different. Your code throws exception purposefully so you intend
something to break here - you might as well just written exit(1) and
said there's no safe code at all since you could exit at any moment.
That's not what I mean. I mean that operation that was previously not
prone to fatal errors just because of variable holding some value would
now produce such errors - not because the user wrote code to
specifically do that but because of hidden properties of the engine. If
the engine would by itself insert such code as above into user classes
that would be dangerous too but of course it does not.
isset() checks will continue to work.
For some definition of "work" - since it would return false for null
values, but null values are actually OK.
It's just about getting a value. (and to check whether it's a typed property, there's Reflection support in the RFC.)
You don't propose using Reflection before each variable access I
presume. Reflection is useless in runtime scenario.
--
Stas Malyshev
smalyshev@gmail.com
2016-05-26 7:00 GMT+02:00 Stanislav Malyshev smalyshev@gmail.com:
Hi!
Also, property access never was safe. Consider:
$obj = new class {
public $foo;
function __construct() {
unset($this->foo);
}
function __get($prop) {
throw new Exception("No $prop for you today!");
}
};
var_dump($obj->foo); // exception.This is different. Your code throws exception purposefully so you intend
something to break here - you might as well just written exit(1) and
said there's no safe code at all since you could exit at any moment.
That's not what I mean. I mean that operation that was previously not
prone to fatal errors just because of variable holding some value would
now produce such errors - not because the user wrote code to
specifically do that but because of hidden properties of the engine. If
the engine would by itself insert such code as above into user classes
that would be dangerous too but of course it does not.isset() checks will continue to work.
For some definition of "work" - since it would return false for null
values, but null values are actually OK.
If there's a function to check it, how would you handle it? It's clearly a
programming mistake.
It's just about getting a value. (and to check whether it's a typed
property, there's Reflection support in the RFC.)You don't propose using Reflection before each variable access I
presume. Reflection is useless in runtime scenario.--
Stas Malyshev
smalyshev@gmail.com
Hi!
We already have the differentiation between IS_NULL and IS_UNDEF, why
not expose the latter to userland? I mean, JavaScript has it too and
people are able to understand it.
IS_UNDEF is not a PHP type, it is an engine implementation flag. Now,
adding a new type "undefined" would be a pretty big thing and then you'd
need to deal with all the implications of it. Including a huge BC break
of changing the type of all uninitialized variables, and the question of
"what if I want my parameter to be able to accept undefined values" and
so on. Huge can of worms, and all of it again just to have a type that
is exactly like null but not null. While the only reason null exists is
to do exactly what "undefined" is proposed to do.
--
Stas Malyshev
smalyshev@gmail.com
Hi!
We already have the differentiation between IS_NULL and IS_UNDEF, why
not expose the latter to userland? I mean, JavaScript has it too and
people are able to understand it.IS_UNDEF is not a PHP type, it is an engine implementation flag. Now,
adding a new type "undefined" would be a pretty big thing and then you'd
need to deal with all the implications of it. Including a huge BC break
of changing the type of all uninitialized variables, and the question of
"what if I want my parameter to be able to accept undefined values" and
so on. Huge can of worms, and all of it again just to have a type that
is exactly like null but not null. While the only reason null exists is
to do exactly what "undefined" is proposed to do.
Andrea already said that we would not use it for untyped properties,
hence, no BC.
It is not the same as null, very similar, but definitely not the same.
Think of it in DB terms:
| table |
| ----- |
| id |
SELECT name FROM table;
That's not null, it's not defined (undefined, unset, ...). In other
words, null is a value and undefined/unset a state.
Whether this proposal should become part of this RFC or not is something
that needs to be discussed.
--
Richard "Fleshgrinder" Fussenegger
It is not the same as null, very similar, but definitely not the same.
Think of it in DB terms:| table |
| ----- |
| id |SELECT name FROM table;
That's not null, it's not defined (undefined, unset, ...). In other
words, null is a value and undefined/unset a state.
If no field 'name' exists then you get an error. If no valid record is
found then name will be populated with 'NULL' if you try and read the
returned record ... unless the 'noofrec' variable is accessed first and
establishes that '0' records were returned.
If you are reading a set of fields for which some have no matching
values then these are returned as 'NULL' while the rest will be
populated. NULL
is ALWAYS a 'state' meaning that this field is undefined
or more accurately unset.
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
Hi!
Andrea already said that we would not use it for untyped properties,
hence, no BC.
Again, it's not that simple. Properties are not local. That means any
code that can deal with a class that may have typed properties (which
may be library class, for example, so you don't even know what it has
inside) has to deal with the possibility of it being of the new type. So
if the old code uses is_null($object->foo) as means to check if the
value wasn't initialized, and it's no longer null, then that code is
broken and needs to be rewritten. That's a BC break. Yes, it will never
happen if you never use typed properties, and never use any libraries
that might use typed properties, but then what's the point of the whole
thing? The point of BC is that if you don't use new features, you don't
have to change your code and it will keep working. With the proposed
solution, it won't be the case.
It is not the same as null, very similar, but definitely not the same.
Think of it in DB terms:| table |
| ----- |
| id |SELECT name FROM table;
That's not null, it's not defined (undefined, unset, ...). In other
words, null is a value and undefined/unset a state.
"name" is not a value, as in if you do that in SQL, you don't get a
value, you get an error. Same as if you wrote "please can I haz a
pony?". It's just something the SQL can not give you, so it produces an
error. What is proposed here, however, is a PHP type, not an error.
That's a different thing - if you have a variable, then you have to have
a value, and if you have a value, then you have to have a type.
Stas Malyshev
smalyshev@gmail.com
Hi!
Andrea already said that we would not use it for untyped properties,
hence, no BC.Again, it's not that simple. Properties are not local. That means any
code that can deal with a class that may have typed properties (which
may be library class, for example, so you don't even know what it has
inside) has to deal with the possibility of it being of the new type. So
if the old code uses is_null($object->foo) as means to check if the
value wasn't initialized, and it's no longer null, then that code is
broken and needs to be rewritten. That's a BC break. Yes, it will never
happen if you never use typed properties, and never use any libraries
that might use typed properties, but then what's the point of the whole
thing? The point of BC is that if you don't use new features, you don't
have to change your code and it will keep working. With the proposed
solution, it won't be the case.It is not the same as null, very similar, but definitely not the same.
Think of it in DB terms:| table |
| ----- |
| id |SELECT name FROM table;
That's not null, it's not defined (undefined, unset, ...). In other
words, null is a value and undefined/unset a state."name" is not a value, as in if you do that in SQL, you don't get a
value, you get an error. Same as if you wrote "please can I haz a
pony?". It's just something the SQL can not give you, so it produces an
error. What is proposed here, however, is a PHP type, not an error.
That's a different thing - if you have a variable, then you have to have
a value, and if you have a value, then you have to have a type.
I understand where you are getting at. Another proposal after giving
this some more thought.
var_dump($a); // null + E_NOTICE
Undefined
var_dump(isset($a)); // false
var_dump(is_null($a)); // true + E_NOTICE
Undefined
var_dump($a == null); // true + E_NOTICE
Undefined
var_dump($a === null); // true + E_NOTICE
Undefined
$a = ['x' => null];
var_dump($a['x']); // null
var_dump(isset($a['x']); // false
var_dump(array_key_exists($a['x'])); // true
var_dump(is_null($a['x']); // true
var_dump($a['x'] == null); // true
var_dump($a['x'] === null); // true
$b = (object) [];
var_dump($b->x); // null + E_NOTICE
Undefined
var_dump(isset($b->x)); // false
var_dump(property_exists($b, 'x')); // false
var_dump(is_null($b->x)); // true + E_NOTICE
Undefined
var_dump($b->x == null); // true + E_NOTICE
Undefined
var_dump($b->x === null); // true + E_NOTICE
Undefined
$c = new class { public int $x; };
var_dump($c->x); // null + E_NOTICE
Uninitialized
var_dump(isset($c->x)); // false
var_dump(property_exists($c, 'x')); // true
var_dump(is_null($c->x)); // true + E_NOTICE
Uninitialized
var_dump($c->x == null); // true + E_NOTICE
Uninitialized
var_dump($c->x === null); // true + E_NOTICE
Uninitialized
$d = new class { public ?int $x; };
var_dump($d->x); // null + E_NOTICE
Uninitialized
var_dump(isset($d->x)); // false
var_dump(property_exists($d, 'x')); // true
var_dump(is_null($d->x)); // true + E_NOTICE
Uninitialized
var_dump($d->x == null); // true + E_NOTICE
Uninitialized
var_dump($d->x === null); // true + E_NOTICE
Uninitialized
$e = new class { public ?int $x = null; };
var_dump($e->x); // null
var_dump(isset($e->x)); // false
var_dump(property_exists($e, 'x')); // true
var_dump(is_null($e->x)); // true
var_dump($e->x == null); // true
var_dump($e->x === null); // true
/* {{{ PHP 7.1 */
$f = new class { public $x; };
var_dump($f->x); // null
var_dump(isset($f->x)); // true + E_STRICT
Uninitialized
var_dump(property_exists($f, 'x')); // true
var_dump(is_null($f->x)); // true
var_dump($f->x == null); // true
var_dump($f->x === null); // true
/* }}} */
/* {{{ PHP 8 */
$g = new class { public $x; };
var_dump($g->x); // null + E_NOTICE
Uninitialized
var_dump(isset($g->x)); // false
var_dump(property_exists($g, 'x')); // true
var_dump(is_null($g->x)); // true + E_NOTICE
Uninitialized
var_dump($g->x == null); // true + E_NOTICE
Uninitialized
var_dump($g->x === null); // true + E_NOTICE
Uninitialized
/* }}} */
The only thing I personally dislike is the fact that there is no
counterpart to isset(). This means that one cannot create a positive
conditional that checks for the opposite case without raising an E_NOTICE.
class T {
private int $x;
public function getX() {
if (isset($this-x) === false) {
$this->x = 42;
}
return $this->x;
}
}
However, one could argue that empty() is good enough at this point --
despite the fact that many values are considered empty that might be
valid values in other circumstances -- because we want to know the
uninitialized case here. From the manual:
The following things are considered to be empty: [...] a variable
declared, but without a value
class T {
private int $x;
public function getX() {
if (empty($this->x)) {
$this->x = 42;
}
return $this->x;
}
}
I could live with that.
Note that the behavior of isset() and empty() was already once changed
during the 5.4 feature release! I am proposing to change it with a major
version for existing code and only emitting an E_STRICT
till then. This
is not even close as brutal as that behavioral change back then but
other than that pretty much the same change. This time it just affects
objects and not associative arrays.
--
Richard "Fleshgrinder" Fussenegger
I understand where you are getting at. Another proposal after giving
this some more thought.
Could you summarise what your proposal actually is; I got a bit lost
with what your long list of examples was trying to show me.
Note that the behavior of isset() and empty() was already once changed
during the 5.4 feature release!
Can you provide a reference for that? The only thing mentioned in the
changelog in the manual is this rather rare situation:
$foo = 'a string';
isset($foo['some_key']);
$foo['some_key'] doesn't actually have much of a meaning in that case,
anyway, and it has nothing to do with initialisation.
Regards,
Rowan Collins
[IMSoP]
Could you summarise what your proposal actually is; I got a bit lost
with what your long list of examples was trying to show me.
To summarize it: we should change the behavior of isset() to work
exactly the same way as it does for associative array keys if they have
null assigned to them.
Shorter example of current PHP implementation:
$a = ['x' => null];
var_dump(isset($a['x'])); // false
var_dump(array_key_exists($a, 'x')); // true
$o = (object) ['x' => null];
var_dump(isset($a->x)); // true
var_dump(property_exists($a, 'x')); // true
PHP 8
$o = (object) ['x' => null];
var_dump(isset($a->x)); // false
var_dump(property_exists($a, 'x')); // true
This would actually be more consistent with the isset() behavior
together with associative arrays and it would allow us to handle typed
properties that where not initialized (as illustrated in the longer
example).
Can you provide a reference for that? The only thing mentioned in the
changelog in the manual is this rather rare situation:$foo = 'a string';
isset($foo['some_key']);$foo['some_key'] doesn't actually have much of a meaning in that case,
anyway, and it has nothing to do with initialisation.
Just tested it with those ancient versions and you are right that I
interpreted that sentence incorrectly. The behavior of isset() with
array keys that were explicitly set to null never changed.
However, this does not change my proposal. :)
--
Richard "Fleshgrinder" Fussenegger
$o = (object) ['x' => null];
var_dump(isset($a->x)); // false
var_dump(property_exists($a, 'x')); // true
Apart from a typo in your example (you change from $o to $a), this is
already the current behaviour, and always has been: https://3v4l.org/NeqGl
isset() is really very simple: if the thing your accessing would give
you the value null, it returns false, otherwise it returns true.
Regards,
Rowan Collins
[IMSoP]
$o = (object) ['x' => null];
var_dump(isset($a->x)); // false
var_dump(property_exists($a, 'x')); // trueApart from a typo in your example (you change from $o to $a), this is
already the current behaviour, and always has been: https://3v4l.org/NeqGlisset() is really very simple: if the thing your accessing would give
you the value null, it returns false, otherwise it returns true.Regards,
Now I feel stupid but I guess I got lost myself. :P
This means it is even simpler, we just have to add the E_NOTICE
and be
done with it.
$g = new class { public $x; };
var_dump($g->x); // null + E_NOTICE
Uninitialized
var_dump(isset($g->x)); // false
var_dump(property_exists($g, 'x')); // true
var_dump(is_null($g->x)); // true + E_NOTICE
Uninitialized
var_dump($g->x == null); // true + E_NOTICE
Uninitialized
var_dump($g->x === null); // true + E_NOTICE
Uninitialized
This behavior would be true for all variations:
class A {
var $x;
public $x;
public int $x;
public ?int $x;
}
No notice for the following:
class A {
var $x = null;
public $x = null;
public int $x = 0;
public ?int $x = null;
}
--
Richard "Fleshgrinder" Fussenegger
Bare with me ... just trying to fill in a few of the gaps in the current
documentation.
$g = new class { public $x; };
var_dump(isset($g->x)); // false
isset manual entry does not say what happens if $g->x does not exist but
the false here could equally be 'does not exist' if unset has been
called somewhere?
var_dump(property_exists($g, 'x')); // true
or array_key_exists('x', $g) in our consistent style but as has been
pointed out we do not have a simple 'exists' ...
$g->exists('x') ?
along with $g->isinit('x')
var_dump($g->x); // null +
E_NOTICE
Uninitialized
var_dump(is_null($g->x)); // true +E_NOTICE
Uninitialized
var_dump($g->x == null); // true +E_NOTICE
Uninitialized
var_dump($g->x === null); // true +E_NOTICE
Uninitialized
Unless null IS the required initial value? Why should we have to
initialize a nullable typed property explicitly?
I'm still stuck in the simple model of things where 'x' is expandable so
we have the simple generic variable of old (PHP4 days) which now has
additional attributes such as accessibility (public etc) and a few
special cases of type filtering but is lacking a tidy way of adding the
more useful filtering attributes such as constraints and yes typing.
properties and associative arrays are simply managed list of these
simple variables so why do we need different functions to access them.
Within a class isset($x) should mirror isset($this->x) and exists($x)
makes sense along with other 'object' related functions, but is there no
way to get back to a lot simpler consistent handling of variables ...
and a more constructive way to add flexible type constraints.
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
var_dump(property_exists($g, 'x')); // true
or array_key_exists('x', $g) in our consistent style but as has been
pointed out we do not have a simple 'exists' ...
$g->exists('x') ?
along with $g->isinit('x')
I like the exists() idea. :) But we might not need it.
var_dump($g->x); // null +
E_NOTICE
Uninitialized
var_dump(is_null($g->x)); // true +E_NOTICE
Uninitialized
var_dump($g->x == null); // true +E_NOTICE
Uninitialized
var_dump($g->x === null); // true +E_NOTICE
UninitializedUnless null IS the required initial value? Why should we have to
initialize a nullable typed property explicitly?
You don't have to unless null is the required initial value.
You are only punished with an E_NOTICE
if you try to access a property
that was never initialized with anything. This would be 100% consistent
with old PHP behavior.
$x;
var_dump($x); // null + E_NOTICE
Undefined
$y = null;
var_dump($y); // null
class O {
public $x;
public $y = null;
}
$o = new O;
var_dump($o->x); // null + E_NOTICE
Undefined / Uninitialized
var_dump($o->y); // null
Only the E_NOTICE
for $o->x would be new.
I'm still stuck in the simple model of things where 'x' is expandable so
we have the simple generic variable of old (PHP4 days) which now has
additional attributes such as accessibility (public etc) and a few
special cases of type filtering but is lacking a tidy way of adding the
more useful filtering attributes such as constraints and yes typing.properties and associative arrays are simply managed list of these
simple variables so why do we need different functions to access them.
Within a class isset($x) should mirror isset($this->x) and exists($x)
makes sense along with other 'object' related functions, but is there no
way to get back to a lot simpler consistent handling of variables ...
and a more constructive way to add flexible type constraints.
With this proposal we would not go anywhere else. We would make it more
consistent and allow the typed properties RFC to continue. Unless I
missed something in the discussion or got something wrong again. Please
correct me!
--
Richard "Fleshgrinder" Fussenegger
$o = (object) ['x' => null];
var_dump(isset($a->x)); // false
var_dump(property_exists($a, 'x')); // trueApart from a typo in your example (you change from $o to $a), this is
already the current behaviour, and always has been: https://3v4l.org/NeqGlisset() is really very simple: if the thing your accessing would give
you the value null, it returns false, otherwise it returns true.Regards,
Now I feel stupid but I guess I got lost myself. :P
Heh, no worries, easily done. :)
This means it is even simpler, we just have to add the
E_NOTICE
and be
done with it.$g = new class { public $x; };
var_dump($g->x); // null +
E_NOTICE
Uninitialized
var_dump(isset($g->x)); // false
var_dump(property_exists($g, 'x')); // true
var_dump(is_null($g->x)); // true +E_NOTICE
Uninitialized
var_dump($g->x == null); // true +E_NOTICE
Uninitialized
var_dump($g->x === null); // true +E_NOTICE
UninitializedThis behavior would be true for all variations:
class A {
var $x; public $x; public int $x; public ?int $x;
}
No notice for the following:
class A {
var $x = null; public $x = null; public int $x = 0; public ?int $x = null;
}
I am definitely in favour of this from a language point of view. The
notice is warning about initialization, not declaration, so it makes
sense to warn on "var $foo" and not "var $foo = null".
The only thing I'm not sure is what the impact would have on the
internals, which may be why it doesn't already work that way. With a
simple variable the notice can be easily raised based on the variable
name not being in the current symbol table; with an object property, the
name is in the relevant table, because it's been declared even
though it hasn't been initialized. Thus you need some extra flag to
track that a declared property exists but has never been written to.
But it sounds like typed properties require adding some such overhead
anyway...
Regards,
Rowan Collins
[IMSoP]
I am definitely in favour of this from a language point of view. The
notice is warning about initialization, not declaration, so it makes
sense to warn on "var $foo" and not "var $foo = null".The only thing I'm not sure is what the impact would have on the
internals, which may be why it doesn't already work that way. With a
simple variable the notice can be easily raised based on the variable
name not being in the current symbol table; with an object property, the
name is in the relevant table, because it's been declared even
though it hasn't been initialized. Thus you need some extra flag to
track that a declared property exists but has never been written to.But it sounds like typed properties require adding some such overhead
anyway...Regards,
Looking at zend_object_handlers.c
and zend_std_read_property
there
is the line:
retval = &EG(uninitialized_zval);
This is what gives us the default null of our properties if I interpret
everything correctly. This is also the place where the undefined
property error comes from.
We need help here from people who know the PHP source better.
--
Richard "Fleshgrinder" Fussenegger
Hi!
Andrea already said that we would not use it for untyped properties,
hence, no BC.
Again, it's not that simple. Properties are not local. That means any
code that can deal with a class that may have typed properties (which
may be library class, for example, so you don't even know what it has
inside) has to deal with the possibility of it being of the new type. So
if the old code uses is_null($object->foo) as means to check if the
value wasn't initialized, and it's no longer null, then that code is
broken and needs to be rewritten. That's a BC break. Yes, it will never
happen if you never use typed properties, and never use any libraries
that might use typed properties, but then what's the point of the whole
thing? The point of BC is that if you don't use new features, you don't
have to change your code and it will keep working. With the proposed
solution, it won't be the case.
If you want, you can easily write a backwards-compatible new class that
uses declared type properties with
public int $property = null;
I don't think loss of the (as yet hypothetical) lazy shortcut to write
the same thing:
public int $property;
is BC break.
Tom
We already have the differentiation between IS_NULL and IS_UNDEF, why
not expose the latter to userland?
Is this not simply a mistake?
The whole reason for null in my book is that it IS 'undefined'. We have
to have a flag for it since you can't easily identify it as a 'value'
stored im the variable. I think I can see why some people would want to
know if a variable has not been initialised, but null still fits that
requirement. When any variable is created it IS_NULL until such time as
a value is assigned - and a type of value established. In my book an
assignment will check for more than IS_INT so using typed variables is
of little advantage. But if I test for a value and find null then I know
it has not yet been initialised.
IS_UNDEF can't exist if there is no named variable to attach it to, so
user land gets an error that the variable does not exist.
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
We already have the differentiation between IS_NULL and IS_UNDEF, why
not expose the latter to userland?
I wondered if the conversation would go in this direction. This has been
discussed to death, and in my opinion all the reasons given in previous
discussions why isset() is not broken, and we do not need a new magic
value / type, are just as valid in the case of object properties as
anywhere else.
I can see an advantage to this raising some kind of warning:
class A { ?int $foo }
$a = new A;
var_dump($a->foo); // not initialized yet!
But it should absolutely not be possible to detect the difference
between that and this:
class A { ?int $foo }
$a = new A;
$->foo = null;
var_dump($a->foo); // null
Because that is exactly the same as this:
var_dump($foo); // not initialized yet!
vs this:
$foo = null;
var_dump($foo);
The warning or error on unitialized variables or properties is an
assertion - code should be written such that it simply can't happen.
If you're unsure if something's set, you can always do this:
if ( ! isset($this->foo) ) { $this->foo = null; }
If it's already an explicit null, you perform one unnecessary operation;
if it's never been initialized, it has now.
Regards,
Rowan Collins
[IMSoP]
Have a look at my latest message:
http://marc.info/?l=php-internals&m=146424924029857&w=2
--
Richard "Fleshgrinder" Fussenegger
Morning Dmitry,
I made this check(s) to be invariant. You may like to do this
differently...I think this is what everyone expects, isn't it ?
I did omit to mention that part ...
RFC doesn't define how uninitialized nullable typed properties should
behave.It does:
Nullable typed properties will not raise an exception when accessed
before initialization.I don't agree with this choice, for three reasons:
a) This unnecessarily restricts what can be expressed in the type system.
With these semantics it will no longer be possible to express that a
property should be nullable, but have no default value. This situation is
not uncommon in practice, in particular anytime you have a nullable
constructor argument, you will want the corresponding property to be
nullable without a default, to ensure that it is explicitly initialized.b) This directly contradicts the meaning of ?Type for parameters. For
parameters ?Type means that it's a nullable parameter without a default
value. That's the very thing that distinguishes it from the Type $prop =
null syntax. And now ?Type for properties should mean the exact opposite?c) If you view this in a larger scope of union types, this special case
becomes even more weird. Why does the particular union Type|null get
special treatment, while all other unions don't? Or is it actually not
specific to "null", but to single value types? E.g. if we also allowed
Type|false, would that also receive an implicit false default value? What
about the type null|false? Does that get an implicit default, and if so,
which? I realize this is not quite in scope for type properties, but the
further evolution of the type system should be kept in mind.Please keep things consistent: If there is not default, there is no default.
Object properties being in a uninitialized state is unfamiliar in
current PHP practice. We are accustomed to not worrying about an
"uninitialized error" when we read a property. We are assured to get
either null or whatever was last written to the property.
I suspect this unfamiliarity lies behind some people's preference for an
implicit initial null value of a nullable typed property.
But I'm inclined to agree with Nikita that the following should be
different:
public ?Client $mark;
public ?Client $mark = null;
... and that the difference should be coherent with that between:
function con(?Client $mark) {}
function con(?Client $mark = null) {}
... which is that you must give $mark value in the first and you don't
need to in the second because it has an explicit default. We are
more-or-less accustomed already to the difference between:
function con(Client $mark) {}
function con(Client $mark = null) {}
... so I think your consistency argument is good.
Moreover, the "good old" implicit initial null for untyped properties
(i.e. that public $foo;
means public $foo = null;
) is just a lazy
shortcut that I wouldn't defend except for BC, which isn't an issue here.
Tom