Re: bikeshed: Typed Aliases

From: Date: Tue, 10 Sep 2024 08:31:59 +0000
Subject: Re: bikeshed: Typed Aliases
References: 1 2 3 4 5 6 7 8 9 10 11 12 13  Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message
On Tue, Sep 10, 2024, at 10:00, Mike Schinkel wrote:
>> On Sep 9, 2024, at 5:35 PM, Rowan Tommins [IMSoP] <[email protected]> wrote:
>> 
>> On 09/09/2024 19:41, Mike Schinkel wrote:
>>> In Go you cannot add or subtract on a typedef without casting to the 
>>> underlying type.  I would definitely prefer that to be relaxed, but only
>>>  if it is relaxed via an explicit opt-in, e.g. something maybe like 
>>> this:
>>> 
>>> typedef UserId: int operations: +, -, *, /;
>>> typedef UserName: string operations: .;
>> I think this would stray into some of the same complexity as operator overloads on objects,
>> in terms of the types and values allowed. For instance:
>> 
> I tend to agree that allowing operations may be too much for an initial scope given that it is
> unlike anything else in the current language and with no other languages offering an equivalent
> AFAIK.
> 
> I would however make the distinction that it is unlike operator overloading because the big
> concern was what constituted an operation for any given type could be too subjective.  In your
> example of Metres it is pretty obvious, but not at all obvious for a User,
> for example.  (BTW, thank you for not calling out my nonsensical example of operations on a
> UserId; when I wrote that I clear was not thinking about if they were relevant, doh!)
> 
> However give the suggestion regarding operations with a typedef, the only operations that I
> suggested would be valid would be the ones already defined on the underlying type, (when I mentioned
> other operations I was thinking of methods — see my the following example with round — not
> operators so that is not the same as operator overload.) For example:
> 
> /**
>  * Currency is an int so for example in USD 1 
>  * unit of currency not a dollar but a cent.
>  */
> typedef Currency: int operations: +,-,*,/,round;
> function CalcTotal(Currency $subTotal, Currency $shipping, float $tax):Currency {
>    return round($subTotal*(1+$tax/100),0) + $shipping;
> }

This is very similar (behaviorally) to what I wanted to do with GMP. Overloading GMP would have
given you int-like powers in your type. The biggest negative feedback I got was that people would
abuse it still; so we need some way to prevent abuse. If you read Jordon's operator overloads
RFC, and my GMP overloading RFC, you can see that users basically need a way to define how to
operate over even just an integer.

For example, Dollar(1) + Euro(3) is what? Or even Dollar(1) + 1? How does a developer prevent
someone from doing something nonsensical? The language needs to enforce some rules and/or the
developer needs to be able to define them. These rules need to be intuitive and well reasoned, IMHO.

>> typedef Metres: int;
>> 
>> assert( Metres(2) +  Metres(1) === Metres(3) ); // most obvious
>> assert( Metres(2) + 1 === Metres(3) ); // seems pretty clear
> 
> Both of those are in line with what I was suggesting.
>> 
>> 
>> $_GET['input'] = '1';
>> assert( Metres(2) + $_GET['input'] === Metres(3) ); // might be more
>> controversial
>> 
>> 
> I would not consider this appropriate as it has two levels of conversion and could thus end up
> with unintended edge cases. To do the above I think you would have to either convert or typecast:
> 
> assert( Metres(2) + intval($_GET['input']) === Metres(3) ); 
> assert( Metres(2) + (int)$_GET['input'] === Metres(3) ); 
>> 
>> 
>> typedef Feet: int;
>> assert( Metres(2) + Feet(1) === Metres(3) ); // almost certainly a bad idea
>> 
>> 
> This would be operator overloading where knowledge of the conversion between meters and feet
> would be required, and that is not in any way in scope with what I was suggesting.  
> 
> As an aside, I am against userland operator overloading as I have seen in other languages that
> operator overloading gets abused and results in code that is a nightmare to maintain. OTOH, I would
> support operator overloading in specific cases, e.g. a Measurement class in PHP core
> could allow adding meters to feet, assuming such a proposal were made and all other aspects of the
> RFC were of the nature to be voted in.
> 
> To reiterate on typedefs, what I was suggesting was that if an operation was explicitly allowed
> — e.g. + — then anything that would work with the underlying type — such as adding an int 1
> would work without typecasting and yet still result in the typedef type, e..g. Meters(2) + 1 results
> in a value of type Meters. (note that I corrected your spelling of 'Meters' here. ;-) 
> 
> But I agree, this is probably a bridge too far for a first RFC for typedefs. 
> 
>>> type MyNewType: Foo
>>> type MyAlias = Foo
>> I know this was only an example, but as a general point, I think we should avoid concise
>> but cryptic differences like this. PHP is generally keyword-heavy, rather than punctuation-heavy,
>> and I think that's a valid style which we should keep to.
>> 
> Here, I also tend to agree WRT PHP.  Was just pointing out for sake of laying out other options
> that were implied not to exist.
> 
> -Mike

In other news, I'm highly considering refactoring the records RFC to be a typedef RFC; the
infrastructure is there; we just need more restrictions.

— Rob


Thread (25 messages)

« previous php.internals (#125488) next »