Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:125463 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 C34E21A00BD for ; Sat, 7 Sep 2024 00:46:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1725670122; bh=J5NbAcUtf/HaxsqpyaYnk5wjzbkQiatecUl3grhnNfQ=; h=From:Subject:Date:In-Reply-To:Cc:To:References:From; b=BlgMK1N35jwrrnuYUfvNJtAOo9RLtyRnFKK49LAU0q3If+4JkJJDYhJ/b7c1eGgc3 8nl1wMZmApbnoXxtw3wlG2+af8Ap43Oht7IfGPv0xWkEEjsR2wutrexUQ1OmlZwOjJ Y4RyI0wwzWV2rSoG7R1FaNvu9t3WTIQ7LtyUvL64zCXT+qLQU6mNvwiyfXaPIKZF1E n1HMY8z2f8yW4eI+8nYtFLyiGhePrsiVULg1VkHIQgSWCU+qwQt/lH8xCm3/OoFR0/ /v/kxmuSK1/qj0FTl7hy/EOumvbZyLQIaKtMk6iuRIJj/g7StYMXblHB04ccQcCpX0 qbfA1iJhYMB3w== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 3B44B180054 for ; Sat, 7 Sep 2024 00:48:41 +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=4.7 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DMARC_NONE,HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE, SPF_SOFTFAIL autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-pg1-f173.google.com (mail-pg1-f173.google.com [209.85.215.173]) (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, 7 Sep 2024 00:48:40 +0000 (UTC) Received: by mail-pg1-f173.google.com with SMTP id 41be03b00d2f7-7c1324be8easo2619707a12.1 for ; Fri, 06 Sep 2024 17:46:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=daveyshafik-com.20230601.gappssmtp.com; s=20230601; t=1725670001; x=1726274801; darn=lists.php.net; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:sender:from:to:cc:subject:date:message-id:reply-to; bh=jJM32pWitOx9M2neh+vPX2oJBGVTMsQVrdYct7/aRzA=; b=yFD0KZSvOg20KIw89gvRYd5yKMAWp9uvSdL9h5j/Vd616+v3v5i6lLACDBgjS4WV3M nc08pSWRQPaviHFcn2tfvbapZnFxqXag3dzsE4t9Vb8ttERBI37lueIle6kSLKz6ERIt qS8V5v8UUii35+ILD9bS1JIqTJBeyipZIFJud+aIUMixTGDLkJ2RnF/HljjEYrSNIOCk Tp6yL5VL7QdF8tDRZIYFh99F1nnakBwP+sINcHcGbE5+t4VX7wDskPKenstslamNTYlO ygWJg2Rvg1RlWykzz69CAlex3LV8+4DE+r6OAtSQYHbhT0f2h6p0ieDDT1rfongJcPtb itSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1725670001; x=1726274801; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:sender:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=jJM32pWitOx9M2neh+vPX2oJBGVTMsQVrdYct7/aRzA=; b=Uu4J5eGV9Mq+PVpaG6Cc2aTpYx4jRQwyj4CVSIXUxBXGHC6jiyLdEJbFvohFVYL2f/ rE7pwP2VPYnZkgjvU14tTd0jA0SAxtqeWzGUaa9ignpVHfk8Pk4PuRDiqierYSEkPrSd TV+gMbRBFtHviMbiLCgxZrWO5CWaJtkgX3OwfCoNv5yi42DCQeEPFrIJkLlCqCM8aiU3 gpKg/Of3PvR+ohzJWuveXMfs3T6Dzuu1V4gEvxSUFp4JukPLPlBFX2cGdKAcRHTj8Y6U dzAZZBVCbAVYyFhqqbcsSGzlCRR6WKBoeDkzFbS53Fk80ubcgf7qzaeHVKRn1x6lLm34 1rAw== X-Gm-Message-State: AOJu0Ywtdr7MTr4Ehg7eLs5+V1FKYytV0SsWHyJK68e/ejQ//9rj2WTz J3hzrRR/HbsbJ2ajyc/Si8UkwAE+3UJ8xxgpjd4uaWqgaq36SQqQnHb8SWwoO54cABqnTeK9UyG g X-Google-Smtp-Source: AGHT+IEg7CNw4LkGZOrT4pp88AzCxvPyfbWH48QqyWyIKPYXrDVpQGNV8/avwowouI1H6Zb37wQatQ== X-Received: by 2002:a17:902:e5ce:b0:1fa:97ec:3a4 with SMTP id d9443c01a7336-206ee939e31mr72561475ad.8.1725670000063; Fri, 06 Sep 2024 17:46:40 -0700 (PDT) Received: from smtpclient.apple ([73.35.192.19]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-20710e10eccsm684945ad.37.2024.09.06.17.46.38 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 06 Sep 2024 17:46:39 -0700 (PDT) Sender: Davey Shafik Message-ID: <928A2984-6035-4DA6-9EA7-12E85237C270@php.net> Content-Type: multipart/alternative; boundary="Apple-Mail=_C5D8F62B-1A0D-458E-8774-71D566B1470A" Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3776.700.51\)) Subject: Re: [PHP-DEV] bikeshed: Typed Aliases Date: Fri, 6 Sep 2024 17:46:28 -0700 In-Reply-To: Cc: Levi Morrison via internals To: Rob Landers References: <0fa39535-f22d-4eba-b4df-90abe39e683a@app.fastmail.com> <79e58673-50ec-461e-a998-736b020e4287@app.fastmail.com> X-Mailer: Apple Mail (2.3776.700.51) From: davey@php.net (Davey Shafik) --Apple-Mail=_C5D8F62B-1A0D-458E-8774-71D566B1470A Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On Sep 6, 2024, at 16:40, Rob Landers wrote: >=20 >=20 >=20 > On Sat, Sep 7, 2024, at 01:34, Larry Garfield wrote: >> On Fri, Sep 6, 2024, at 6:27 PM, Rob Landers wrote: >>=20 >> >> I suspect there's also other edge case bits to worry about, = particularly if trying to combine a complex alias with a complex type, = which could lead to violating the DNF rule. For example: >> > >> > Oh, DNF is the bane of my existence with this RFC=E2=80=94I don't = want to mess=20 >> > this up. I'll see you at the end of the example, though. >> > >> >>=20 >> >> typealias Foo: (Bar&Baz)|Beep; >> >>=20 >> >> use (Bar&Baz)|Beep as Foo; >> >>=20 >> >> function narf(Foo&Stringable $s) {} >> >>=20 >> >> With the compile time approach, that would expand to = `(Bar&Baz)|Beep&Stringable`, which is not a valid type def. >> > >> > I can see how you arrived at this, but I think you may have missed = a=20 >> > step, since the entirety of Foo will be &'d with Stringable. >> > >> > Foo =3D (Bar & Baz) | Beep >> > >> > want: (Foo) & Stringable >> > >> > expand Foo: ((Bar & Baz) | Beep) & Stringable >> > >> > Which can be reduced to the following in proper DNF (at least, it=20= >> > compiles=E2=80=94https://3v4l.org/0bMlP): >> > >> > (Beep & Stringable) | (Bar & Baz & Stringable) >> > >> > It's probably a good idea to update the RFC explaining how = expansion works. >>=20 >> Woof. We're not "fixingup" anyone's DNF elsewhere. I cannot speak = for everyone, but I'd be perfectly fine not doing any magic fixing for = now, and then debating separately if we should do it more generally. = Just doing it for aliases doesn't seem like the best plan. >>=20 >> --Larry Garfield >>=20 >=20 > Oh, we're definitely not "fixingup" the expression to DNF... more like = spending some time in the RFC showing how the expansion is the same = execution as with a DNF expression to prove that it is a valid type = expression. >=20 > =E2=80=94 Rob My main struggle with this is readability. As much as I want custom = types (and type aliases is a good chunk of the way there), the main = issue I have is understanding what the valid inputs are: function foo(Status $string): void { } How do I know that Status is a) not a class, b) that I can fulfill the = requirement with a string, and/or maybe any object with __toString(), or = maybe it=E2=80=99s ints? Or objects or enums? Even with file-local aliases (which I would definitely prefer to avoid) = we will most likely rely on developer tooling (e.g. IDEs and static = analyzers) to inform the developer what the right input types are. I would very much prefer to either go all in with an Enum-like (which = means that we can hang methods on to the value) or we need to = distinguish between type hints for class-likes and type hints for = not-class-likes (*Bar anyone?). Expanding on type-class-likes: within the type methods, $this->value = would refer to the original value, any operators would follow the _same_ = rules as either the original values type (e.g. $int =3D 4; $string =3D = =E2=80=9Cfoo=E2=80=9D; $int . $string =3D=3D =E2=80=9C4foo", or call = __toString() in all the normal places for strings if defined). type Stringable: string|int { public function __toString(): string { return (string) $this->value; // original value } // Add Stringable methods here }. So, with that in mind=E2=80=A6 I=E2=80=99d also like to open up the = ability for Enums to be fulfilled by the backed value, that is: function foo(Bar $bar): void { } Where Bar is: enum Bar: string { case BAZ =3D 'baz'; case BAT =3D =E2=80=98bat'; } And you can call `foo()` like: foo(=E2=80=98baz=E2=80=99) and Bar::BAZ = will be passed in.=20 I realize I=E2=80=99m opening a barn down here, but I just don=E2=80=99t = see file-local type aliases as that useful, and while I like the = functionality of type-class-likes, I think they would add more non-class = behavior (in addition to enums) for things that look like classes if we = don=E2=80=99t add some sort of identifier. I=E2=80=99d much rather that = we add backed-value to enum casting, and at least make that more = consistent with this functionality if we=E2=80=99re going to conflate = the syntax. - Davey= --Apple-Mail=_C5D8F62B-1A0D-458E-8774-71D566B1470A Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8

On= Sep 6, 2024, at 16:40, Rob Landers <rob@bottled.codes> = wrote:



On Sat, Sep 7, = 2024, at 01:34, Larry Garfield wrote:
On = Fri, Sep 6, 2024, at 6:27 PM, Rob Landers = wrote:

>> I suspect there's also = other edge case bits to worry about, particularly if trying to combine a = complex alias with a complex type, which could lead to violating the DNF = rule.  For example:
>
> Oh, DNF = is the bane of my existence with this RFC=E2=80=94I don't want to = mess 
> this up. I'll see you at the end of the = example, = though.
>
>> 
>= > typealias Foo: = (Bar&Baz)|Beep;
>> 
>> = use (Bar&Baz)|Beep as = Foo;
>> 
>> function = narf(Foo&Stringable $s) = {}
>> 
>> With the compile = time approach, that would expand to `(Bar&Baz)|Beep&Stringable`, = which is not a valid type def.
>
> I = can see how you arrived at this, but I think you may have missed = a 
> step, since the entirety of Foo will be = &'d with Stringable.
>
> Foo =3D = (Bar & Baz) | Beep
>
> want: (Foo) = & Stringable
>
> expand Foo: ((Bar = & Baz) | Beep) & = Stringable
>
> Which can be reduced to = the following in proper DNF (at least, it 
> = compiles=E2=80=94https://3v4l.org/0bMlP):
>
> (Beep & Stringable) | (Bar & Baz & = Stringable)
>
> It's probably a good = idea to update the RFC explaining how expansion = works.

Woof.  We're not "fixingup" = anyone's DNF elsewhere.  I cannot speak for everyone, but I'd be = perfectly fine not doing any magic fixing for now, and then debating = separately if we should do it more generally.  Just doing it for = aliases doesn't seem like the best = plan.

--Larry = Garfield


Oh, we're definitely not "fixingup" the = expression to DNF... more like spending some time in the RFC showing how = the expansion is the same execution as with a DNF expression to prove = that it is a valid type expression.

=E2=80=94 = Rob

My main struggle with this is = readability. As much as I want custom types (and type aliases is a good = chunk of the way there), the main issue I have is understanding what the = valid inputs are:

function foo(Status $string): = void { }

How do I know that Status is a) not a = class, b) that I can fulfill the requirement with a string, and/or maybe = any object with __toString(), or maybe it=E2=80=99s ints? Or objects or = enums?

Even with file-local aliases (which I = would definitely prefer to avoid) we will most likely rely on developer = tooling (e.g. IDEs and static analyzers) to inform the developer what = the right input types are.

I would very much = prefer to either go all in with an Enum-like (which means that we can = hang methods on to the value) or we need to distinguish between type = hints for class-likes and type hints for not-class-likes (*Bar = anyone?).

Expanding on type-class-likes: within = the type methods, $this->value would refer to the original value, any = operators would follow the _same_ rules as either the original values = type (e.g. $int =3D 4; $string  =3D =E2=80=9Cfoo=E2=80=9D; $int . = $string =3D=3D =E2=80=9C4foo", or call __toString() in all the normal = places for strings if = defined).


type Stringable: = string|int {
     public function __toString(): = string
     {
      =     return (string) $this->value; // original = value
     }

  =    // Add Stringable methods = here
}.

So, with that in mind=E2=80=A6 = I=E2=80=99d also like to open up the ability for Enums to be fulfilled = by the backed value, that is:

function foo(Bar = $bar): void { }

Where Bar = is:

enum Bar: string {
  =   case BAZ =3D 'baz';
    case BAT =3D = =E2=80=98bat';
}

And you can = call `foo()` like: foo(=E2=80=98baz=E2=80=99) and  Bar::BAZ will be = passed in. 

I realize I=E2=80=99m opening = a barn down here, but I just don=E2=80=99t see file-local type aliases = as that useful, and while I like the functionality of type-class-likes, = I think they would add more non-class behavior (in addition to enums) = for things that look like classes if we don=E2=80=99t add some sort of = identifier. I=E2=80=99d much rather that we add backed-value to enum = casting, and at least make that more consistent with this functionality = if we=E2=80=99re going to conflate the = syntax.

- Davey
= --Apple-Mail=_C5D8F62B-1A0D-458E-8774-71D566B1470A--