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 internals+get-125488@lists.php.net 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] <imsop.php@rwec.co.uk> 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

« previous php.internals (#125488) next »