Re: [RFC] [Discussion] Literal Scalar Types
| From: | David Gebler | Date: | Mon, 15 Jun 2026 02:29:09 +0000 |
| Subject: | Re: [RFC] [Discussion] Literal Scalar Types | ||
| References: | 1 2 3 4 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-131253@lists.php.net to get a copy of this message | ||
On Mon, Jun 15, 2026 at 3:27 AM David Gebler <davidgebler@gmail.com> wrote:
> On Mon, Jun 15, 2026 at 3:13 AM Seifeddine Gmati <azjezz@carthage..software>
> wrote:
>
>> On Mon, 15 Jun 2026 at 03:03, David Gebler <davidgebler@gmail.com> wrote:
>> >
>> > On Mon, Jun 15, 2026 at 2:24 AM Seifeddine Gmati
>> <azjezz@carthage.software> wrote:
>> >>
>> >> Hello Internals,
>> >>
>> >> I'd like to start the discussion on a new RFC adding literal scalar
>> >> types to PHP.
>> >
>> >
>> > Prima facie, I feel like enums already do what this aims to achieve,
>> much better.
>> >
>> >>
>> >>
>> >> - RFC:
>> >> https://wiki.php.net/rfc/literal_scalar_types
>> >> - Implementation:
>> >> https://github.com/php/php-src/pull/22314
>> >>
>> >> Thanks,
>> >> Seifeddine.
>>
>> Hi David,
>>
>> I agree enums are the better fit for a lot of cases. but not all.
>>
>> 1. describing APIs that already exist.
array_filter's
>> $mode really
>> accepts 0|1|2, but it's typed
>> int because that's all the type
>> system can say today. we can't retype it as an enum without breaking
>> every caller. a literal union lets the signature state the actual
>> contract.
>>
>
> This is probably the strongest case (and should be mentioned on the RFC, I
> think), though I'm not sure it's a sufficient justification for the scope
> of change.
>
>
>> 2. ad-hoc / open value sets. for a library, "ascii"|"utf-8" would need
>> its own named symbol ( enum BorderStyle { case Ascii; case Utf8
>> }, a
>> new file, an import ) for what is really two strings. and because an
>> enum is a closed set, adding a third style later breaks any consumer
>> that match-es over it without a default. widening the union on a
>> parameter ( "ascii"|"utf-8"|"unicode" ) is contravariant, so
>> it breaks
>> nobody.
>>
>
> I'm not so convinced on this point. You add a new case to an enum, that
> library's API isn't inherently broken. Users passing Ascii or Utf8 per the
> original case-set remain valid. The only code that breaks there is code
> that assumes the enum would never gain another case and the same could be
> said of code matching on string literals without a default. And if
> "ascii"|"utf-8" is what a library exposes, consumers may treat that as
> exhaustive, whereas an enum doesn't inherently break as a type hint. A set
> that's *expected* probably shouldn't be an enum, but the strength of an
> enum is precisely that it's a (probably) closed set of values. On the
> flip-side, if a set of values is genuinely open-ended, a closed set of
> scalar literal unions as a type isn't going to help.
>
Apologies for typo of omission in the above paragraph, I meant to say "A
set that's expected to grow probably shouldn't be an enum"
>
>
>
>> 3. scalar interop. a literal value is the scalar, so it works as an
>> array key, compares with ===, round-trips through json, etc. enum
>> cases are objects and don't.
>>
>
> I think backed enums already cover this through value exposure.
>
>
>>
>> so they overlap a lot, but literal unions reach things enums
>> structurally can't: existing scalar APIs, and open sets that grow
>> without a BC break.
>>
>> Cheers,
>> Seifeddine.
>>
>