Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:112149 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 37148 invoked from network); 30 Oct 2020 19:28:04 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 30 Oct 2020 19:28:04 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id DD8E91804D1 for ; Fri, 30 Oct 2020 11:47:31 -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,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=3.4.2 X-Spam-Virus: No X-Envelope-From: Received: from NAM10-MW2-obe.outbound.protection.outlook.com (mail-mw2nam10olkn2037.outbound.protection.outlook.com [40.92.42.37]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Fri, 30 Oct 2020 11:47:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=DhsxWmm4MMG+dKsBz0sctmTFhATiXrV9PFd4voxTiNxekX/8mW0yCd7BpwAaNw1Tjh28GIXG6oyXsCT2eOV0154cg+6AC1SFugvBz7j2oq4UgK3oTXYg+Yajg3RZWRS4O6HQxADP1vbm8EGSGA+6DdUb1QXoylAEuJc772YZARPAGd887HlHF+6EU5xu3G4wWSeyoGMrPkMvdby6kLlZt7a2aBx4ETMsJWgrKc8boXQkEBJm3Wisw0WJPcbCvg/w9sIsgc0peGYVzkUOjnuU1B6Ver7EeIMh+cHRPZ38amMMXlmkBL+ELOGYd+lFMA61Ei2Y52FZkF6WAI0DLUoEOA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=a7Y5R0w7NBI1e9BwEyS0ODSHdCDf/4pnVOE+fNL3XvA=; b=SvH3VnXcKM66qboJh4R+ChyuIh9yi2QgNB0rNNpVFVnFpsVA9qFXLQHv4e2fMIcXoZwXVcsS/pQ/8bXCA1jZKJGWyYNGwUzgPtSGdFEMfZOsOlGKqXKFqnW/cj43RE4U1G4Mmw/Xv6QtDVWTkNZxPZSMpnd/E2AUOPkZFUnv36v6Q87RyFnHPfKhDQUTVqriZXHpfNot8oKQt3kr3WfFd9Qm1zxbGfRJs+b839SF2955A0YYwX3mrdCMljkPjw4jx56XMic1foWnc7+iwYBORIBiB6gyT8sWjOu+m8WqRO6wlw2QXGgQLirggm1gFWhMYx22SKEoqTG/DqeU/9G2eA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=outlook.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=a7Y5R0w7NBI1e9BwEyS0ODSHdCDf/4pnVOE+fNL3XvA=; b=AJHLCdhapP+bDWIj4SxLZXsI3mNZzihG9ekUcLNITjH3t6cb8llCwkzus1Fzl4vRGslCMY+Bhb/fAtkLCebVXFItLlcraHOaBIAzF0+GKzp52Chuggqh+vsXn0Q0ZUGworeFuACeZfn/7cNsJbHTajBhxF5i0t/UQmyptIHRP9pQHI3le+xikDnE5FMQNUnWKyQSR67GtmwTvI9PDEPEr7p9+f1MiDCxVBASil6hV4sUKxxbozOmXlO3zAhB+kiL91VnvUXkk5l/2des28SP5l8sASzG7TeMx20YrRVzJxubTQ5pGIRNOFXtndkLAEDI+7WFYaaNFH+Gs+a7WT+5xw== Received: from BN7NAM10FT013.eop-nam10.prod.protection.outlook.com (2a01:111:e400:7e8f::53) by BN7NAM10HT150.eop-nam10.prod.protection.outlook.com (2a01:111:e400:7e8f::301) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3520.17; Fri, 30 Oct 2020 18:47:29 +0000 Received: from BYAPR05MB5478.namprd05.prod.outlook.com (2a01:111:e400:7e8f::4e) by BN7NAM10FT013.mail.protection.outlook.com (2a01:111:e400:7e8f::156) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3520.17 via Frontend Transport; Fri, 30 Oct 2020 18:47:29 +0000 Received: from BYAPR05MB5478.namprd05.prod.outlook.com ([fe80::1520:24a9:8177:7990]) by BYAPR05MB5478.namprd05.prod.outlook.com ([fe80::1520:24a9:8177:7990%5]) with mapi id 15.20.3499.029; Fri, 30 Oct 2020 18:47:23 +0000 To: Rowan Tommins , PHP Internals List , Nicolas Grekas Thread-Topic: [PHP-DEV] List of attributes Thread-Index: AQHWlKduqAD4JLWTfUSbO6DleNAbtql92cYAgAAq64CAATgcAIAJ4ESAgBYMm8qAAZRFgIAEqHeBgAgHdACAABBagIADMPVM Date: Fri, 30 Oct 2020 18:47:23 +0000 Message-ID: References: , In-Reply-To: Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-incomingtopheadermarker: OriginalChecksum:60F2BA0968C33E7E251C47FC83BB2F0751328DD14D26C88C2A204EF5C3569235;UpperCasedChecksum:C116200F187C11FE16B7EB311DFE5D60644E271E75711DBA0D15E96F815F8A59;SizeAsReceived:7594;Count:44 x-ms-exchange-messagesentrepresentingtype: 1 x-tmn: [gcDK7AVIbrgeicn7TRLnKdfs/KKOvkDf] x-ms-publictraffictype: Email x-incomingheadercount: 44 x-eopattributedmessage: 0 x-ms-office365-filtering-correlation-id: 9d00dd08-eddd-4dbe-74cb-08d87d043d28 x-ms-traffictypediagnostic: BN7NAM10HT150: x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: 5C3Vd/d04l1ernjNs33qKM1Xij/X8k7DVHi2zIgjZHWtPkefVqzyk5e4AWJp5y3XYMH+XhDhfeIap48PvBjG6NMmwxA/mSc7VqEciXAqxNJfUK3dWa6rac0juNY9tVwaKfwxDQem3O0tlyekcBaft0iF1suH+pRi4w6DwzZMrohPE2ABaacf9Y8DDX9hvzrZg9lfyCjRIChTUpLTumjEWa3JtpFOyjC3ZVQUV19Xc10MEeIcsM19DZfcZkTPQWkX x-ms-exchange-antispam-messagedata: YylkmDQXoQNLkYnxnxxXH4ItRiDd/W2KPf7IQqwjuZyg8bjkH9PAsgAin2aFEugW/DX+uXg1U/aU2MjL+AvK0pOsbJAmBt/lHHpEK7Pj22kB6GMsO8rZ5vTASDLcDrp2FGKz2bXr5DueQCV772kmig== x-ms-exchange-transport-forked: True Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-AuthSource: BN7NAM10FT013.eop-nam10.prod.protection.outlook.com X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-CrossTenant-Network-Message-Id: 9d00dd08-eddd-4dbe-74cb-08d87d043d28 X-MS-Exchange-CrossTenant-originalarrivaltime: 30 Oct 2020 18:47:23.1828 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Internet X-MS-Exchange-CrossTenant-id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-rms-persistedconsumerorg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN7NAM10HT150 Subject: Re: [PHP-DEV] List of attributes From: theodorejb@outlook.com (Theodore Brown) Hi Rowan and Nicolas (and internals),=0A= =0A= On Wed, Oct 28, 2020 at 12:57 PM Rowan Tommins wr= ote:=0A= =0A= > On 28/10/2020 16:58, Nicolas Grekas wrote:=0A= > > about why we'd need nested attributes, here is a discussion about=0A= > > nested validation constraints:=0A= > > https://github.com/symfony/symfony/issues/38503=0A= > =0A= > Thanks, it's useful to see some real-world examples. As I suspected,=0A= > nearly all of these explicitly take a *list* of nested attributes,=0A= > not a single attribute.=0A= > =0A= > > While most of the constraints receive the nested constraints as=0A= > > simple array, |Collection| however requires a mapping (field to=0A= > > constraint) and is usually combined with other composite=0A= > > constraints, which gives us a second nesting level.=0A= > =0A= > There is much discussion of Collection as an edge case, but although=0A= > the nested attributes are indeed inside a mapping, the *value* of=0A= > that mapping is again a list of attributes. Single items are allowed,=0A= > but this seems to be a special case for convenience. ... This=0A= > reinforces my earlier suggestion (https://externals.io/message/111936#112= 109)=0A= > that #[Foo] in a nested context can simply imply an array of one=0A= > attribute,=0A= =0A= =0A= While passing all nested attributes as an array would at least enable=0A= consistent semantics, it has the notable disadvantage of preventing=0A= some use cases from being expressed in PHP's type system. Specifically,=0A= how would you express that an attribute parameter must be passed a=0A= single attribute of a particular type?=0A= =0A= For example, suppose a developer wants to create/use an attribute=0A= like the following:=0A= =0A= #[Limit(=0A= min: 10,=0A= max: 100,=0A= error: #[CustomError(message: "...", notify: true, withTrace: false= )]=0A= )]=0A= =0A= I would expect to be able to write the `Limit` attribute class like this:= =0A= =0A= #[Attribute]=0A= class Limit {=0A= public function __construct(=0A= public int $min,=0A= public int $max,=0A= public CustomError $error,=0A= ) {}=0A= }=0A= =0A= But if nested attributes are always passed as an array, the `$error`=0A= parameter would have to have an `array` type, which provides=0A= essentially no context about what is really required. The type system=0A= would be perfectly happy to allow an empty array, or an array with=0A= multiple values instead of the expected single `CustomError` attribute.=0A= =0A= It may be possible to enable static analysis type checks and IDE=0A= autocompletion by adding extra docblock annotations or attributes=0A= specifying that the array has to contain exactly one `CustomError`=0A= value, but this is a workaround requiring a lot more effort than=0A= should be necessary. Overall the dev experience becomes a lot worse=0A= for these use cases.=0A= =0A= =0A= On Wed, Oct 28, 2020 at 11:58 AM Nicolas Grekas wrote:=0A= =0A= > > The problem with this is that it results in inconsistent semantics,=0A= > > where the number of items in an attribute group results in a=0A= > > different type of value being passed. I.e. if you remove two of the=0A= > > three attributes from the list, suddenly the code will break since=0A= > > the `Assert\All` attribute is no longer being passed an array.=0A= > =0A= > Yes.=0A= > This would be solved by NOT accepting #[] inside attribute declarations.= =0A= > Since we borrowed from Rust, let's borrow this again:=0A= > http://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/h= tml/reference/attributes.html#attributes=0A= > =0A= > The Rust syntax accepts the #[] only on the outside of the declaration.= =0A= > The example above should be written as:=0A= >=0A= > #[Assert\All([=0A= > Assert\Email(),=0A= > Assert\NotBlank(),=0A= > Assert\Length(max: 100)=0A= > ])]=0A= > =0A= > The closing brackets () would be required to remove any ambiguity=0A= > with constants. Since constant expressions won't ever allow functions=0A= > in them, this isn't ambiguous with function calls.=0A= =0A= =0A= This does seem more readable and also avoids the grouped syntax=0A= inconsistency. On the other hand, presumably it would prevent ever=0A= supporting function calls in constant expressions. At present I'm not=0A= convinced constant expressions *should* support this, but nevertheless=0A= I have reservations about a syntax choice that would rule it out=0A= completely.=0A= =0A= Furthermore, the requirement of parentheses seems inconsistent with=0A= normal attribute declarations and `new ClassName` instantiations,=0A= where parentheses are optional.=0A= =0A= As I see it, we have the following other options:=0A= =0A= 1. Simply ban the grouped syntax in nested context. This has the=0A= downside of extra verbosity and that it may be unexpected/surprising=0A= for developers.=0A= =0A= 2. Drop support for attribute grouping before PHP 8 is finalized. Rust=0A= (which we borrowed the `#[]` syntax from) itself does not support this=0A= anyway. The primary downside of no attribute grouping is additional=0A= verbosity in some circumstances.=0A= =0A= Note: a number of people who voted for `#[]` expressed disfavor of=0A= attribute grouping, which was originally accepted only for the `<<>>`=0A= syntax with the qualification that it would be superseded by any other=0A= RFC that changes the syntax. [1]=0A= =0A= 3. Vote to switch to a less verbose syntax that avoids these issues.=0A= I.e. revert to `@@`, or alternatively to `##` (the latter would preserve=0A= forward compatibility). This would allow the same syntax to be used for=0A= both parent and nested attributes with identical semantics.=0A= =0A= The downside is that some tooling (e.g. PHP-Parser and PhpStorm) has=0A= already done work to support the `#[]` syntax and this would need to=0A= be changed (though removing attribute grouping will simplify the=0A= implementation for such tooling).=0A= =0A= Examples of option 3:=0A= =0A= @@Limit(=0A= min: 10,=0A= max: 100,=0A= error: @@CustomError(message: "...", notify: true, withTrace: false= )=0A= )=0A= =0A= // or=0A= =0A= ##Limit(=0A= min: 10,=0A= max: 100,=0A= error: ##CustomError(message: "...", notify: true, withTrace: false= )=0A= )=0A= =0A= =0A= Best regards, =0A= Theodore=0A= =0A= [1]: https://wiki.php.net/rfc/attribute_amendments#group_statement_for_attr= ibutes=