Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:123352 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 3DAF51A009C for ; Sat, 18 May 2024 16:14:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1716048908; bh=AlvceS1NyS6Utg0uNOlvh2X3ysa474GoK6VcK8rmt90=; h=In-Reply-To:References:Date:From:To:Subject:From; b=VpJ/ALCx7re+qniD746EAHF+/v80X9IM/eVKk7cRb5Kc/kR7koBwEhGZIyAZ5LkzL sfkNhW8Akjy8S4IdJkEaX62sXp3BkxuE5H3M4zRDN0MpjY74dmWD3ZxUO/Kk/hIBE2 taqUhlMLnrdWe9yDU+pDwwOD5DhIujmQSBEepi4eTFSjuyt9/buXKDUnnNuksTRwg7 AWkjKe5wxRE3VLHJXLwL7pj4cyVQQSYZuOKND1W0X2yP7O6fPTYUwFC+C+I+yyA14e oCHR4gXYWx4miIpUoTFmeNSZxwyEO62X26CK9Un8aTYb2FLiBhl5B6TO5AA1rWradb iwDclroQb+n6A== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 0758F180605 for ; Sat, 18 May 2024 16:15:06 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,RCVD_IN_DNSWL_LOW, SPF_HELO_PASS,SPF_NONE,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from fhigh5-smtp.messagingengine.com (fhigh5-smtp.messagingengine.com [103.168.172.156]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sat, 18 May 2024 16:15:05 +0000 (UTC) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailfhigh.nyi.internal (Postfix) with ESMTP id ECC4E11400C2 for ; Sat, 18 May 2024 12:14:10 -0400 (EDT) Received: from imap50 ([10.202.2.100]) by compute1.internal (MEProxy); Sat, 18 May 2024 12:14:10 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= garfieldtech.com; h=cc:content-transfer-encoding:content-type :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to; s=fm1; t=1716048850; x=1716135250; bh=SinY0tNHw3eFHrY/Wr0Ij jRZC7sNUDUQeUyZwvCoTOs=; b=dBa6CFuepd3DjmK/lO4Za22YyZE9xJTQIBp29 sxKy2UyG20UldqZSDykg+4MFobNmBWdywzYru4o2mQK+FYt0FUXyEcyjZnY/su4L 4wGjic0KR5yseWb7jCtbCOrwpTDY5PgPg+NlmV5aeWmn3z5PTQHy2SjUxOdAFyMC NHzIOhfwB4V8fKkdKJjO6n/paswyRFG/+FroUCUXJxWxu7RkwNQHaOZvnS/BGKQx M3hhZU7ZjqeocgH5w9rSsU9mJQKZfxEQ+U2yTCJIV17cfVMoiJmn6SrTSmBdk+69 sgMBlQdWREcetusGZQLPn0lJg95EKtYrTqzK7SJCl93UkBJ/Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1716048850; x= 1716135250; bh=SinY0tNHw3eFHrY/Wr0IjjRZC7sNUDUQeUyZwvCoTOs=; b=E Q+uNljSBeAHuJtMcajIDsm2TnwtqOop2gEcdfdLmLNhpOUncF/MGcKyZJ8mr/BJK ygGMTMTWmOI59UBK1/lobv0xEkqKk44iT+uGluQeVC8EClrDzY7DfZM6+VlCPUK8 IwtCS2gZw5oMyA3ddZBDrTXFOtGxhkkrjZ2OB8b5TDx8GtmPmNPvwQ6oZ7rEztDG NLBL6AnJ6Xk2DEzFE9NvGt8FsoHvrUWG1GxCgPmeBjhGxQYZSVLMOtbbcHaKyybS XN+asXvNzYc/RfZ3L4WmLXKcq3SdqNbmII4kkTubEHYgBVbSt74PNdN6kNdErKLt zEW4Dcbg5hp1/gWpMuv3g== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrvdehiedgjeelucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne goufhushhpvggtthffohhmrghinhculdegledmnecujfgurhepofgfggfkjghffffhvffu tgfgsehtqhertderreejnecuhfhrohhmpedfnfgrrhhrhicuifgrrhhfihgvlhgufdcuoe hlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomheqnecuggftrfgrthhtvghrnhep keekheeludfgheehgeekfeevtdevtdetffejhfetgfethfejudetieeiffdvjefgnecuff homhgrihhnpeefvheglhdrohhrghenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgr mhepmhgrihhlfhhrohhmpehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomh X-ME-Proxy: Feedback-ID: i8414410d:Fastmail Received: by mailuser.nyi.internal (Postfix, from userid 501) id 866971700093; Sat, 18 May 2024 12:14:10 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.11.0-alpha0-456-gcd147058c-fm-hotfix-20240509.001-g0aad06e4 Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 Message-ID: <5014b401-6341-44c6-a16e-f453ab52220c@app.fastmail.com> In-Reply-To: <878c09ca-860e-4c0c-85ae-2cd0246cda3c@rwec.co.uk> References: <878c09ca-860e-4c0c-85ae-2cd0246cda3c@rwec.co.uk> Date: Sat, 18 May 2024 11:13:49 -0500 To: "php internals" Subject: Re: [PHP-DEV] [DISCUSSION] Checking uninitialized class properties Content-Type: text/plain;charset=utf-8 Content-Transfer-Encoding: quoted-printable From: larry@garfieldtech.com ("Larry Garfield") On Sat, May 18, 2024, at 9:40 AM, Rowan Tommins [IMSoP] wrote: > On 18/05/2024 11:52, Luigi Cardamone wrote: >> I am already using a solution like the one >> proposed by Robert: it works but it >> leaves some doubts since each project >> can have a different name for NotSet > > > An argument is often made that this is a good thing, in the sense that=20 > "null" and other "universal" terminal values combine multiple meanings=20 > in an unhelpful way. You'll see this frequently regarding SQL's handli= ng=20 > of NULL, for instance - does it mean "unknown", "not applicable",=20 > "invalid", etc. > > A common solution put forward to this perceived problem is "algebraic=20 > data types" - a Maybe or Option type for "value or missing", an Error = or=20 > Failable type for "value or error", etc. PHP doesn't have those=20 > (yet...), but the same information can be conveyed nicely with a final=20 > class or single-element enum. > > In your example, the actual value you want to represent is not "Not=20 > Set", it's "Keep Current Value", so that's the terminal value you need: > > final class KeepCurrent {} > class MyDTOPatch { > =C2=A0 =C2=A0 public int|null|KeepCurrent $propA; > =C2=A0 =C2=A0 public=C2=A0int|null|KeepCurrent $propB; > } > > or: > > enum PatchState { case KeepCurrent } > class MyDTOPatch { > =C2=A0 =C2=A0 public int|null|PatchState $propA; > =C2=A0 =C2=A0 public=C2=A0int|null|PatchState $propB; > } > > > >> Are there any downsides in adding a >> specific syntax to check if a property >> is initialized with any value? > > > In my opinion - and I stress that others may not share this opinion -=20 > the entire concept of "uninitialized properties" is a wart on the=20 > language, which we should be doing our best to eliminate, not adding=20 > more features around it. > > As a bit of background, the concept was created when typed properties=20 > were being added, to handle a limitation of the language: given the=20 > declaration "public Foo $prop;" there is no way to specify an initial=20 > value which meets the type constraint. For nullable properties, you ca= n=20 > write "public ?Foo $prop=3Dnull;" but since PHP (thankfully) distingui= shes=20 > nullable and non-nullable types, you can't write "public Foo $prop=3Dn= ull;" > > Some languages, e.g. Swift, require that all properties are initialise= d=20 > before the constructor returns, but retrofitting this to PHP was=20 > considered impractical, so instead it was left to a run-time error: if=20 > you fail to initialise a property, you will get an error trying to=20 > access it. > > To track that, the engine has to record a special state, but assigning= a=20 > meaning to that error state is a bit like using exceptions for flow=20 > control. It would be more in keeping with the original purpose to have=20 > an object_is_valid() function, which returned false if *any* property=20 > had not been initialised to a valid value. > > > PHP actually has a bewildering variety of such special states. In a=20 > different compromise added at the same time, calling unset() on a type= d=20 > property puts it into a *separate* state where magic __get and __set a= re=20 > called, which they are not if the property has simply not yet been=20 > assigned, e.g. https://3v4l.org/C7rIF > > I have always found this a mess. If a property says it is of type=20 > "?int", I want to know that it will always be an integer or null, not=20 > "int or null or uninitialised or unset". If it needs more than one=20 > non-integer state, that should be specified in the type system, e.g.=20 > "int|NotApplicable|NotSpecified|NotLoaded". > > > PS: Etiquette on this list is to post replies below the text you're=20 > replying to, preferably editing to the relevant parts as I've done her= e,=20 > rather than adding your text above the quoted message. > > Required, > > --=20 > Rowan Tommins > [IMSoP] I am unsurprisingly entirely in agreement on the problems of using null = as a universal sentinel, and the value of using an enum as a sentinel. However, that breaks down with readonly properties, which are not allowe= d to have a sentinel. Uninitialized is their sentinel, for better or wo= rse. Ideally, yes, all readonly properties are set by the time the cons= tructor ends, but that's not always feasible. And as I noted earlier in= the thread, when writing a serializer or other dynamic systems (an ORM = probably would have the same issue), you really need to be able to diffe= rentiate between null and uninitialized. Even if you think the uninitia= lized value is a sign of an error, it's coming from code you don't contr= ol so you have to be able to handle it somehow. Some way to more easily check if a property is in one of the various "sp= ecial states" would be helpful. Even if the number of special states is= itself bad (I don't disagree there), they are already there, and making= it easier to work around them would be helpful. --Larry Garfield