Nikita Popov wrote:
On Wed, May 25, 2016 at 10:30 AM, Joe Watkins wrote:
*Nullable typed properties will not raise an exception when accessed
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:
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
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.