Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:122309 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 2312 invoked from network); 6 Feb 2024 19:18:59 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 6 Feb 2024 19:18:59 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1707247192; bh=dZ7sIqi3aEmJPtXZXG0Lix1V+GE1whIbBtqepkhKVBU=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=SZTAYne29TS08v+xH3+o/YRKT/+8Zc7YrQwyZkkhrIWpYzKN657IcxkJlTBI7qiJR sw78yObYod6KnyMYhpULiZlyGsphGoFuXXEpHHVHNjwVTuQDE9NMyoaTwVzPFc3Drn F+JPqrtt9zcjKKBFCvTg4m9k+PMAimCf7LeORsUO0wvkjStYuZAiBu9HBizmLtxA/e yun46lcx9oKwki4XxVtkw/Lt3j6QKP6/48rmMk6+Z0+7L2+Ha6cTny8sa3gOLUjCFV 2TzB6pmUdKKobo+KbumA5MUnZ8MeqT4PSkgmcuMB0x+fSlVx0441LtfAmXYbmVWVRk K4aO4Nsr445Kw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id C256F180061 for ; Tue, 6 Feb 2024 11:19:50 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,BODY_8BITS, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS, FREEMAIL_FROM,HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2, SPF_HELO_NONE,SPF_PASS,URIBL_SBL_A autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-io1-f44.google.com (mail-io1-f44.google.com [209.85.166.44]) (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 ; Tue, 6 Feb 2024 11:19:50 -0800 (PST) Received: by mail-io1-f44.google.com with SMTP id ca18e2360f4ac-7bc332d49f6so274740839f.1 for ; Tue, 06 Feb 2024 11:18:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1707247137; x=1707851937; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=FjlLLLmd6haXvg43IMxtBJywrchZkFKfXiEHHkp/zeM=; b=JPLakMJKIdOj0GlXw1cz33mPgI7c4jAMo1qRmXBazvTVTvAgLARzRFhpJ+vqfSMetL TMQHoQ5qpS95VG/ehbj6xZQMcw+CTorVLxrsTD/A8nEgKdZjlVshPU4mMeiaA0nUMbwR Iy6VARMwaKI5rLhFK6zwflZKzemIj1h/D1knfSF5yeg8Iu0p/K93UuJhexlfAKqN6NiH Q6yVB2y7I8wlykXa9xA4HOGFRr5IHpCXNoJL5SsY+VfaTBfm8AOKFQSPX26fRq8Mvv0P L0bA0ajAUWoVT56M2N6XTcJjcZ1/adI0yKg+0/rj3hoZ/jjrArT6nuzVCuJ3rS1Hrdqf ztfA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1707247137; x=1707851937; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=FjlLLLmd6haXvg43IMxtBJywrchZkFKfXiEHHkp/zeM=; b=pmF9GL8/IZaJmXx0ZVi8QIvxB9fnAGuyZ/nAh2jYcPOg08H0lSVYikEV+ljkPOcUsB BuaULPP/+YmoVErlzb8oxalVdvAsaphUxq7icxdXAFijidlDmzkynfFyLELEGHczPQMs wxFtX/b5PsRGU4eN1q9KMtu+JrAXiDb3WO5zbSnb0fT8T/HG5UfLhulmTjKDBdq1P30w /zK0pw48hsIn2w/ncQxv7w/PIqodWgxZa0KhWGlHSByoFw3pFoKGmQJrV+VtwCwOPma2 tADpF+tuNN0rb9yOVhm0MnkZ52WSQuzAvDZOzqfCN036JjjKAXQzLIfBeDtdK5nnYkey uzAw== X-Gm-Message-State: AOJu0Yw0TMK80Jf4IRpIz+OZAsNhaidjx8w+Su0EvDQwNflHL4bb5VlY eqvP1IeyNhOUSiyeNLOcUWuS3np9i4Tab177OnlTkY4KuezDdAA8GR90p2qLWpESTMgpuvW62SN IeK9rzT+HrGMjRJ/t53p2FVCggZyCxgB0 X-Google-Smtp-Source: AGHT+IFgiGf4lQ9nAom7hVy1uOJU2lYB6xDAYSFz65JyMLDzYe3IHGyg9jCAnciLE0/l2bOypfoWaVlpfIsIK0NqFmE= X-Received: by 2002:a5e:c30f:0:b0:7c3:f361:3ffb with SMTP id a15-20020a5ec30f000000b007c3f3613ffbmr2629135iok.14.1707247137054; Tue, 06 Feb 2024 11:18:57 -0800 (PST) MIME-Version: 1.0 References: <742f202d-7990-4f51-b903-7a15e3fd33c2@app.fastmail.com> In-Reply-To: <742f202d-7990-4f51-b903-7a15e3fd33c2@app.fastmail.com> Date: Tue, 6 Feb 2024 21:18:20 +0200 Message-ID: To: Larry Garfield Cc: php internals Content-Type: multipart/alternative; boundary="00000000000025e5540610bb73b6" Subject: Re: [PHP-DEV] Feature request: https://github.com/php/php-src/issues/13301 From: arvids.godjuks@gmail.com (Arvids Godjuks) --00000000000025e5540610bb73b6 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Tue, 6 Feb 2024 at 19:14, Larry Garfield wrote: > On Tue, Feb 6, 2024, at 4:13 PM, =D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0= =B8=D0=B9 Senior PHP / =D0=A0=D0=B0=D0=B7=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1= =87=D0=B8=D0=BA Web > wrote: > > Btw, i agree about Javascript, but on a low level it produces the most > > clean code, because there's no types and rules. All types moved to > > TypeScript's client side compiler. > > > > JS 15 years ago ACCIDENTALLY created a pipeline. Named it "Promise". We > > spent years after to understand that while (true) and then/catch should > be > > different patterns. > > I assume much of this thread is a language-barrier issue, which is making > it more hostile than it needs to be. So let me try and expand a bit, > because I am actually quite sympathetic to the OP's request, though not t= he > way it's being made. > > First of all, please don't top post. It is considered rude on this list. > GMail makes it a bit annoying to bottom post but it can be done. Please = do > so. > > Second, there's considerable prior art and discussion on the topic of > error handling and exceptions. In particular, I recommend this excellent > article by Joe Duffy: > > https://joeduffyblog.com/2016/02/07/the-error-model/ > > And this one from me: > > https://peakd.com/hive-168588/@crell/much-ado-about-null > > Yes, they're long, but error handling is a topic that requires more than > casual thought. > > To summarize the articles for the short of time: > > * Exceptions in many languages (including PHP) are very expensive. The > stack trace is one of the most expensive things PHP does. This is one of > the reasons why exceptions are terrible for flow control. > * Unchecked exceptions (where a function doesn't define what it can throw= ) > are a great way to break your application in exciting and unpredictable > ways. (This is the other reason exceptions are terrible for flow control= .) > * Many people find checked exceptions cumbersome, even though they are > better (for reasons Duffy goes into). This is due mostly to bad design o= f > checked exceptions in JVM languages. > * The real problem is that we have a channel for a success case (return > value), a channel for catastrophic failure (exceptions), but no channel f= or > mundane errors (things a responsible developer should expect and know how > to handle gracefully). So those get shoved into one or the other, usuall= y > an exception. > > The need is for a "mundane error" channel. I agree with this. Different > languages handle it in different ways. > > * Go has multi-returns. > * Rust has the Result type (which is an Either monad), and an > auto-propagation operator (?). > * PHP has union types (though that's not a deliberate design, just an > emergent one). > > One of the key differences between different approaches is whether they > force you to handle error cases (Result type) or let you ignore errors an= d > assume a happy path (Go, PHP), letting an unhappy path just explode later > on. Whether the language should force you to think about unhappy paths i= s > a complex and subjective question that I won't delve into now beyond sayi= ng > that there's valid arguments and use cases for both designs. > > As noted in the article above, I've started using enums and union type > returns a lot for error handling and it's pretty nice, all things > considered. That works today in all supported PHP verisons (8.1+). That > said, it's not perfect, in part because it's not standardized and there's > no really good language-level automation around it. > > If we had generics and ADTs, building a Rust-like Result type would be > super easy, and I'd suggest we include one in the stdlib for consistency. > We'll probably get ADTs eventually, but generics are not something I'd ba= nk > on, so that is out. > > HOWEVER, and this is where the important part lies, an open, lightweight, > checked exception system is isomorphic to a Result object. It's just > unwrapped. Compare these hypotheticals: > > class DivByZero {} > (this could also be an enum case, but being generic for now.) > > function divide(float $a, float $b): Result > { > if ($b =3D=3D=3D 0) return new Result::Err(new DivByZero()); > return new Result::OK($a/$b); > } > > $result =3D divide(5, 0); > $x =3D match ($result) { > is Result::OK($x) =3D> $x, > is Result::Err =3D> // Do some kind of error handling. > } > > vs. > > function divide(float $a, float $b): int raises DivByZero > { > if ($b =3D=3D=3D 0) raise new DivByZero(); > return new $a/$b; > } > > try { > $result =3D divide(5, 0); > // Do stuff with $result, knowing it is valid. > } catch (DivByZero) { > // Do some kind of error handling. > } > > These two samples *are logically identical*, and even have mostly the sam= e > performance characteristics, and both expose useful data to static > analyzers. They're just spelled differently. The advantage of the secon= d > is that it could be implemented without generics. (ADTs would be an > optional nice-to-have.) And if the caller doesn't handle DivByZero, it > would try to pass it up to its caller, but being checked it would require > the caller to also declare that it can raise DivByZero. > > The second option could also be improved by other syntactic sugar to make > it easier to work with, like Rust has. For example: > > try $result =3D divide(5, 0) catch (DivByZero) { // Error handling that > evaluates to a value } > > Or by making null-aware operators (??, ?->, etc.) treat raised > light-exceptions as if they were null to make pipelining easier. Or > various other ideas I'm just giving examples of for the moment to make th= e > point, but let's not get off on that tangent. (I would also note that I > agree entirely such a system should only support objects, not primitives.= ) > > This would provide a far better alternative to the "returns value on > success or false on failure" anti-pattern throughout the stdlib, and to t= he > common "returns value on success or null on failure or value not found or > any other possible issue" pattern common in user-space code. (No, I don'= t > expect us to go back and change all of stdlib; just pointing out that it'= s > a known language limitation, and this would be the solution.) > > To be clear: I really like this concept and have discussed it with others > before, using almost exactly this syntax. I have not proposed it because > my read of Internals lately is that there's no stomach for more > type-centric behavior, especially with the obvious "But we already have > exceptions, what's yer problem?" response (which is valid to a point, but > also incomplete for reasons explained above). The responses in this thre= ad > so far confirm that fear, but as an optimist I'd be very happy to be prov= en > wrong if there is an appetite for improving error handling via the type > system. > > Absent that, union types and enums (or really any interfaced object) or a > purpose-built Either object are the best options today, and while they're > not ideal, they're not bad options either. > > None of that logic or argument requires sh*tting on OOP as a concept or > abusing others on the list, however. Doing that only undermines the vali= d > point that there is ample headroom to improve PHP's error handling. > > --Larry Garfield > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > > Thank you Larry for this interesting summary - didn't remember there was quite a bit a discussion around the topic prior. I lean on the "we have exceptions, just leave it be" side out of practical reasons - the vast majority of OO code has standardized around the approach and interoperability is high. It makes using code that's out there super easy and predictable - almost nobody uses the "return false|0|-1" out there (at least I haven't used code like that except the PHP's stdlib, and even that has been changing little by little). It makes error handling predictable, and considering the type of code we mostly write in PHP - most of the time we leave the catching to the global top-level handler or sentry/bugsnag/etc libraries. Consistency is the word I want to highlight here. For better or for worse - it's the method the PHP ecosystem arrived at and it's the predominant one. Introducing a distinctly different method of error handling is going to bring in wrappers around libraries that convert errors to one style or the other, the application code can end up using different ways of error handling, etc, etc. My approach is to grab a different language aka "the right tool for the job" if I want to build things differently, that's why we have so many programming languages and not just a few :) I'd put resources into optimising the VM and php engine to handle the exceptions better and if there are improvements to be had there - do those maybe? (I suspect JIT is also going to influence this a lot going forward). Sincerely, Arv=C4=ABds Godjuks +371 26 851 664 arvids.godjuks@gmail.com Telegram: @psihius https://t.me/psihius --00000000000025e5540610bb73b6--