> On Sep 9, 2024, at 5:35 PM, Rowan Tommins [IMSoP] <imsop....@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; } > 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