Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:111030 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 57303 invoked from network); 15 Jul 2020 20:24:06 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 15 Jul 2020 20:24:06 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 9DF3F180510 for ; Wed, 15 Jul 2020 12:16:51 -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.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=3.4.2 X-Spam-Virus: No X-Envelope-From: Received: from mail-il1-f196.google.com (mail-il1-f196.google.com [209.85.166.196]) (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 ; Wed, 15 Jul 2020 12:16:50 -0700 (PDT) Received: by mail-il1-f196.google.com with SMTP id i18so2958914ilk.10 for ; Wed, 15 Jul 2020 12:16:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=datadoghq.com; s=google; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=U3m+75jTMC7oP4hjNC1Vp4inNYYPNM//xiqMHa+ZOuQ=; b=OBBngGQfGcLzdO1QKxUJC1u2gb8LwXaHGK7/EfewN3FXnDPGPiv1FE8+IPjsgPfQnQ hvdPLsJYXAzC+jgwDvldUkOEKZBTSoKAzcbzFZ8eLcQejiUoitNpPnpfVzunyKJdaQ4R UzCleTErrjSBNJAxsNJCFya01yVP48uSkJY9k= 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=U3m+75jTMC7oP4hjNC1Vp4inNYYPNM//xiqMHa+ZOuQ=; b=nwKYb07c2E9tv6JfGXMoJnV/3qkONL3vag8rn7G/h9qEn4nbCzXapVldKpeeEkUbUX AQt5yGGMrTOPeM7WXg/bxZohDmxzeeo7FJk9ameggJMeMhEzXj9YDwQpVq+V77MFjeYy XPTRCgKuKGaYO3upES/rZyoyt1wOmrMIzsv1F3G/Qt4bMKMa80VhgLI7iH/PV0YBDeoE nmOYt9h2sOVbgO382UQA8ePtOIxxjEXUV37EelMELrrukm7D1eWHTjWQgtK0MJXjbTfc 9cb0Zz66eP70qlad6vLiwCawPa3j4lly36xnSxs7gjHnvHgqPfdrLn2YMnAK2zwKyfPA pPYQ== X-Gm-Message-State: AOAM5336++aszYs1I8Znnxi9Wht/pxUVmrB3hoVAf/HTdAXMpbzNXCFk gMDDVPrOSWwM/bvZf0c+cFrSkZVwuyjnmaO6vx0I6g== X-Google-Smtp-Source: ABdhPJyXAVOuQ+1f497I72M0s2xfI9PHU2h7pYGt/bo21KLmNV1xWh4CINMIBX5gfmG0c38o06AHGo5IaJCsjmrd+dE= X-Received: by 2002:a92:1b51:: with SMTP id b78mr1030796ilb.232.1594840607274; Wed, 15 Jul 2020 12:16:47 -0700 (PDT) MIME-Version: 1.0 References: <21C5073D-3F39-49DA-8686-E027AE780793@joshbruce.dev> In-Reply-To: Reply-To: Levi Morrison Date: Wed, 15 Jul 2020 13:16:36 -0600 Message-ID: To: Marco Pivetta Cc: Larry Garfield , php internals Content-Type: text/plain; charset="UTF-8" Subject: Re: [PHP-DEV] [RFC][Discussion] Objects can be declared falsifiable From: internals@lists.php.net ("Levi Morrison via internals") On Wed, Jul 15, 2020 at 10:43 AM Marco Pivetta wrote: > > Hey Larry, > > On Wed, Jul 15, 2020 at 5:32 PM Larry Garfield > wrote: > > > 1) return null, which is a non-type, and thus you need to make the return > > type ?User or User|null, which means the caller *must* always check it's > > nullness. > > > > Allowing an object to falsify itself is a 4th, more type-safe option. It > > lets you return an object that both fails a boolean check (like null) but > > also has default values in it for the base case. A user object likely > > wouldn't use that, but a value object like an Address very well could. > > > > Until we can support for-reals monads (which would require enums and > > generics to do properly; the former is possible the latter is very hard), > > it's the best option we have for more type-safe returns. > > > > Adding a "falsey" state for code that expects `is_object($foo) === (bool) > $foo` seems to be a massive BC break to me, and reduces type safety of > boolean operators (and checks) by expanding the `object` type and all > operators and expressions that can interact with it. > > In general, `?T` is very much equivalent to `Maybe T` > > Where `instance Monad Maybe` is implemented in type-safe langs as (quoting > https://en.wikibooks.org/wiki/Haskell/Understanding_monads/Maybe - I > omitted `return` because the lifting bit is not really used in PHP): > > ```hs > (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b > (>>=) m g = case m of > Nothing -> Nothing > Just x -> g x > ``` > > `?T` is very much the same in PHP (pseudo-code, since nullability is not > represented the same way in Haskell): > > ```hs > (>>=) :: ?T -> (T -> Maybe T2) -> ?T2 > (>>=) m g = case m of > null -> null > x -> g x > ``` > > Let's not confuse Java nullable issues with PHP nullability, which is quite > healthy :-) > > I see adding a "falsey" evaluation to something that has been assumed (for > a looooooong time) as universally "truthy" is a very major issue. > > We need code examples where this is a clear advantage over previous logic: > as it stands, I don't see why I would ever prefer `(bool) $object` over > `$object !== null`, or `$object->valid()` (which I believe to be an > anti-pattern) In my opinion, it seems reasonable to be able to swap out an array for an object that implements Traversable, ArrayAccess, Countable, etc in common situations. However, this is not possible in at least two common situations: if ($array) { // ... foreach ($array as $key => $value) { // ... } // ... } if (!empty($array)) { // ... foreach ($array as $key => $value) { // ... } // ... } You could swap `!empty()` for `count > 0` , but I can imagine objects where we can know that we aren't empty without knowing the full count. For example, a database result using a cursor or something; we'll know on the first response if we have even 1 result, but we won't know the final count ahead of time. Of course, there are cases where we can't do this swap because of `array_*` specific functions anyway, but my point is rather that from a language perspective it seems like a reasonable goal to pursue.