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