Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:125014 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 5AAFE1A00CB for ; Sat, 17 Aug 2024 00:47:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1723855756; bh=NxqBCSXuFZdfsijLkdmsoiEk7o/X49h+XTiHCcVql3U=; h=Date:From:To:Cc:In-Reply-To:References:Subject:From; b=DDmlFB2M6C3WOW782+Ogf1HbPktNwFbnXv4KYz9pZerIAMgz54ww00GFouAbKP9jT ryom6K5dkm2vNqbHgrsdnA0XN1wJ5+X8jRqBIW2Zs4pYkt5je3opQf11jaLmj0I7If 0nNzD0JH6Pw01afCOphxLq/D7QFVcu/IiK9eoZYYqCLWn3hsf7GcnMSipXNDyunsZQ DrolpYCfMWNfsiTPTfMVCaZ5UlV9cZUaf45XHutvRpXJ5dYORDU188Vj5NdzpTFUy9 HsW1PFL3yT36bgCospaptEQcfuLZvabSCfZnGknnn/ENEEHY0EHsv6Al893dweTZMD 8ITgk/4OxHJyQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 6DC511801EF for ; Sat, 17 Aug 2024 00:49:13 +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.8 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DMARC_MISSING,HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE, SPF_NONE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-qt1-f174.google.com (mail-qt1-f174.google.com [209.85.160.174]) (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, 17 Aug 2024 00:49:10 +0000 (UTC) Received: by mail-qt1-f174.google.com with SMTP id d75a77b69052e-45007373217so31799971cf.0 for ; Fri, 16 Aug 2024 17:47:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=coggenterprises-com.20230601.gappssmtp.com; s=20230601; t=1723855643; x=1724460443; darn=lists.php.net; h=mime-version:subject:references:in-reply-to:message-id:cc:to:from :date:from:to:cc:subject:date:message-id:reply-to; bh=NxqBCSXuFZdfsijLkdmsoiEk7o/X49h+XTiHCcVql3U=; b=GmC7+cj/QC+8OeHgJZM7QnOBIxYRqSItdF+dGcSse3+uZb1g7pIgPdvEDQP3pevsVy cLRWovKu4CBGIBfOQKXpfCTrnl8uNUq5U4/K2g2iEeLxOGlIeUjHuJNZUiRchspkmkrT 0OtD4F2FCrnnOMQCzKXw7H8A4F8/iixYXTDTB3+giTJR1M507OQSy0DjZ2o4vnEcaMdc bCSB6xc31of7aTB48/HjoKk6V0M+nJlQ0WMvK+2Ce8z+JutImBeuncE6JhHlY3Q5I74y VstwcPhsFQDkTjszeYBw93KEzgUFzfb7nPIwIVrIFwqjj4fnEiFBgGJ6sRPvf0qB6RMm J2XA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723855643; x=1724460443; h=mime-version:subject:references:in-reply-to:message-id:cc:to:from :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=NxqBCSXuFZdfsijLkdmsoiEk7o/X49h+XTiHCcVql3U=; b=BgFd5wMCJzdzzLVDokJca948zeo2+HkCuybPtFuRH0zz//SWnoXxImIo5+xzjlz9Yp GUbGW79YhaDbgIn6zDYyWa3HvXkiaPwIgC33pE7IGmDS58No9xVA8BCfJOuU+4LqGH3t 9DwkhYr98kbqg4b6wPKsYaeOGkuKhTDUsVj0kW6/O5UxyItvfFEIM3gjQrrlXFByI+A/ djVgr3aPjWWeMCPT/wEzek2gChO92+zyiCFYJhIxbkgUNOmj1nfYufyrfml/Z6U2dnl+ Y7xma25vf2eSo2Ki3oH/HZFWkjmxqSNxNweTDbtSUCo5sXWswGNv8dzatrkpLHWwm4rw 3ilw== X-Gm-Message-State: AOJu0YwZS0YljtrUuaV7I1Zu1bP+48WcyrSW8tK8zgS09RjEveXQBjfp 5jECGTFNpFFmk89D/xozWlZwy6DX4PF+0x1hYYYDDljeWhgaT6rYcjnCFoM56WR5IhYdIPsIwol 1 X-Google-Smtp-Source: AGHT+IG9LU7TDTZq6Ue2WExT4GNmz49DOeh/fX1HaKp8jY2pflJ1EhM8PDEQqYnXLIpYPmdtL4jBHw== X-Received: by 2002:ac8:4596:0:b0:453:5f34:1d1b with SMTP id d75a77b69052e-4536787bf4amr116224641cf.18.1723855642541; Fri, 16 Aug 2024 17:47:22 -0700 (PDT) Received: from Johns-MacBook-Pro-2.local ([98.97.17.118]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-4536a072267sm21631001cf.81.2024.08.16.17.47.21 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 16 Aug 2024 17:47:22 -0700 (PDT) Date: Fri, 16 Aug 2024 20:47:20 -0400 To: Larry Garfield Cc: php internals Message-ID: <82BB4B15-F799-4E11-8A0F-CF5E5C995F82@getmailspring.com> In-Reply-To: References: Subject: Re: [PHP-DEV] String enums & __toString() X-Mailer: Mailspring Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="66bff318_643c9869_17d67" From: john@coggeshall.org (John Coggeshall) --66bff318_643c9869_17d67 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Content-Disposition: inline > To the original question, there's two reasons that __toString() was deliberately omitted from enums: > > 1. To discourage their use as "fancy strings". Enums are their own type, independent of any other. Making them usable as 95% strings partially defeats their purpose. I disagree with the idea that we need to take this extreme of a stance when it comes to the notion of protecting the developer from themselves. There are a lot of really value use cases where it makes sense to have a string-backed enum . Not allowing developers to cast it to a string isn't doing anything but making people type $enum->value instead of (string)$enum -- so if someone wants to defeat their purpose this isn't stopping them. It is, however, making the language inconsistent because I literally have a enumeration defined by strings and there is literally no way to make PHP treat it like a string. This makes APIs sloppy imo because consider something like this: function foo(string|Stringable $bar) {} Because of these limitations this blows up into a much uglier thing in order accomplish what IMO should be a straightforward task: function fooThatWantsString(string|Stringable|UnitEnum $bar) { if(($bar instanceof UnitEnum) && !is_string($bar->value)) { throw InvalidArgumentException('This is exactly the sort of thing we are trying to get rid of with type hinting'); } else { $bar = $bar->value; } $bar = (string)$bar; } Of course, you could also pass $bar->value higher up the call stack but it's much cleaner IMO to let the function call be smart enough to typecast as necessary. What's the point of a Stringable interface if we can't actually implement __toString() for it? Note again we can implement JsonSerializable and nothing complains when enum serializes to a simple string. > 2. We still intend to add associated values to enums at some point (aka ADTs, aka tagged unions), and... we're not really sure yet if that will impact __toString() at all. It may, it may not, we don't know. So for now we're keeping our options open by disallowing __toString(), in case it ends up being needed for some ADT-related behavior in the future. __toString() should return a string, if an enum literally represents a string constant it makes zero sense for it to ever return anything but that string constant. I don't think this is something ADTs or tagged unions or anything of the sort should play a role in deciding. John --66bff318_643c9869_17d67 Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline
To the original question, there's two reasons that = =5F=5FtoString() was deliberately omitted from enums:

1. To= discourage their use as =22fancy strings=22. Enums are their own type, i= ndependent of any other. Making them usable as 95% strings partially defe= ats their purpose.

I disagree with = the idea that we need to take this extreme of a stance when it comes to t= he notion of protecting the developer from themselves. There are a lot of= really value use cases where it makes sense to have a string-backed enum . Not allowing developers to cast it to a string isn't= doing anything but making people type =24enum->value&nbs= p; instead of (string)=24enum  -- so if someone wants t= o defeat their purpose this isn't stopping them. It is, however, making t= he language inconsistent because I literally have a enumeration defined b= y strings and there is literally no way to make PHP treat it like a strin= g. This makes APIs sloppy imo because consider something like this:
=
function foo(string=7CStringable =24bar) =7B=7D

Be= cause of these limitations this blows up into a much uglier thing in orde= r accomplish what IMO should be a straightforward task:

fun= ction fooThatWantsString(string=7CStringable=7CUnitEnum =24bar)
=7B
     if((=24bar instanceof UnitEnum) &= amp;& =21is=5Fstring(=24bar->value)) =7B
  &nb= sp;        throw InvalidArgumentExcept= ion('This is exactly the sort of thing we are trying to get rid of with t= ype hinting');
     =7D else =7B
=           =24bar =3D =24bar-= >value;
     =7D

 &nb= sp;   =24bar =3D (string)=24bar;
=7D

Of= course, you could also pass =24bar->value higher up the call stack bu= t it's much cleaner IMO to let the function call be smart enough to typec= ast as necessary. What's the point of a Stringable  int= erface if we can't actually implement =5F=5FtoString() for it=3F Note aga= in we can implement JsonSerializable  and nothing compl= ains when enum  serializes to a simple string.
2. We still intend to add associated values to enums at some= point (aka ADTs, aka tagged unions), and... we're not really sure yet if= that will impact =5F=5FtoString() at all. It may, it may not, we don't k= now. So for now we're keeping our options open by disallowing =5F=5FtoStr= ing(), in case it ends up being needed for some ADT-related behavior in t= he future.

=5F=5FtoString() should return a string, = if an enum literally represents a string constant it makes zero sense for= it to ever return anything but that string constant. I don't think this = is something ADTs or tagged unions or anything of the sort should play a = role in deciding.

John
--66bff318_643c9869_17d67--