First, some background: several versions of PHP ago authors of
functions and methods could only restrict types to the array type or a
class/interface type. We slowly added some other types such as
callable and primitive types. These tools have been invaluable to
those who care about restricting the types of their inputs and
outputs. This type information reduces the code each author has to
write if they want to restrict to working with certain types and it
also provides a form of documentation. Overall these features have
been well received and are considered a good thing to do.
However, as we have added these new restrictions we still cannot
express exactly what types are permitted in some common cases.
- Return types cannot specify the function will return only type T or Null.
- Parameter types cannot express that an iterable type is required.
It's common for functions to work a stream of data and it is
irrelevant if it is an array or a Traversable object. - Parameter types cannot express that that the parameter must
implement two different interfaces. For example, requiring a parameter
to implement both Countable and Traversable cannot be done.
There are some common work-arounds to these issues:
- Omit the type information and rely on documentation.
- Check the parameter type inside the function (eg
assert(is_array($x) || $x instanceof Traversable)
) - Introduce a new type that embodies the restrictions. If this in an
interface it must be implemented by every object you hope to use the
restriction with.
In some cases these work-arounds are tolerable. However, some of them
are really painful.
- Requiring a new supertype is intrusive. Code cannot always be
changed to use the new supertype. For example:- Upstream projects that would not benefit from your changes.
- Primitives cannot be extended except by altering the engine.
In these cases a new type has to be introduced that proxies
behavior to the underlying object/primitive.
- Relying on documentation can lead to subtle and hard to diagnose
issues when it is used incorrectly. Erroring immediately is sometimes
preferable.
All of these issues I've outlined can be nicely resolved by adding two
new kinds of types to our system: union and intersection types. A
union type requires the variable to match at least one of the types.
An intersection type requires the variable to match all of the types.
The vertical par symbol (OR) is used for unions and ampersand (AND) is
used for intersections. For example:
function (A | B $var); would require $var to be either type A or type B.
function (A & B $var); would require $var to be type A and type B.
To accommodate the common use-case of returning some type or Null we
would need to formally allow Null
as an explicit type:
function (): T | Null;
Since this is a common use case some languages have a short-hand
notation to represent a union with Null:
Continued (hit send by hotkey accident):
First, some background: several versions of PHP ago authors of
functions and methods could only restrict types to the array type or a
class/interface type. We slowly added some other types such as
callable and primitive types. These tools have been invaluable to
those who care about restricting the types of their inputs and
outputs. This type information reduces the code each author has to
write if they want to restrict to working with certain types and it
also provides a form of documentation. Overall these features have
been well received and are considered a good thing to do.However, as we have added these new restrictions we still cannot
express exactly what types are permitted in some common cases.
- Return types cannot specify the function will return only type T or Null.
- Parameter types cannot express that an iterable type is required.
It's common for functions to work a stream of data and it is
irrelevant if it is an array or a Traversable object.- Parameter types cannot express that that the parameter must
implement two different interfaces. For example, requiring a parameter
to implement both Countable and Traversable cannot be done.There are some common work-arounds to these issues:
- Omit the type information and rely on documentation.
- Check the parameter type inside the function (eg
assert(is_array($x) || $x instanceof Traversable)
)- Introduce a new type that embodies the restrictions. If this in an
interface it must be implemented by every object you hope to use the
restriction with.In some cases these work-arounds are tolerable. However, some of them
are really painful.
- Requiring a new supertype is intrusive. Code cannot always be
changed to use the new supertype. For example:
- Upstream projects that would not benefit from your changes.
- Primitives cannot be extended except by altering the engine.
In these cases a new type has to be introduced that proxies
behavior to the underlying object/primitive.- Relying on documentation can lead to subtle and hard to diagnose
issues when it is used incorrectly. Erroring immediately is sometimes
preferable.All of these issues I've outlined can be nicely resolved by adding two
new kinds of types to our system: union and intersection types. A
union type requires the variable to match at least one of the types.
An intersection type requires the variable to match all of the types.
The vertical par symbol (OR) is used for unions and ampersand (AND) is
used for intersections. For example:function (A | B $var); would require $var to be either type A or type B. function (A & B $var); would require $var to be type A and type B.
To accommodate the common use-case of returning some type or Null we
would need to formally allowNull
as an explicit type:function (): T | Null;
Since this is a common use case some languages have a short-hand
notation to represent a union with Null:
function (): ?T;
Examples of such languages include Swift, C#, OCaml and Hack (though
the symbol is sometimes in the front and sometimes in the back.
Later today I will be submitting RFCs for each of these proposals.
Although they can work independently it is helpful to understand the
overall goal and how they fit together, which has been the purpose of
this email. Feedback for each RFC will belong in the thread for that
piece, but discussion about the ideas overall is better suited here.
Nothing to add other than +1, however, didn't you already write those?
https://wiki.php.net/rfc/nullable_types
https://wiki.php.net/rfc/union_types
Or is this just an announcement that these will be finalized now?
Btw. I am in favor of having the question mark as a suffix and not as a
prefix because it is more readable and more natural to type.
function fn(string? $str): bool?;
Declare a function with the name fn that takes a string argument that is
nullable which will return a bool or null.
That is exactly how I would think about the above while writing and
reading. :)
--
Richard "Fleshgrinder" Fussenegger
Nothing to add other than +1, however, didn't you already write those?
https://wiki.php.net/rfc/nullable_types
https://wiki.php.net/rfc/union_typesOr is this just an announcement that these will be finalized now?
Btw. I am in favor of having the question mark as a suffix and not as a
prefix because it is more readable and more natural to type.function fn(string? $str): bool?;
Declare a function with the name fn that takes a string argument that is
nullable which will return a bool or null.That is exactly how I would think about the above while writing and
reading. :)--
Richard "Fleshgrinder" Fussenegger
I have written them but later they will be formally moved to Under
Discussion and will create new threads for them here on the mailing
list.
Nothing to add other than +1, however, didn't you already write those?
https://wiki.php.net/rfc/nullable_types
https://wiki.php.net/rfc/union_typesOr is this just an announcement that these will be finalized now?
Btw. I am in favor of having the question mark as a suffix and not as a
prefix because it is more readable and more natural to type.function fn(string? $str): bool?;
Declare a function with the name fn that takes a string argument that is
nullable which will return a bool or null.That is exactly how I would think about the above while writing and
reading. :)--
Richard "Fleshgrinder" FusseneggerI have written them but later they will be formally moved to Under
Discussion and will create new threads for them here on the mailing
list.
Awesome, let me know if I can be of any help, even if it is only proof
reading. This is an extremely valuable addition that I want to have.
May I suggest you the following article (more of a starting point into
Ceylon actually) regarding this topic:
http://ceylon-lang.org/documentation/tour/types/
Ceylon is very nicely designed regarding union and intersection types
and I think it can add value to learn from these people too. I am not
handing out this because I think that you don't know what you are doing.
The opposite is the case. However, Ceylon is very young and I don't
think many people know of it; while you probably already know all the
oldies who support union and intersection types. ;)
--
Richard "Fleshgrinder" Fussenegger
Hi!
May I suggest you the following article (more of a starting point into
Ceylon actually) regarding this topic:
There was a time where PHP was considered a good beginner's language.
Now it seems we want to pivot and target category theory PhDs instead? :)
Stas Malyshev
smalyshev@gmail.com
Hi!
May I suggest you the following article (more of a starting point into
Ceylon actually) regarding this topic:There was a time where PHP was considered a good beginner's language.
Now it seems we want to pivot and target category theory PhDs instead? :)
Hahaha funny how many people consider Ceylon to be too academic. :)
I personally just want to make the language more consistent, secure (in
terms of introduction of bugs and error handling), and better suited for
real enterprise and high performance usage. And of course learn a
shitload about language design along the way. ;)
--
Richard "Fleshgrinder" Fussenegger
Am 13.04.2016 um 22:24 schrieb Stanislav Malyshev smalyshev@gmail.com:
Hi!
May I suggest you the following article (more of a starting point into
Ceylon actually) regarding this topic:There was a time where PHP was considered a good beginner's language.
Now it seems we want to pivot and target category theory PhDs instead? :)Stas Malyshev
smalyshev@gmail.com
PHP has and will retain the invaluable capability of not requiring types.
If you have weak types, which you have by default, it's just about as easy as it was the last 15 years.
The only thing which changed is that not only internal functions but also user functions can impose some limits on what is being accepted. I could understand your complains if it were completely new and not even internal functions ever rejected inputs based on types [or rather how well-formed numeric strings they are].
The only thing a bit harder (requiring a little understanding of types), is when you edit files with strict types active. But still, if that's too much of pain for a beginner, he's free to disable them.
Types are designed in a way enhancing the languages experience while avoiding nearly every impact for people who want to ignore them.
And that's great.
And that's why we shall continue on improving our optional type system.
Thanks,
Bob
Hi!
Types are designed in a way enhancing the languages experience while
avoiding nearly every impact for people who want to ignore them.
This is not true. If it's in language, you have to understand it to be
able to use the language. Nobody writes code in vacuum - there are
libraries, communities, teams, best practices, tutorials, etc. So if
(hypothetically) you want to introduce algebraic types in PHP, then
since that moment you can not really be a PHP programmer if you don't
understand algebraic types. Otherwise you would not be able to
communicate with the rest of the community, understand and use code
written by others, contribute to projects, etc.
And that's why we shall continue on improving our optional type
system.
That's a very broad statement which which everybody agrees - who's
against improving? Who'd want to make the type system worse? Nobody.
The specifics are more complicated - do we really need complex type
expressions in PHP to the point of inventing micro-language with its own
syntax to just specify a type? I don't think so.
--
Stas Malyshev
smalyshev@gmail.com
Types are designed in a way enhancing the languages experience while
avoiding nearly every impact for people who want to ignore them.This is not true. If it's in language, you have to understand it to be
able to use the language. Nobody writes code in vacuum - there are
libraries, communities, teams, best practices, tutorials, etc. So if
(hypothetically) you want to introduce algebraic types in PHP, then
since that moment you can not really be a PHP programmer if you don't
understand algebraic types. Otherwise you would not be able to
communicate with the rest of the community, understand and use code
written by others, contribute to projects, etc.
I agree. This is an important point. I should include it in my RFC[1]
that argues pro nullable return but contra nullable params or unions.
May I copy-paste?
Tom
Hi!
May I suggest you the following article (more of a starting point into
Ceylon actually) regarding this topic:
There was a time where PHP was considered a good beginner's language.
Now it seems we want to pivot and target category theory PhDs instead? :)
A language that is usable primarily by beginners will only be useful for
beginners. Non-beginners will shun it, or simply grow out of it and leave.
A language that is usable only by PhDs will be useful only for PhDs.
Beginners won't be able to comprehend it.
A language that is usable by both beginners and PhDs, and can scale a
user from beginner to PhD within the same language, will be used by both.
Doing that is really hard. And really awesome. And the direction PHP has
been trending in recent years is in that direction. Which is pretty
danged awesome. :-)
--
--Larry Garfield
May I suggest you the following article (more of a starting point into
Ceylon actually) regarding this topic:
There was a time where PHP was considered a good beginner's language.
Now it seems we want to pivot and target category theory PhDs instead? :)
Well it's well above my M.Sc in Digital Systems ... but that was gained
in 1982 and it seems even my wife's primary school charges are already
trained to a higher level of programming.
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
Continued (hit send by hotkey accident):
First, some background: several versions of PHP ago authors of
functions and methods could only restrict types to the array type or a
class/interface type. We slowly added some other types such as callable
and primitive types. These tools have been invaluable to those who care
about restricting the types of their inputs and outputs. This type
information reduces the code each author has to write if they want to
restrict to working with certain types and it also provides a form of
documentation. Overall these features have been well received and are
considered a good thing to do.However, as we have added these new restrictions we still cannot
express exactly what types are permitted in some common cases.
- Return types cannot specify the function will return only type T
or Null.- Parameter types cannot express that an iterable type is required.
It's common for functions to work a stream of data and it is irrelevant
if it is an array or a Traversable object.- Parameter types cannot express that that the parameter must
implement two different interfaces. For example, requiring a parameter
to implement both Countable and Traversable cannot be done.There are some common work-arounds to these issues:
- Omit the type information and rely on documentation.
- Check the parameter type inside the function (eg
assert(is_array($x) || $x instanceof Traversable)
)- Introduce a new type that embodies the restrictions. If this in an
interface it must be implemented by every object you hope to use the
restriction with.In some cases these work-arounds are tolerable. However, some of them
are really painful.
- Requiring a new supertype is intrusive. Code cannot always be
changed to use the new supertype. For example:
- Upstream projects that would not benefit from your changes.
- Primitives cannot be extended except by altering the engine.
In these cases a new type has to be introduced that proxies
behavior to the underlying object/primitive.- Relying on documentation can lead to subtle and hard to diagnose
issues when it is used incorrectly. Erroring immediately is sometimes
preferable.All of these issues I've outlined can be nicely resolved by adding two
new kinds of types to our system: union and intersection types. A union
type requires the variable to match at least one of the types. An
intersection type requires the variable to match all of the types. The
vertical par symbol (OR) is used for unions and ampersand (AND) is used
for intersections. For example:function (A | B $var); would require $var to be either type A or type B. function (A & B $var); would require $var to be type A and type B.
To accommodate the common use-case of returning some type or Null we
would need to formally allowNull
as an explicit type:function (): T | Null;
Since this is a common use case some languages have a short-hand
notation to represent a union with Null:function (): ?T;
Examples of such languages include Swift, C#, OCaml and Hack (though the
symbol is sometimes in the front and sometimes in the back.Later today I will be submitting RFCs for each of these proposals.
Although they can work independently it is helpful to understand the
overall goal and how they fit together, which has been the purpose of
this email. Feedback for each RFC will belong in the thread for that
piece, but discussion about the ideas overall is better suited here.
COOLNESS!! +10
I really like this mindset of a general solution to these stricter types.
I think it will present a more consistent "interface" for using types
across PHP in the future.
In general, this is a more general and elegant solution to nullable type
in properties, hints, and return types.
I am eager to see what you have in those RFCs. ?
--
Stephen