On Sat, Sep 7, 2024, at 12:07 PM, Rowan Tommins [IMSoP] wrote:
> On 7 September 2024 17:23:13 BST, Davey Shafik <m...@daveyshafik.com> wrote:
>>
>>My point is that if you talk about type DEFs, you now have this feature where 
>>you can input one type and get something that encapsulates it, and it seems 
>>weird that enums would LOOK similar In type hint usage and function 
>>differently.
>
> Personally, I would prefer to go the other way: make typedefs, like 
> enums, something you explicitly construct / cast to, rather than 
> something that implicitly coerces any compatible value. 
>
> Like enums, I would want to use typedefs to prevent accidental mixing 
> of values (e.g. a name where a reference number was expected, or a size 
> in pixels where a size in centimetres was expected). That use is 
> compromised if every scalar value is silently accepted for any matching 
> typedef.
>
> Regards,
> Rowan Tommins
> [IMSoP]

There's a couple of different use cases floating around close to each other 
here.

One is a type *alias*, which is just "a way to type less."

The other is a type *def*, which creates a new for-reals type that you can 
check at runtime.

They are closely related, but serve different purposes.  While an alias could 
make sense file-local or app-wide, in practice a def only makes sense app-wide.

Whether we want to have one or the other or both is a subjective question.  
Personally I'd be fine with both, as I see them serving different purposes.

eg:

typealias Foo: Bar|Baz;

Foo is now a compile time copy-paste for Bar|Baz, meaning this is totally valid:

class A {
  public Foo $a;
}

class B {
  public Bar|Baz $a;
}

The other direction is:

typedef UserId: int;

UserID is now an object that consists of just an int, but can be type checked 
against.  What's unclear is if you can do other int-y things to them (add, 
subtract, etc.), or if it's really just a shorthand for

readonly class UserId {
  public function __construct(public int $value) {}
}

I could see an argument for either.  If we had operator overloads, I would 
absolutely go for the latter; make all of those other int-y things opt-in.  
Once we get pattern matching, as noted a few months ago, it could be quite 
powerful to allow patterns as a validation on a typedef of that sort.

typedef UserId: int is >0;

Though that opens up all kinds of interesting questions about a typedef based 
on another typedef, if that's a form of inheritance or not, etc.  Again, I'm 
not sure if Rob wants to go there or not, but it's a place my brain has gone 
before. :-)

We may want to focus just on aliases for now, but design them in such a way 
that they do not cause an issue for typedefs in the future.  (Eg, using the 
`typealias` keyword instead of just `type`.)

--Larry Garfield

Reply via email to