Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:102858 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 12414 invoked from network); 16 Jul 2018 16:20:20 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 16 Jul 2018 16:20:20 -0000 Authentication-Results: pb1.pair.com smtp.mail=nikita.ppv@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=nikita.ppv@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.223.173 as permitted sender) X-PHP-List-Original-Sender: nikita.ppv@gmail.com X-Host-Fingerprint: 209.85.223.173 mail-io0-f173.google.com Received: from [209.85.223.173] ([209.85.223.173:38322] helo=mail-io0-f173.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 7B/9E-39793-2C5CC4B5 for ; Mon, 16 Jul 2018 12:20:18 -0400 Received: by mail-io0-f173.google.com with SMTP id v26-v6so38348352iog.5 for ; Mon, 16 Jul 2018 09:20:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=7WxOd36vpzKWlsum+XhIM7xiuWQTk6tQj0vhF1e2jxg=; b=RxAI9+f/f11v5VgHpzFRz4nfX6nb07Iw3lTGKiwZoEyENIJW6NK4Ww647CaWJ3oGEs U5KeOjwgzc5vxa1MoJjoUbtBjP1LfY/3wjwflvOZZtOgjeVx1Ok7Z1ypXTc7n4PrAagZ mgcCWOHs7bXtRwuCaFQN3W/yldsoXOw7nGs/E4sOKWvZdnBOvQjQf58wLdMBixcYadIY y5fX9T5itPA5PkRUfLwX3UIloIWw31ujbCgXlmCxFaSVpU9FX3BQ1tQ4F/L1x17hMbA9 MC2A2v1Gc0HVoUNy8PZ2HArYF4iwD/+TTm8YmFf9dqSv/CXvaj3PVFMORc/hXUEbt2Q5 6yzQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=7WxOd36vpzKWlsum+XhIM7xiuWQTk6tQj0vhF1e2jxg=; b=X3Han0jnMtW7ueyLwVoHWsSClZMWnh70mJ8c2w5t2jhJYct6Ixlr8lxci27oKghDPb uVGGvCubpXi34lPgQXTggkYbpv6YF/pCv6m5K+FVCUW5wcfvxjrjYphZmld92rwJjZx2 LW1v8pXuOUO/A0s58+qbYYZ9cNWm+f+4KotkHxZmeVkqZ2qhjBK/txfo/lVZCD9NwAZI qhBbIr02sleydsYx5XHVgvCQXdHq0n8Ol1802Y3PBH7A7S+7lhJaTwcI+uEzyutWm1WQ +p+0u8gILh37EZskC+VUOr/zpYeAaKwumK166d8ObZ7JXgC02HSrAS0At0xR//MOGVGw y9jA== X-Gm-Message-State: AOUpUlEOSNWNcEIAPCI4JLWsJ+Yw3ry1rI3tC28ZAiSxXAN4jgp0g0Kt JRwO1lAuq0H/AfpPFVJCDKG6kaax7xFFcl13hz0= X-Google-Smtp-Source: AAOMgpdicXKTcJx3TWZZxcUjSi7COks94b90Vzg2xPxV3Fd0PEKL3E6sJBMTwVTD2H8AULVrehKgA7cPq/EM4L2mBJU= X-Received: by 2002:a6b:254e:: with SMTP id l75-v6mr14574609iol.47.1531758015907; Mon, 16 Jul 2018 09:20:15 -0700 (PDT) MIME-Version: 1.0 Received: by 2002:a6b:148a:0:0:0:0:0 with HTTP; Mon, 16 Jul 2018 09:20:15 -0700 (PDT) In-Reply-To: <8916EC21-D368-40F8-9ABD-CE0C04A73539@gmail.com> References: <8916EC21-D368-40F8-9ABD-CE0C04A73539@gmail.com> Date: Mon, 16 Jul 2018 18:20:15 +0200 Message-ID: To: Rowan Collins Cc: PHP internals Content-Type: multipart/alternative; boundary="0000000000006bafd70571203400" Subject: Re: [PHP-DEV] Non-nullable properties From: nikita.ppv@gmail.com (Nikita Popov) --0000000000006bafd70571203400 Content-Type: text/plain; charset="UTF-8" On Sat, Jul 14, 2018 at 3:09 PM, Rowan Collins wrote: > Hi all, > > As briefly mentioned, I think the approach to non-nullable types in the > typed properties proposal needs more discussion, to make sure we're not > repeating Tony Hoare's "billion-dollar mistake". > > For parameter hints, nullability is naturally optional, particularly in > PHP where "nullable Foo" is equivalent to a union type "null or Foo". For > properties, this isn't the case, because every property must have some > initial state. > > The simplest solution, which I think would be a sensible starting point if > we're not ready for more complex changes, is to say that all typed > properties must have a default value, and if that default value is null, > the type hint must naturally be nullable. In other words, make "public Foo > $foo" illegal, but allow "public ?Foo $foo=null". > > The current RFC proposes the next simplest solution, which is to allow > non-nullable types, and trust the user to initialise them before use. > > My first objection to this is that it creates an entirely new state for > object properties to be in, which behaves differently from everything else > in the language. There will then be three or four different ways for an > object property to be "unset": > > - not declared at all; access gives a notice and the implicit value null > - declared with no default, uninitialised, implicitly null > - declared with a default of null, or explicitly assigned as null > - declared with a non-nullable type, never initialised; rather than an > implicit null, access generates an Error > > The bigger problem is that the properties are non-nullable in name only, > and the declaration can't be trusted. Consider the following class: > > class Validity { > public \DateTimeInterface $validFrom; > public ?\DateTimeInterface $validTo = null; > } > > If I have an instance $v of that class, I would expect to be able to > safely call $v->validFrom->getTimestamp(), but need to check for nulls > before doing the same with validTo. Under the current proposal, doing so > will risk errors, so I will have to check both properties before access > anyway. Worse, using is_null() or ?: will attempt to retrieve the value, so > I actually have to be *more* careful, and use isset() or ?? instead. > I'm just going to reply to this one line, because this is the root of your misunderstanding: The user should never, ever, under any circumstances (*) check for the initialization of a typed property. The user simply uses the property under the firm knowledge that it will be initialized -- or there is a bug in the initialization code. If there is a bug in the initialization code then it needs to be fixed there, not by introducing a check when working with the object. This is very, very different from a nullable property, where it is the users responsibility to handle the null value. If the user receives a null value it does *not* indicate an initialization bug and they *must* write code to account for it. Please do also remember that uninitialized properties and unset properties are the same thing, and during the last proposal there was a strong consensus that we must retain support for property unsetting to be compatible with Doctrine and other libraries using proxy objects. Nikita (*) Okay, there are exceptions, e.g. introspection libraries ;) > > Alternatively, I can trust the author of the class, but at that point they > might as well just use a docblock - the type hint documents their intent, > but is not enforced. > > > Swift is often cited as a language which gets nullability right, and a lot > of attention is given to Options, and the compiler ensuring that the None / > null case is handled; but at least as important is how it handles > initialisation of non-nullable properties, using "two-phase > initialisation": https://docs.swift.org/swift-b > ook/LanguageGuide/Initialization.html > > In short, Swift defines a specific point after which all properties must > have a valid value; before this point, the entire object is invalid for > read operations, so there is no need for a specific error when accessing > uninitialised properties. > > Swift marks this point by the call to the parent initialiser, ultimately > going up the chain to the root object. PHP has no root object, and no > mandatory parent constructor calls, so would need a different way to mark > this stage. Constructors can already violate the rules the first phase > should impose, so we can't just use the end of the constructor as the > validation point. > > One possibility would be to add a new keyword like "initialize" which must > be added to constructors in the presence of non-nullable properties. Above > that keyword, use of $this other than to write to its properties would be > an error; afterwards, the constructor could carry on as normal. > > > As I say, this is complex, and it may be best to add nullable typed > properties first, and give more time to try out approaches to > initialisation. > > Regards, > -- > Rowan Collins > [IMSoP] --0000000000006bafd70571203400--