Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:103226 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 12604 invoked from network); 22 Sep 2018 14:08:13 -0000 Received: from unknown (HELO mail-pg1-f178.google.com) (209.85.215.178) by pb1.pair.com with SMTP; 22 Sep 2018 14:08:13 -0000 Received: by mail-pg1-f178.google.com with SMTP id 205-v6so6193607pgd.2 for ; Sat, 22 Sep 2018 03:15:19 -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=scSsvQUK9pwAFD25uIQWp3VoY0NEgreV44kvz9rsdhg=; b=sa/ujQQJr095iTiCH+igMApmuqH/FMGvcbl1NZS+rkacock4ab+Q5hsYlCmcGrlumZ L/A51otYtMmlLAD9I7GH9MmTR+Xsr0VVFerN0qovwPwYEUYI725F+/93+6zBonID2RcS H+3MLqcKia++iXTxfk2X7eI7DHBo7ZK/BO/jhgLxLhmoSako5LdskvacgrmUwaWrlJIl c+pRlVX5FEwFBLnRknGq8F1TFCbd4TaL+BQGYoD3MLIcJSyGAqsq0+8A2Kp77q25n2v5 duYy7Kow3nNZ9zLxC4864DeIE6VntE2344t5lvHU5XPFsDJ80rIKV9xHS5ClMk19ReHr GDEQ== 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=scSsvQUK9pwAFD25uIQWp3VoY0NEgreV44kvz9rsdhg=; b=lObb/oGP6tVfpt2IgpFxXJBvg4KX0PK6MWJf1QZKb/ZqgiK8NsogNk0cJKtg1IcAQM gKzt0Lc13SuB3AJIlKHSS33eB1pwroV1zmNiIIPjZ3W8EqHJhZy8kq4Rd+E/BWBZZpTf 4aQZAgf/94Iojn0TFgTrbQXysCRnVdrs1fntT7gwAdY2Q31F2PoMMWdRp/ZIkBz5JNU0 3G9ToC62l5LPms8xkpYTMxPeFyC3MFpIcTtO/acNdTaLZteceFCVSofc3CBnGcXBdI3T /zcgvf4jJKYTVZqrJkkv96/aLFZ9HeLGOF1LXLJLnQjWFcqEHJdIYPGzQS+VxZZopYXD Kf+Q== X-Gm-Message-State: ABuFfojgh/9egTwb1dJzZ/bBG33YxuFQkL50wkl2z2BfKBtVVkNmFRng TpYsN5+d+7alAE9jWdRIjOLTYkkXPo2eI/9UJfPgmVQ4Xc8= X-Google-Smtp-Source: ACcGV63XFDVsc6QjVzD34kcZbsMnKlABduD0lAhUxbA1SDvw1WxD/jXR2GEEnED1XGfd3pa3Os15IHUXFFMS7Y47JR4= X-Received: by 2002:a63:1064:: with SMTP id 36-v6mr1766394pgq.254.1537611318388; Sat, 22 Sep 2018 03:15:18 -0700 (PDT) MIME-Version: 1.0 References: <4983605.CXexPrWP49@vulcan> In-Reply-To: <4983605.CXexPrWP49@vulcan> Date: Sat, 22 Sep 2018 12:15:07 +0200 Message-ID: To: larry@garfieldtech.com Cc: PHP internals Content-Type: text/plain; charset="UTF-8" Subject: Re: [PHP-DEV] [RFC] [VOTE] Typed properties v2 From: rasmus@mindplay.dk (Rasmus Schultz) I apologize for the long posts, but Larry asked me to comment on this. On Thu, Sep 20, 2018 at 5:52 PM Larry Garfield wrote: > I think the distinction here is that one group is arguing for "state of the > data assertions" while the RFC as implemented is "setter assertion shorthand". The point of the setter assertions is to provide guarantees about the state of the data - there is literally no difference. > 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, is can only BE a given type. The problem here is you want to make exemptions for null as type - as though nulls aren't types (which they are) and as though nullable types aren't distinct from the types they're derived from. (again, they are.) > I don't think a complete IS enforcement is possible given PHP's nature. 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've type-hinted a property as int, you don't allow strings - that would be pointless, right? But that is precisely the problem we're talking about - if you've type-hinted a property as non-nullable int, it shouldn't allow null... but that is literally the exemption you want to allow for - you just want to annotate the property with an additional meta-data property "unintialized", which is literally the same as adding a boolean "is set" for every property in your model. > This isn't a compile time check > either: > > $b = 'foo'; > test($b); > > It's a runtime TypeError, not compile time. This actually illustrates my point nicely - the variable $b in this case has nothing to do with the state of the parameter var inside the function body, until you pass it via a function call. That's perfectly fine. You'll get an error at the point where the parameter type-constraint was violated - you can look at a stack-trace and debug that easily. Now take your example and call a constructor instead of a function: class Test { public string $b; } $b = 'foo'; $test = new Test(); Your constructor call generates no run-time error here, and the program continues to execute with $test in a state that, according to specification of the class itself, isn't valid. Since the constructor is how a valid instance of Test gets generated in the first place, you've missed your *only* chance to enforce those constraints - meaning, you've missed the only opportunity you had to verify that the constructor does in deed generate an instance of Test that lives up to Test's own specification of what a Test instance is. > 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. If you don't perform that check, you have no guarantees at all. Consider this example: function login(int $user_id) { // ... } Inside the body of this function, you can safely assume you have an integer, right? A basic guarantee provided by the language. Now consider this alternative: function login(User $user) { // ... } Inside the body of this function, you'd assume you have a valid instance of User, right? The same basic guarantee provided by the language. Wrong. Something might be "unintialized". This might in fact not be a valid instance of User, it might be only partially initialized. This is a problem, because I want my type User to be a reliable type - as reliable as any other type. Integers for example is nice, because I know I'm going to be able to add, subtract, multiple, divide, and so on - if you've type-hinted a parameter as int, you know it has those abilities, you know the + operator isn't going to fail because there's a special kind of int that doesn't work with the + operator. We want those same guarantees from our own types, that's all. In the case where a type *doesn't* provide such a guarantee, it can explicitly state that something is nullable - not guaranteed to be set. You have that option already, you don't need unintialized properties for that. If there really is a use-case for "optional values that must not be removed again once they've been set" - and I can't think of one - but if there is, you can handle that rare case with logic in getters/setters. The normal everyday use-case is you want to know if a property is going to be set or not - hence nullable property-types, which are part of the RFC. Userland work-arounds for basic guarantees that the language should be providing, in my opinion, are totally unacceptable - in a nutshell, because basic guarantees provided for other types won't apply to objects. It's incoherent with the workings of type-hints in the language, and will make those substantially less useful.