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 aUser
, for example. (BTW, thank you for not calling out my nonsensical example of operations on aUserId
; 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