Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:118095 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 24884 invoked from network); 25 Jun 2022 12:54:02 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 25 Jun 2022 12:54:02 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id A0F1E1804BD for ; Sat, 25 Jun 2022 07:44:18 -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=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS15169 209.85.128.0/17 X-Spam-Virus: No X-Envelope-From: Received: from mail-vs1-f49.google.com (mail-vs1-f49.google.com [209.85.217.49]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sat, 25 Jun 2022 07:44:18 -0700 (PDT) Received: by mail-vs1-f49.google.com with SMTP id h38so4940786vsv.7 for ; Sat, 25 Jun 2022 07:44:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=basereality-com.20210112.gappssmtp.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=j2PxgXOPKFtRu/ecMUiiv5rD4ZKGhtBwr4vtdgByqlY=; b=lfQeWwP6B78scs9Ue8crKZS7NytgLlLeI0fADa1zcttPbAn/eA0QgCdzn5uSUu0pCM J1+/ifARnCSjEb8s+8RiF5NMVFWQ31vLtmHnjH73HRoIQHNtDs+xS8cMvQcrrRi91z4L EYA/h5c3Lz5N2RUwP18Lii62Z/gHW6FxPbU2uowuNLa6TVcJq7BAjp+/rPc0ZoZHyrmn A0lZ/I09w5YE8y92naPu2GXYiuZS7hv129SuevKJiDdFdywCo+BYZ2CVhE/thLtxvBF3 fhDo/IPWckZrB1jOnIFn/eAKBHqbxYbW+8gvKgw7LDBVTXlEGlAUi8KJioueAeT5+pzO MgBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=j2PxgXOPKFtRu/ecMUiiv5rD4ZKGhtBwr4vtdgByqlY=; b=CTFKFF/W1JrU7mHxIqIkB9EBNesuw1DmN8QcXwswVEY96syKjJ+cXx3MZ2KR6Qnp1q d1XpAtw1EWo7DPjEk0Y8fwTrv1HhTGPJ4jncValEzJs3nmcQjvUpcxj9IxBDl6kAdVLZ rvObj7mbxH9aijXhkcvs/91067pFth9EVdhChSCOdZFN2GaOTPif53RJQc+BoU5Pt3lb RgGfhwAIVzMxJlUBQYttgj67UbpOKNlHDXZdu0qGgKxzZz7FivbtFoYUUS8CO+AlFqi9 hdoG/eUPPk6VDL5zjBBJmz65/3RJXdfXrC4+RiOGj47VN9+EhN28jCbxtx2TcQpS9TOw 3ATA== X-Gm-Message-State: AJIora8DZPxnSbSFXNJa8HwrN0aCPv6Ve8Grly+3qtVq3/+xMPyK/VDY GlDn3LDV2xUnFDjAtV3gN9X7Lv0bATLXlW6+q3GHyMt2Mh4= X-Google-Smtp-Source: AGRyM1t9nHXemEQNlnxuzHqUv3TqLzfr5l9txzZAhKWksm47ev+rDctOX7KasWLUvxoyRbebPabVjRh0f71YvswXRL4= X-Received: by 2002:a67:c501:0:b0:354:5326:4fba with SMTP id e1-20020a67c501000000b0035453264fbamr1459893vsk.42.1656168257341; Sat, 25 Jun 2022 07:44:17 -0700 (PDT) MIME-Version: 1.0 References: <9C11261B-B9D0-4342-81EB-60276B3036E5@php.net> In-Reply-To: Date: Sat, 25 Jun 2022 15:44:03 +0100 Message-ID: To: Nicolas Grekas Cc: PHP Internals List Content-Type: text/plain; charset="UTF-8" Subject: Re: [PHP-DEV] [RFC] [Under Discussion] Auto-implement Stringable for string backed enums From: Danack@basereality.com (Dan Ackroyd) Hi Nicolas, On Fri, 24 Jun 2022 at 17:38, Nicolas Grekas wrote: > > I'm now considering withdrawing the RFC because I don't see a way forward > that could be consensual enough. Just in general, I think changes to the type system are always going to take longer than a few weeks to discuss. There are always going to be subtle implications that need to be thought through thorougly. Also, the argument for a change to the type system like this should be based on why it's the right thing to do for new code that is being written. Although obviously everyone who has a large code base wants to be able to upgrade to the latest and greatest PHP to get the new features at the lowest cost in changing code, imo it's more important long term to get the language right, rather than putting too much emphasis on lowering the cost of upgrading. >> Derick wrote: >> My concern is that auto implementing __toString, will lead to decreasing >> type safety of enums in weak typing mode, since they get auto-casted to >> string when passed to a function accepting strings. This effectively adds >> more type juggling cases. > > I don't share this concern: if an API accepts a string and the engine can > provide a string, function/method calls are not the only place were type comparisons are done. My understanding is that if this RFC is passed, then the situation would be: Foo::Bar == 'Bar'; // true Baz::Bar == 'Bar'; // true Baz::Bar == Foo::Bar; // false Which is not obviously the correct thing. There is also the issue that callbacks called internally by the engine are always in weak/coercive mode. That means that changes to weak/coercive can leak through to code that wants to always be in strict mode. > It would be great if we could find ways to make it easier for general-purpose > libraries to support enums without cluttering libraries with if/else blocks > and without changing existing interfaces in a backwards-incompatible way. There's two parts going on here. First, yes, enums could probably be easier to work with, and we should probably be looking how to do that. Second is an argument about how easy it should be to retrofit new features to existing code. Although I can see why people would want that, it's a lot harder to justify it. > As experienced on the Symfony repository, this problem is especially visible > at the boundary of libraries: when some component accepts a string as input, > ppl want them to also accept backed-enums. This usually means that they > propose widening the accepted types of some method to make them work > seamslessly with enums. Doing that appears to be a violation of the "open for extension, closed for modification" principle. If you want to change the type signature, introducing a new function is almost certainly the 'right' thing to do, even if that means more work for people with large existing code-bases. e.g. Change: class Foo { function bar(string $quux) {} } To this: class Foo { function bar(string $quux) {} function barEx(string|SomeEnum $quux) {} } And eventually deprecate the original bar method. > but we also have a case in Symfony where defining service > definitions in yaml doesn't work with enums because there > is no way to express the "->value" part. I very strongly think the limitations of what yaml config file choices were made in a downstream project should not influence the design of a the type system of an upstream project. I'm pretty sure that a successful RFC isn't going to need to mention that problem. > If other ppl share my concerns and have a proposal, please let us know. It might be hard to have a one size fits all rule, hard-coded in the engine as people genuinely have different views of what enums are. One idea that I think may have been mentioned before (and if I recall, shot down pretty hard) would be to allow people to register cast callbacks similar to the code below. That would allow people who view enums as special constants to cast away, and those view enums as types, to not cast. This currently would be problematic for the same reason that PHP ini settings are problematic; without a module or package system, any settings that affect how the engine behave affect all code that is run, rather than being limited to just the library that wants to enable that setting. Which is a problem that keeps rearing it's head. Maybe someone sponsoring some blue-sky research on how feasible a module/package system could be, would make addressing problems similar to the one here be easier to work on. cheers Dan Ack enum Suit: string { case Hearts = 'H'; case Spades = 'S'; } function foo(string $bar) { var_dump($bar); } function cast_backed_enum_to_string(BackedEnum $enum): string { return $enum->value; } register_cast_callback( BackedEnum::class, // source type 'string', // target type cast_backed_enum_to_string(...) ); foo(Suit::Hearts); // Engine sees we have a BackedEnum and that foo wants a // string, so calls cast_backed_enum_to_string to do the conversion