Hello, internals!
What do you think about creating shorthand
number
forint|float
?
This is also related to allow all types of type-hints in the use-statement, like
use int|float as numeric;
Anyone interested in creating an RFC for this?
Olle
PS. Original thread here: https://externals.io/message/112209#112209
(dunno how to respond to an old thread when I don't have the original
message)
Hi Olle,
I appreciate your idea of introducing a similar concept of typedef.
What if you write an RFC explaining that concept. I can join you
however in co-authoring this request.
Seriously, I have had issues with writing such type again and again.
If you look at mixed type, it is indeed an alias of some union types.
Adding such an option to userland would lead to introduction of
various type hints. Plus, it will help devs write short hand aliases
for their intersection types.
Regards
Ahmad
Hello, internals!
What do you think about creating shorthand
number
forint|float
?This is also related to allow all types of type-hints in the use-statement,
likeuse int|float as numeric;
Anyone interested in creating an RFC for this?
Olle
PS. Original thread here: https://externals.io/message/112209#112209
(dunno how to respond to an old thread when I don't have the original
message)--
To unsubscribe, visit: https://www.php.net/unsub.php
number
type But frankly this seems a bit silly and reminds me too much of
JavaScript.
On Wed, Sep 28, 2022, 9:08 PM Hamza Ahmad office.hamzaahmad@gmail.com
wrote:
Hi Olle,
I appreciate your idea of introducing a similar concept of typedef.
What if you write an RFC explaining that concept. I can join you
however in co-authoring this request.Seriously, I have had issues with writing such type again and again.
If you look at mixed type, it is indeed an alias of some union types.
Adding such an option to userland would lead to introduction of
various type hints. Plus, it will help devs write short hand aliases
for their intersection types.Regards
Ahmad
Hello, internals!
What do you think about creating shorthand
number
forint|float
?This is also related to allow all types of type-hints in the
use-statement,
likeuse int|float as numeric;
Anyone interested in creating an RFC for this?
Olle
PS. Original thread here: https://externals.io/message/112209#112209
(dunno how to respond to an old thread when I don't have the original
message)--
To unsubscribe, visit: https://www.php.net/unsub.php
--
To unsubscribe, visit: https://www.php.net/unsub.php
2022-09-29 12:33 GMT+02:00, Ryan Jentzsch ryan.jentzsch@gmail.com:
number
type But frankly this seems a bit silly and reminds me too much of
JavaScript.
That's just an example. You can also consider use array|ArrayAccess as arraylike
, or such.
Olle
Sadly, I am disappointed with the way this suggestion has been looked down on.
2022-09-29 12:33 GMT+02:00, Ryan Jentzsch ryan.jentzsch@gmail.com:
number
type But frankly this seems a bit silly and reminds me too much
of
JavaScript.That's just an example. You can also consider
use array|ArrayAccess as arraylike
, or such.Olle
2022-09-29 5:08 GMT+02:00, Hamza Ahmad office.hamzaahmad@gmail.com:
Hi Olle,
I appreciate your idea of introducing a similar concept of typedef.
What if you write an RFC explaining that concept. I can join you
however in co-authoring this request.Seriously, I have had issues with writing such type again and again.
If you look at mixed type, it is indeed an alias of some union types.
Adding such an option to userland would lead to introduction of
various type hints. Plus, it will help devs write short hand aliases
for their intersection types.
Note that my suggestion here is NOT about a project-global type alias,
but an extension of the existing file-only alias, the use-statement.
This can also explain the lack of reaction. :) Internal devs might
already have consensus on the right way to proceed here, even if
there's no RFC yet.
Olle
On Fri, Sep 30, 2022 at 11:04 AM Olle Härstedt olleharstedt@gmail.com
wrote:
2022-09-29 5:08 GMT+02:00, Hamza Ahmad office.hamzaahmad@gmail.com:
Hi Olle,
I appreciate your idea of introducing a similar concept of typedef.
What if you write an RFC explaining that concept. I can join you
however in co-authoring this request.Seriously, I have had issues with writing such type again and again.
If you look at mixed type, it is indeed an alias of some union types.
Adding such an option to userland would lead to introduction of
various type hints. Plus, it will help devs write short hand aliases
for their intersection types.Note that my suggestion here is NOT about a project-global type alias,
but an extension of the existing file-only alias, the use-statement.
This can also explain the lack of reaction. :) Internal devs might
already have consensus on the right way to proceed here, even if
there's no RFC yet.Olle
--
To unsubscribe, visit: https://www.php.net/unsub.php
I don't know if file based type aliases make sense, but just spitballing
some ideas here.
// core php or perhaps some libraries
typedef number = int|float;
typedef number<number $min> = TypeDef::extend('number', static fn (number
$value, number $min) => $value >= $min);
typedef number<?number $min, number $max> = TypeDef::extend('number',
static fn (number $value, ?number $min, number $max) => ($min === null ||
$value >= $min) && $value <= $max);
typedef even = TypeDef::extend('number<?number $min, number $max>', static
fn (number $value) => $value % 2 === 0);
typedef positive = number<0>;
typedef negative = number<max: 0>;
typedef fraction = float<0, 1>;
typedef string<int $min> = TypDef::extend('string', static fn (string
$value, int $min) => strlen($value) >= $min);
typedef string<?int $min, int $max> = TypeDef::extend('string', static fn
(string $value, ?int $min, int $max) => length_is_between($value, $min,
$max));
typedef regex<string $expression> = TypeDef::extend('string', static fn
(string $value, string $regex) => preg_match($regex, $value));
namespace App\Domain;
typedef NonEmptyString = string<1>; // minimum length of 1
typedef LimitedString = string<null, 32>; // no minimum length, max length
of 32
// or typedef LimitedString = string<max: 32>; as alternative notation with
named parameters
typedef SomeToken = regex<'/a-z0-9{12}/i'>;
// only allows even numbers ranging from -100 to 100
function someFunction(even<-100, 100> $number) {}
namespace Elsewhere;
use App\Domain\NonEmptyString;
use App\Domain\LimitedString;
use App\Domain\SomeToken;
someFunction(102); // fails `$max` check from `number<min, max>`
someFunction(-99); // fails `% 2` check from `even`
I tried to use some consistency for the examples, by no means this is what
I think it must look like, just making sure the intent of the examples is
clear. This would be nothing more than syntactic sugar to what I'd
otherwise write in custom objects to validate types and values and ensure
type safety. This also doesn't take into account how operators should
behave or how autoloading could/should behave.
2022-09-30 12:15 GMT+02:00, Lynn kjarli@gmail.com:
On Fri, Sep 30, 2022 at 11:04 AM Olle Härstedt olleharstedt@gmail.com
wrote:2022-09-29 5:08 GMT+02:00, Hamza Ahmad office.hamzaahmad@gmail.com:
Hi Olle,
I appreciate your idea of introducing a similar concept of typedef.
What if you write an RFC explaining that concept. I can join you
however in co-authoring this request.Seriously, I have had issues with writing such type again and again.
If you look at mixed type, it is indeed an alias of some union types.
Adding such an option to userland would lead to introduction of
various type hints. Plus, it will help devs write short hand aliases
for their intersection types.Note that my suggestion here is NOT about a project-global type alias,
but an extension of the existing file-only alias, the use-statement.
This can also explain the lack of reaction. :) Internal devs might
already have consensus on the right way to proceed here, even if
there's no RFC yet.Olle
--
To unsubscribe, visit: https://www.php.net/unsub.php
I don't know if file based type aliases make sense, but just spitballing
some ideas here.// core php or perhaps some libraries typedef number = int|float; typedef number<number $min> = TypeDef::extend('number', static fn (number $value, number $min) => $value >= $min); typedef number<?number $min, number $max> = TypeDef::extend('number', static fn (number $value, ?number $min, number $max) => ($min === null || $value >= $min) && $value <= $max); typedef even = TypeDef::extend('number<?number $min, number $max>', static fn (number $value) => $value % 2 === 0); typedef positive = number<0>; typedef negative = number<max: 0>; typedef fraction = float<0, 1>; typedef string<int $min> = TypDef::extend('string', static fn (string $value, int $min) => strlen($value) >= $min); typedef string<?int $min, int $max> = TypeDef::extend('string', static fn (string $value, ?int $min, int $max) => length_is_between($value, $min, $max)); typedef regex<string $expression> = TypeDef::extend('string', static fn (string $value, string $regex) => preg_match($regex, $value)); namespace App\Domain; typedef NonEmptyString = string<1>; // minimum length of 1 typedef LimitedString = string<null, 32>; // no minimum length, max length of 32 // or typedef LimitedString = string<max: 32>; as alternative notation with named parameters typedef SomeToken = regex<'/a-z0-9{12}/i'>; // only allows even numbers ranging from -100 to 100 function someFunction(even<-100, 100> $number) {} namespace Elsewhere; use App\Domain\NonEmptyString; use App\Domain\LimitedString; use App\Domain\SomeToken; someFunction(102); // fails `$max` check from `number<min, max>` someFunction(-99); // fails `% 2` check from `even`
I tried to use some consistency for the examples, by no means this is what
I think it must look like, just making sure the intent of the examples is
clear. This would be nothing more than syntactic sugar to what I'd
otherwise write in custom objects to validate types and values and ensure
type safety. This also doesn't take into account how operators should
behave or how autoloading could/should behave.
Impressive repertoire of ideas, but probably out of scope from what I
was thinking of. :) Some call this "refinement types":
https://en.wikipedia.org/wiki/Refinement_type
Olle
2022-09-29 5:08 GMT+02:00, Hamza Ahmad office.hamzaahmad@gmail.com:
Hi Olle,
I appreciate your idea of introducing a similar concept of typedef.
What if you write an RFC explaining that concept. I can join you
however in co-authoring this request.Seriously, I have had issues with writing such type again and again.
If you look at mixed type, it is indeed an alias of some union types.
Adding such an option to userland would lead to introduction of
various type hints. Plus, it will help devs write short hand aliases
for their intersection types.Note that my suggestion here is NOT about a project-global type alias,
but an extension of the existing file-only alias, the use-statement.
This can also explain the lack of reaction. :) Internal devs might
already have consensus on the right way to proceed here, even if
there's no RFC yet.
Background:
Type aliases have been discussed several times. There's definitely interest, but like many things it runs into the problems of time and figuring out the details.
In particular, I don't get the sense that there's much appetite for file-local aliases. While that would have some benefit, it could lead to all kinds of confusion when then using code from another file. Consider:
A.php:
use int|float as number;
interface A
{
public function a(number $a) {}
}
B.php:
// Yeah, aliasing this is very helpful.
use (Request&Linkable)|(ServerRequest&Linkable)|array|null as input;
interface B
{
public function b(input $b) {}
}
C.php:
class C implements A, B
{
// Which of these to use?
public function a(int|float $a) {}
public function a(number $a) {}
// Or do I need to repeat the definition of "number" in every file?
// WTF do I do here? Do I have to repeat the entire definition either
// inline or in this file's "use" block? Both suck.
public function b(...)
}
This becomes even more of an issue when you start talking about function types, which is often mentioned as the primary use case.
type fn(int $a, string $b): Request as mycallback
function do(mycallback $callback) {}
So I have to duplicate the type def in every file now? This is not an improvement.
So we have to go with app-global aliases, but then... how do you handle resolution? Autoloading? Namespacing? Conflict resolution? I dunno, that's all hard, and that's where the conversation usually peters out.
The degenerate case you mention of simple type renaming has its own interesting implications, which are also a factor for the broader case. Specifically, does that create a new type unto itself, or does the difference get elided at compile time? For instance:
use int as userId;
use int as productId;
function a(userId $user) {
b($userId);
}
function b(productId $product) {
// ...
}
a(123);
Does this work? Is it a compile error for mismatched types (as in Go, which has this exact feature) or no? If it is, how do you make it work? Do you need explicit casts? If it does work, have you gained much since it's no more useful than docblocks? If it does work, how long before SA tools turn it into an error anyway and make everything more complicated? (Because you know they will.)
Does the same answer apply for longer type aliases like the nutty ones in the earlier examples?
These are the kinds of questions that need to be answered before any serious RFC could be attempted. Answers for them can certainly be found, but so far no one has really done the work, in particular around how to make aliases cleanly global. If you're interested in tackling that, fantastic; I think most people would be on board with it (especially for function types). But be aware it's a not-small puddle you're wading into.
(I think Danack had a writeup similar to this but it went a bit further; not sure where it is off hand, but he probably knows.)
--Larry Garfield
2022-09-30 17:16 GMT+02:00, Larry Garfield larry@garfieldtech.com:
2022-09-29 5:08 GMT+02:00, Hamza Ahmad office.hamzaahmad@gmail.com:
Hi Olle,
I appreciate your idea of introducing a similar concept of typedef.
What if you write an RFC explaining that concept. I can join you
however in co-authoring this request.Seriously, I have had issues with writing such type again and again.
If you look at mixed type, it is indeed an alias of some union types.
Adding such an option to userland would lead to introduction of
various type hints. Plus, it will help devs write short hand aliases
for their intersection types.Note that my suggestion here is NOT about a project-global type alias,
but an extension of the existing file-only alias, the use-statement.
This can also explain the lack of reaction. :) Internal devs might
already have consensus on the right way to proceed here, even if
there's no RFC yet.Background:
Type aliases have been discussed several times.
Ya ok, not what I could find in externals.io ^^
There's definitely
interest, but like many things it runs into the problems of time and
figuring out the details.In particular, I don't get the sense that there's much appetite for
file-local aliases. While that would have some benefit, it could lead to
all kinds of confusion when then using code from another file. Consider:A.php:
use int|float as number;
interface A
{
public function a(number $a) {}
}B.php:
// Yeah, aliasing this is very helpful.
use (Request&Linkable)|(ServerRequest&Linkable)|array|null as input;interface B
{
public function b(input $b) {}
}C.php:
class C implements A, B
{
// Which of these to use?
public function a(int|float $a) {}
public function a(number $a) {}
// Or do I need to repeat the definition of "number" in every file?
Yes, you would. That's the limit of my current suggestion. Same
semantics as use-statements.
// WTF do I do here? Do I have to repeat the entire definition either
// inline or in this file's "use" block? Both suck.
public function b(...)
Neither suck. :) Just "normal" inheritance boilerplate in the absence
of project-global type aliasing.
Do you have similar counter-examples for non-OOP code?
}
This becomes even more of an issue when you start talking about function
types, which is often mentioned as the primary use case.type fn(int $a, string $b): Request as mycallback
function do(mycallback $callback) {}
So I have to duplicate the type def in every file now? This is not an
improvement.
It's an improvement for readability, especially when repeated in one
file. But my suggestion does not include function-types, because
there's no such thing already in the system. Just to let use-statement
include more of already existing types. If function-types were added
later, they should be supported too, yes.
So we have to go with app-global aliases, but then... how do you handle
resolution? Autoloading? Namespacing? Conflict resolution? I dunno,
that's all hard, and that's where the conversation usually peters out.
Yeah, always better to have a clear limitation, is it not? :D
The degenerate case you mention of simple type renaming has its own
interesting implications, which are also a factor for the broader case.
Specifically, does that create a new type unto itself
No. Keep the same semantics of the current use-statement. But it could
be a future extension, sure. But then you need some kind of "factory"
way to produce those types. In FP they do it with "abstract types",
where the implementation of a type is hidden from outside the module.
In PHP, maybe with Foo::make() functions or such. Different
discussion.
or does the
difference get elided at compile time? For instance:use int as userId;
use int as productId;function a(userId $user) {
b($userId);
}function b(productId $product) {
// ...
}a(123);
Does this work? Is it a compile error for mismatched types (as in Go, which
has this exact feature) or no? If it is, how do you make it work? Do you
need explicit casts? If it does work, have you gained much since it's no
more useful than docblocks? If it does work, how long before SA tools turn
it into an error anyway and make everything more complicated? (Because you
know they will.)
Not sure I agree with you there. Obviously, static analyzers would
have to abide to the semantics of the core language, no...?
Does the same answer apply for longer type aliases like the nutty ones in
the earlier examples?These are the kinds of questions that need to be answered before any serious
RFC could be attempted.
Isn't an RFC a good place to document all these cases? I was thinking
that an RFC could be a good place even for things we do NOT want to
implement. to help pave the way for features we do.
Answers for them can certainly be found, but so far
no one has really done the work, in particular around how to make aliases
cleanly global. If you're interested in tackling that, fantastic; I think
most people would be on board with it (especially for function types). But
be aware it's a not-small puddle you're wading into.
I never had a need for such a feature tho. :d Although my motivation
for current concept is also dubious (transpilation to C, mainly).
Maybe generic-notation for arrays is more relevant to improve
type-hints, buuut that's another can of worms, and I didn't read up on
current discussion yet. :)
Thanks for the feedback, Larry! Can I still get karma to write it down
in the wiki? Again, not to necessarily encourage implementation, more
for documentation purpose. And I prefer to have it on the wiki, to
keep all the docs central.
Olle
After reading through all of the suggestions above, I have come to
this conclusion that all suggestion can be incorporated in the
following ways:
Types can exist in name spaces, Either in the global namespace or in
the user defined name spaces. If one wants to import a type from a
name space, it can easily use "use" statement per file. Alternatively,
it can include a namespace and it does all that handy job for the dev.
I agree with the idea of creating an RFC and document all use cases,
possible ways to implement and also the features that can be added
currently or will be left for the future scope.
Regards
Ahmad
2022-09-30 17:16 GMT+02:00, Larry Garfield larry@garfieldtech.com:
2022-09-29 5:08 GMT+02:00, Hamza Ahmad office.hamzaahmad@gmail.com:
Hi Olle,
I appreciate your idea of introducing a similar concept of typedef.
What if you write an RFC explaining that concept. I can join you
however in co-authoring this request.Seriously, I have had issues with writing such type again and again.
If you look at mixed type, it is indeed an alias of some union types.
Adding such an option to userland would lead to introduction of
various type hints. Plus, it will help devs write short hand aliases
for their intersection types.Note that my suggestion here is NOT about a project-global type alias,
but an extension of the existing file-only alias, the use-statement.
This can also explain the lack of reaction. :) Internal devs might
already have consensus on the right way to proceed here, even if
there's no RFC yet.Background:
Type aliases have been discussed several times.
Ya ok, not what I could find in externals.io ^^
There's definitely
interest, but like many things it runs into the problems of time and
figuring out the details.In particular, I don't get the sense that there's much appetite for
file-local aliases. While that would have some benefit, it could lead to
all kinds of confusion when then using code from another file. Consider:A.php:
use int|float as number;
interface A
{
public function a(number $a) {}
}B.php:
// Yeah, aliasing this is very helpful.
use (Request&Linkable)|(ServerRequest&Linkable)|array|null as input;interface B
{
public function b(input $b) {}
}C.php:
class C implements A, B
{
// Which of these to use?
public function a(int|float $a) {}
public function a(number $a) {}
// Or do I need to repeat the definition of "number" in every file?Yes, you would. That's the limit of my current suggestion. Same
semantics as use-statements.// WTF do I do here? Do I have to repeat the entire definition either
// inline or in this file's "use" block? Both suck.
public function b(...)Neither suck. :) Just "normal" inheritance boilerplate in the absence
of project-global type aliasing.Do you have similar counter-examples for non-OOP code?
}
This becomes even more of an issue when you start talking about function
types, which is often mentioned as the primary use case.type fn(int $a, string $b): Request as mycallback
function do(mycallback $callback) {}
So I have to duplicate the type def in every file now? This is not an
improvement.It's an improvement for readability, especially when repeated in one
file. But my suggestion does not include function-types, because
there's no such thing already in the system. Just to let use-statement
include more of already existing types. If function-types were added
later, they should be supported too, yes.So we have to go with app-global aliases, but then... how do you handle
resolution? Autoloading? Namespacing? Conflict resolution? I dunno,
that's all hard, and that's where the conversation usually peters out.Yeah, always better to have a clear limitation, is it not? :D
The degenerate case you mention of simple type renaming has its own
interesting implications, which are also a factor for the broader case.
Specifically, does that create a new type unto itselfNo. Keep the same semantics of the current use-statement. But it could
be a future extension, sure. But then you need some kind of "factory"
way to produce those types. In FP they do it with "abstract types",
where the implementation of a type is hidden from outside the module.
In PHP, maybe with Foo::make() functions or such. Different
discussion.or does the
difference get elided at compile time? For instance:use int as userId;
use int as productId;function a(userId $user) {
b($userId);
}function b(productId $product) {
// ...
}a(123);
Does this work? Is it a compile error for mismatched types (as in Go,
which
has this exact feature) or no? If it is, how do you make it work? Do
you
need explicit casts? If it does work, have you gained much since it's no
more useful than docblocks? If it does work, how long before SA tools
turn
it into an error anyway and make everything more complicated? (Because
you
know they will.)Not sure I agree with you there. Obviously, static analyzers would
have to abide to the semantics of the core language, no...?Does the same answer apply for longer type aliases like the nutty ones in
the earlier examples?These are the kinds of questions that need to be answered before any
serious
RFC could be attempted.Isn't an RFC a good place to document all these cases? I was thinking
that an RFC could be a good place even for things we do NOT want to
implement. to help pave the way for features we do.Answers for them can certainly be found, but so far
no one has really done the work, in particular around how to make aliases
cleanly global. If you're interested in tackling that, fantastic; I
think
most people would be on board with it (especially for function types).
But
be aware it's a not-small puddle you're wading into.I never had a need for such a feature tho. :d Although my motivation
for current concept is also dubious (transpilation to C, mainly).
Maybe generic-notation for arrays is more relevant to improve
type-hints, buuut that's another can of worms, and I didn't read up on
current discussion yet. :)Thanks for the feedback, Larry! Can I still get karma to write it down
in the wiki? Again, not to necessarily encourage implementation, more
for documentation purpose. And I prefer to have it on the wiki, to
keep all the docs central.Olle
--
To unsubscribe, visit: https://www.php.net/unsub.php
Very interesting
But I think that the original suggestion had a slimer scope than the
rest of the opinions, that is why I also agree that the "scope" should
be defined clearly, and provide the examples needed to clarify the
suggestion itself.
Cheers
2022-10-03 19:56 GMT+02:00, juan carlos morales dev.juan.morales@gmail.com:
Very interesting
But I think that the original suggestion had a slimer scope than the
rest of the opinions, that is why I also agree that the "scope" should
be defined clearly, and provide the examples needed to clarify the
suggestion itself.Cheers
Yep, agree. Got the karma to open an RFC now, will do it "later".
Olle