Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:103230 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 84988 invoked from network); 22 Sep 2018 23:25:06 -0000 Received: from unknown (HELO mail-pf1-f176.google.com) (209.85.210.176) by pb1.pair.com with SMTP; 22 Sep 2018 23:25:06 -0000 Received: by mail-pf1-f176.google.com with SMTP id h79-v6so7388559pfk.8 for ; Sat, 22 Sep 2018 12:32:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mindplay-dk.20150623.gappssmtp.com; s=20150623; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=uFCcLhHJ1zdsh973xAggTpG8T82tBr+vckQcgmDQFbI=; b=OY+WfNiz0yZ3fDGwJSB3xOabx5hiT/IbdNrmd2iUwCT1ipeU+GTZmqgBcD8kIRefX1 3tIKwkiajpEg+cCxt28BO6WoC1K5wVbx3qu4b+SDSNcG0jcoe6v8pnUfEMS2hmjJuODx Jhwr6+O7tMmndxFHSyFOOsw9mxF5/c17c74rs+As4/XVZr/r2aW+sNmjdlhhv9Ol9Y92 iMafz2COZMDpALqksA9+JBNP95gexagAACxWxBR7zSMMBB4uw+THDLj46gL1uihTp7pc g/d2+LyDLDAHIbtd38YYAvwJH26MQGxGvU4OvEtR7teS4Py8/Ei3O0BHB2GXasVn22UX d6Xw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=uFCcLhHJ1zdsh973xAggTpG8T82tBr+vckQcgmDQFbI=; b=sB7GmCfyHw3tfoVKqvOLvFtoDq/V2KW5Eoip2+H2zIovqzcD/kNw/Db4TSKfzXrk5j wifGOlWRKSP/pPuThquXeh1ZQ+5Vo0A/Qkf61/kJTAv07HoLmMEqOtqXp/ivIhT7W6rm zgHkedwHvWQv3uq3Mx6AflDgRNTV04UihhRj8bnnFZHJS4Ald2drWhD5uKgkF72D8ae8 XQoWM3RNJX/nm1E4CwubwJpg3NshcD2MrPY5eSqAo8WQr6jjbiQcQMvlrCLNDQPybgZl HV440hyd0tYwZTDwE5GHncgsKscGiaAhRMhZFwdW1ZRl4LzH1AMuZ+6E+VTSyE9eZ1e6 tnbg== X-Gm-Message-State: ABuFfoiGr49r1M/QD6Yvbm4Tg5yhuXoAu0jhyVUABlBVpN+ADfmfayUt ovHce6QT2sDLnif74clhih8pO8c+4GFYiO27sbxl27ZT X-Google-Smtp-Source: ACcGV617JmwadhVSD3nSFqTUrwDudmk7fjHCxhYGCk2rc5Jjp0YWLUNBm0rhDGnPikMHzFuTgj/8lBIvtlloxJr/FTE= X-Received: by 2002:a63:1064:: with SMTP id 36-v6mr3283479pgq.254.1537644736683; Sat, 22 Sep 2018 12:32:16 -0700 (PDT) MIME-Version: 1.0 References: <5273905.aE8IdBJUB6@vulcan> In-Reply-To: <5273905.aE8IdBJUB6@vulcan> Date: Sat, 22 Sep 2018 21:32:04 +0200 Message-ID: To: Larry Garfield Cc: PHP internals Content-Type: multipart/alternative; boundary="000000000000523a1d05767ad0b7" Subject: Re: [PHP-DEV] [RFC] [VOTE] Typed properties v2 From: rasmus@mindplay.dk (Rasmus Schultz) --000000000000523a1d05767ad0b7 Content-Type: text/plain; charset="UTF-8" Larry, this wasn't aimed at "you" personally, I'm just using the proverbial "you", as in "not me". if you read my last post (especially the last part) carefully, you'll see why this elephant analogy is incomplete. the issue is not whether or not something gets in - it's much more far reaching than that. the issue is, once something gets in, can you even be sure that that something is what it claims to be? at the moment you can't, and that's a serious issue - type hints appear to provide some guarantees that in fact aren't provided at all. it's confusing, and the explanations are more complex than they need to be. (and I guess that's generally an issue in very dynamic languages, but type hints are supposed to provide a means to improve on these problems where it makes sense - not make the problems worse.) On Sat, Sep 22, 2018, 20:32 Larry Garfield wrote: > Rasmus: Please be careful when you refer to "you" as wanting or doing > something. I had no part in the patch design or implementation beyond > saying > "yay!" a few times on the list/twitter. "I" don't want a particular > engine > pseudo-type (uninitialized); I honestly don't care about that level of > implementation detail. I am only trying to offer suggestions for how to > tighten the guarantees further without violating the basic facts of how > PHP > works. > > On Saturday, September 22, 2018 12:12:48 PM CDT Rowan Collins wrote: > > On 22/09/2018 11:15, Rasmus Schultz wrote: > > >> That is, it doesn't assert that a value IS a given type, but that it > can > > >> only be SET TO a given type. > > > > > > That is literally the same thing - if it can only be set to a given > > > type, it can only BE a given type. > > > > Consider this analogy: if I build a house with a standard, human-sized > > door, I cannot walk an elephant through that door; however, if the > > elephant was already there, I could build the house around it. So, the > > assertion that "no elephant can get in through that door" is not the > > same as the assertion "there is no elephant inside that house". If > > you're interested in protecting your house from roaming elephants, the > > small door is probably sufficient for your needs; if you want to know > > that when you walk into a house, there is no elephant inside, you need > > other assurances. > > > > What Larry is pointing out is that Levi and Marco are happy to make the > > door elephant-proof (prevent nulls being assigned to the properties); > > whereas you and I are looking for a stronger guarantee that there will > > never be an elephant inside (that the object will not be in an invalid > > state). > > LOL. Rowan, I love that analogy. It expresses the problem space very > well. > > > > I don't think that, and I don't expect that - I'm not suggesting we > > > enforce > > > anything statically, I'm merely suggesting that a constructor needs to > > > satisfy the constraints specified by the class. > > > > If you read carefully, that's exactly what Larry's proposal below > requires. > > > > >> To wit, could we add an engine check to scan an object and make sure > its > > >> objects are all type valid right-now (viz, nothing is unitialized), > and > > >> then call it on selected actions automatically and allow users to call > > >> it at arbitrary times if they are doing more esoteric things? > > > > > > In my opinion, this is a solution to the problem we created when we > > > decided > > > every property should internally be annotated with an "initialized" > > > boolean > > > property - you have all this extra state that wasn't part of the > > > specification of the class itself, and now you have to deal with that > > > state. > > > > > > In my opinion, tracking this extra state *during the constructor call* > is > > > acceptable and necessary in a scripting language like PHP - I never > > > asked for static type-checking, I'm merely asking for this check to be > > > built-into the language and performed at run-time when you exit the > > > constructor, e.g. at the last moment where you can feasibly perform > > > this check. > > > > I'm not sure if you've misunderstood Larry's proposal, or are just > > agreeing with it: the sentence you quote says "add an engine check" and > > "call it on selected actions automatically"; and you ask for it to be > > "built-into the language and performed at run-time"; you mention it > > happening "when you exit the constructor", and just below the part you > > > > quote, so does he: > > > * on __construct() exit. > > > * on __wakeup() exit. > > > * Possibly other similar checkpoints. > > > > The key compromise, however, is that this still doesn't guarantee that > > there is no elephant in the house: there will be ways to create an > > object that don't go through the constructor, so won't trigger this > > check; and ways to manipulate an object that will put it into an invalid > > state. Not to mention that inside the constructor, $this will be usable > > as a normal object, unlike in a true 2-phase initialisation system like > > Swift's. > > > > In short, we will still need runtime errors for attempting to read an > > uninitialized property, but they will be much less likely to happen > > accidentally and show up a long way from their cause. > > > > > > I would be interested to hear if there are any use cases that this would > > break - a static factory method can defer as much initialisation as > > needed to the constructor, and cases where the constructor is bypassed > > will also bypass the check. > > > > Regards, > > Yes, Rowan has it exactly. To continue the analogy, I'm proposing that, > once > the house is built, you take a moment to look inside and say "Holy crap, > there's an elephant in here!" > > In more code terms, this is an extremely common pattern in PHP today > (using > the post-RFC syntax): > > class Doer { > > protected Processor $processor; > > public function __construct(Processor $p) { > $this->processor = $p; > } > // ... > } > > This code is obviously valid, because while there is a moment at which the > Doer::$processor value is null/unintialized/not-a-Processor-object, it's a > short-lived moment and by the time anyone other than the class author > cares > marked as nullable would, in fact, be a worse guarantee. > > the constructor it would only blow up in my face, not someone else's. > > class DoerOne { > public Processor $processor; > $d1 = new DoerOne(); > $d->processor; > class DoerTwo { > public function processor() : Processor { return null; } > $d2 = new DoerTwo(); > $d2->processor(); > > Both $d1->processor and $d2->processor() will fail with a TypeError. In > both > cases it's very clearly and obviously the fault of the Doer class's > author. In > both cases the TypeError happens on access, and I can work back from there > to > figure out where it should have been set. In both cases my course of > action > It can be done one better, though, by adding an is_there_an_elephpant() > check > at key points. Effectively, it becomes logically equivalent to: > if (is_there_an_elephant($this)) { > throw new TypeError('Bad, Elephant, no cookie!'); > } > Serializable::unserialize(), or whatever else. (By analogy, also checking > that an elephant didn't get in while the window was open.) > public Address $streetAddress; > } > Because you would at least need a constructor to set $streetAddress to an > empty Address value. Which... I am OK with and consider a good trade-off. > PS: It was so, SO hard to write elephant and not elePHPant throughout this > post... :-) --000000000000523a1d05767ad0b7--