> 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;
}
> 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