Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:114216 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 45740 invoked from network); 27 Apr 2021 22:18:53 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 27 Apr 2021 22:18:53 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id D6C691804CC for ; Tue, 27 Apr 2021 15:23:15 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_LOW,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_PASS,SPF_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-Virus: No X-Envelope-From: Received: from out4-smtp.messagingengine.com (out4-smtp.messagingengine.com [66.111.4.28]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Tue, 27 Apr 2021 15:23:15 -0700 (PDT) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id AF5325C0118 for ; Tue, 27 Apr 2021 18:23:14 -0400 (EDT) Received: from imap8 ([10.202.2.58]) by compute4.internal (MEProxy); Tue, 27 Apr 2021 18:23:14 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=TXoYFD Bt4wler8OHwnt60JaaIHWnc8WktfS/IYeTW0U=; b=I1LqWNe+R9CHV6F3v81qlm kXvvxGZlSLbtXQj3ebP1mKKfufPvENVaKB6f0nUZHa+Ma/4cOvC2D2XfGp5+1cTu RcMNphPMuDWFz2jMDqqUXPzhkzpmqt4VwdkN1AtOpnKm1HiMF38gWRhF83zm301W 927d3E+eFrsEg9vB15gyxaXCuzJEd4iyKTrNwSfrl2e0GB2leDq0ciEiNNR5zKRB D+kZC92TQlJ0P+LrPQN9va3Y74w2Ak+mqRJOD46C91KN9hRQic+euqBPy8zpNvlD JRlYi2lzAFpsYtL9YCUcghPJCxi/WPOxuDIHBy8B1bBUj1IGzTEBdmmQLWaPg/9w == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrvddvuddgtdejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepofgfggfkjghffffhvffutgesthdtredtreertdenucfhrhhomhepfdfnrghr rhihucfirghrfhhivghlugdfuceolhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtoh hmqeenucggtffrrghtthgvrhhnpeeglefgkeduiedvvdetffeujefftdfhjeeiveehgfff keduveektddvledvvdfffeenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmh grihhlfhhrohhmpehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomh X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id 5FA183A02D2; Tue, 27 Apr 2021 18:23:14 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.5.0-alpha0-403-gbc3c488b23-fm-20210419.005-gbc3c488b Mime-Version: 1.0 Message-ID: <51fffd88-03c7-463d-a6d7-94c086cb5893@www.fastmail.com> In-Reply-To: References: <5b9f1500-615a-48f1-815f-1d48b327ef90@processus.org> <179049b1475.11134368b213512.254739612773841999@void.tn> <722ed544-69e3-3be4-f828-185914617228@processus.org> Date: Tue, 27 Apr 2021 17:21:48 -0500 To: "php internals" Content-Type: text/plain Subject: Re: [PHP-DEV] [RFC][Draft] Sealed Classes From: larry@garfieldtech.com ("Larry Garfield") On Tue, Apr 27, 2021, at 2:07 PM, Chase Peeler wrote: > > Sometimes it's helpful to apply a risk perspective the shed some light > > under hidden assumptions of different arguments. For example, what's > > the probability and impact of an event that would limit a coder when a > > library is using a sealed class? And the other way around, what's the > > probability and impact of an event that would decrease code quality > > when a sealed class is *not* used (like being able to subclass > > Maybe/Option even when it "shouldn't" be possible)? > > > > > As someone mentioned above, maybe they want to just add some logging > capabilities to maybe. > class MyMaybe extends Maybe { > protected $logger; > public function setLogger($logger){ $this->logger = $logger; } > public function value(){ > if(null !== $this->logger){ $this->logger->log("getting value"); } > return parent::value(); > } > } That's subtly different than what is being discussed here. Consider: class Maybe { ... } class Some extends Maybe { ... } class None extends Maybe { ... } And now assume we have pattern matching in the match expression (just to make the following example simpler; it could also be done with instanceof directives just as well but it's more verbose): function operateOnValue(Maybe $m) { $val = match($m) is ( Some($v) => $v, None => $some_default, }; ... } This code works on Maybe as defined, with two branches, Some and None. If you extend Some with your own custom Some, it still works. This code is fine. Such extension could be prevented by making Some final, but *you can already do that today*. If you want to add another subclass of Maybe, called Perhaps... that function will now break, because the nominal contract of Maybe (that it has only two variants) has been broken. As soon as you pass a Perhaps to operateOnValue(), the function will fail with an exception. And there is no way to prevent that today. The two options to prevent such errors are: 1. Sealed classes. 2. Extend Enums into ADTs. They're different in a few key ways, but both address the same problem space and would render operateOnValue() safer against errors, because its developer can know, by definition, that it can handle all possible variants of Maybe. (That is, it's a total function over Maybe.) A comment (by whatever syntax) saying "pretty please don't extend Maybe" is worth the executable code it generates (which is to say, None). --Larry Garfield