There's always a lot of talk about types in the PHP community.
Specifically, many developers want property types, generics, function
signature types, union and intersection types, and more. Those talks
(and RFCs) always end with the same result: "We can't do it because
performance issues."
Has there ever been a discussion about adding some of those features
syntactically, but ignoring them during runtime? At least until someone
finds a performant way to check them at runtime. That way we could have
advanced type checking in our editors at least.
The idea will sound familiar to TypeScript users. It works great for
that language.
I'm excited to hear your opinions.
On Tue, Jun 5, 2018 at 4:23 PM Rudolph Gottesheim r.gottesheim@loot.at
wrote:
There's always a lot of talk about types in the PHP community.
Specifically, many developers want property types, generics, function
signature types, union and intersection types, and more. Those talks
(and RFCs) always end with the same result: "We can't do it because
performance issues."Has there ever been a discussion about adding some of those features
syntactically, but ignoring them during runtime? At least until someone
finds a performant way to check them at runtime. That way we could have
advanced type checking in our editors at least.The idea will sound familiar to TypeScript users. It works great for
that language.I'm excited to hear your opinions.
DbC style has no performance issue at all. In addition, you can perform
much better validation than simple type checks.
function f($username) {
assert(is_string($username) && preg_match('\A[a-z]\z', $username);
....
}
--
Yasuo Ohgaki
yohgaki@ohgaki.net
On Tue, Jun 5, 2018 at 2:22 AM Rudolph Gottesheim r.gottesheim@loot.at
wrote:
There's always a lot of talk about types in the PHP community.
Specifically, many developers want property types, generics, function
signature types, union and intersection types, and more. Those talks
(and RFCs) always end with the same result: "We can't do it because
performance issues."Has there ever been a discussion about adding some of those features
syntactically, but ignoring them during runtime? At least until someone
finds a performant way to check them at runtime. That way we could have
advanced type checking in our editors at least.The idea will sound familiar to TypeScript users. It works great for
that language.
It's an interesting compromise, but I worry about the confusion it may sow,
particularly for incoming programmers from languages that do enforce such
things - such as Java.
Has there ever been a discussion about adding some of those features
syntactically, but ignoring them during runtime? At least until someone
finds a performant way to check them at runtime. That way we could have
advanced type checking in our editors at least.
You can have that today: https://preprocess.io/
The main thing that would missing would be a mapping of source file +
line to the running code, which would make debugging harder.
cheers
Dan
There's always a lot of talk about types in the PHP community.
Specifically, many developers want property types, generics, function
signature types, union and intersection types, and more. Those talks
(and RFCs) always end with the same result: "We can't do it because
performance issues."Has there ever been a discussion about adding some of those features
syntactically, but ignoring them during runtime? At least until
someone finds a performant way to check them at runtime. That way we
could have advanced type checking in our editors at least.
Hi,
I believe this is part of the original aim of Hack-Lang: the additional
type features of that language are not part of the run-time, but checked
by a static analysis tool offline. A number of languages have similar
setups - Python and Dart both have the types as offline and/or
development-mode-only features. Indeed, PHP seems to have gone a very
unusual route in having a dynamic language with type constraints which
are effectively always-on assertions.
One of the problems with moving PHP to this offline-checking model is
that people will expect new type constraints to work like existing ones,
so may be caught out by them not being checked at run-time. Worse,
static checks may not be able to detect certain violations; I don't know
much about Hack's model, but I understand it includes both different
levels of strictness, and restrictions on dynamic language features -
things like references, "variable variables", and non-object callables.
I do think it's an interesting question to think about though.
Regards,
--
Rowan Collins
[IMSoP]
Why would something like this not work?
strict class MyClass
{
protected int $foo = 1;
public string $bar = "strict keyword in front of class allows/enforces
strict properties";
private string $isItReallyThatDifficult = "to implement this?";
}
On Tue, Jun 5, 2018 at 4:17 PM, Rowan Collins rowan.collins@gmail.com
wrote:
There's always a lot of talk about types in the PHP community.
Specifically, many developers want property types, generics, function
signature types, union and intersection types, and more. Those talks (and
RFCs) always end with the same result: "We can't do it because performance
issues."Has there ever been a discussion about adding some of those features
syntactically, but ignoring them during runtime? At least until someone
finds a performant way to check them at runtime. That way we could have
advanced type checking in our editors at least.Hi,
I believe this is part of the original aim of Hack-Lang: the additional
type features of that language are not part of the run-time, but checked by
a static analysis tool offline. A number of languages have similar setups -
Python and Dart both have the types as offline and/or development-mode-only
features. Indeed, PHP seems to have gone a very unusual route in having a
dynamic language with type constraints which are effectively always-on
assertions.One of the problems with moving PHP to this offline-checking model is that
people will expect new type constraints to work like existing ones, so may
be caught out by them not being checked at run-time. Worse, static checks
may not be able to detect certain violations; I don't know much about
Hack's model, but I understand it includes both different levels of
strictness, and restrictions on dynamic language features - things like
references, "variable variables", and non-object callables.I do think it's an interesting question to think about though.
Regards,
--
Rowan Collins
[IMSoP]
Why would something like this not work?
strict class MyClass
{
protected int $foo = 1;
public string $bar = "strict keyword in front of class allows/enforces
strict properties";
private string $isItReallyThatDifficult = "to implement this?";
}
The problem is not in defining what code has type annotations, it's what to
do with them afterwards.
The performance hit comes from the fact that every time you run:
$foo->bar = $baz;
The engine now needs to check whether $foo is a class with type
constraints, and what the type constraint of bar is, and whether the type
of $baz matches that constraint. The answer will be "no constraint" most of
the time, but it doesn't know that until it checks, at run-time, every time.
Nor is it just straight-forward assignments that would need to change,
there are knock-on effects across the language, such as assignment by
reference:
strict class MyClass
{
public int $foo;
public string $bar;
}
$a = new MyClass;
$inst =& $a->foo; // If this is allowed...
$inst = 'bad'; // ...then this needs to error
$s = 'good';
$a->bar =& $s; // And if this is allowed...
$s = 42; // ... then this needs to error
The previous proposal for typed properties simply raised errors when you
tried to use reference assignment with any typed property, which feels like
an arbitrary restriction to me. The alternative is to allow every variable
in the language to carry type constraint information. I mused some more on
this here: http://rwec.co.uk/q/php-type-system
In short, yes, it really is that difficult.
Regards,
Rowan Collins
[IMSoP]
Thanks Rowan for the detailed explanation.
I thought that leveraging __get
/ __set
internally would have addressed
many of the type checking issues that you mentioned.
I've used __get/__set in userland to enforce property types and hoped that
an internal C based solution would something that is reasonable to code and
implement.
Also, can anyone in internals respond to this inquiry?
https://github.com/php/php-src/pull/1797#issuecomment-394434391
On Wed, Jun 6, 2018 at 4:00 AM Rowan Collins rowan.collins@gmail.com
wrote:
Why would something like this not work?
strict class MyClass
{
protected int $foo = 1;
public string $bar = "strict keyword in front of class
allows/enforces strict properties";
private string $isItReallyThatDifficult = "to implement this?";
}The problem is not in defining what code has type annotations, it's what
to do with them afterwards.The performance hit comes from the fact that every time you run:
$foo->bar = $baz;
The engine now needs to check whether $foo is a class with type
constraints, and what the type constraint of bar is, and whether the type
of $baz matches that constraint. The answer will be "no constraint" most of
the time, but it doesn't know that until it checks, at run-time, every time.Nor is it just straight-forward assignments that would need to change,
there are knock-on effects across the language, such as assignment by
reference:strict class MyClass
{
public int $foo;
public string $bar;
}$a = new MyClass;
$inst =& $a->foo; // If this is allowed...
$inst = 'bad'; // ...then this needs to error$s = 'good';
$a->bar =& $s; // And if this is allowed...
$s = 42; // ... then this needs to errorThe previous proposal for typed properties simply raised errors when you
tried to use reference assignment with any typed property, which feels like
an arbitrary restriction to me. The alternative is to allow every variable
in the language to carry type constraint information. I mused some more on
this here: http://rwec.co.uk/q/php-type-systemIn short, yes, it really is that difficult.
Regards,
Rowan Collins
[IMSoP]
On Fri, Jun 8, 2018 at 9:29 AM, Ryan Jentzsch ryan.jentzsch@gmail.com
wrote:
Thanks Rowan for the detailed explanation.
I thought that leveraging__get
/__set
internally would have addressed
many of the type checking issues that you mentioned.
I've used __get/__set in userland to enforce property types and hoped that
an internal C based solution would something that is reasonable to code and
implement.Also, can anyone in internals respond to this inquiry?
https://github.com/php/php-src/pull/1797#issuecomment-394434391
Added type checking to __get and __set is one of the primary reasons for a
downvote of the typed properties RFC (
https://wiki.php.net/rfc/typed-properties)
Marco Pivetta
Also, can anyone in internals respond to this inquiry? https://github.com/
php/php-src/pull/1797#issuecomment-394434391
For ease of reference, that comment says:
Is there a document somewhere that summarizes the reasons why this
proposal was rejected? Have any of the items been addressed since then?
I would be happy to be proved wrong, but I think the answer is almost
certainly "no, but feel free to write one". Documentation is notoriously
the thing that gets put off most easily, and documentation of a
discussion is just not going to be at the top of anyone's todo list. But,
all the discussions are public - on that PR thread, and on the discussion
of the RFC on this list (available through any of several archives) - so
theoretically anyone could go through and summarise the key points.
I know that's not what you want to hear, but it's just human nature - we
had the discussion, reached a conclusion, and moved on with the next topic.
Regards,
Rowan Collins
[IMSoP]
On Fri, Jun 8, 2018 at 10:50 AM, Rowan Collins rowan.collins@gmail.com
wrote:
Also, can anyone in internals respond to this inquiry?
https://github.com/
php/php-src/pull/1797#issuecomment-394434391For ease of reference, that comment says:
Is there a document somewhere that summarizes the reasons why this
proposal was rejected? Have any of the items been addressed since then?I would be happy to be proved wrong, but I think the answer is almost
certainly "no, but feel free to write one". Documentation is notoriously
the thing that gets put off most easily, and documentation of a
discussion is just not going to be at the top of anyone's todo list. But,
all the discussions are public - on that PR thread, and on the discussion
of the RFC on this list (available through any of several archives) - so
theoretically anyone could go through and summarise the key points.I know that's not what you want to hear, but it's just human nature - we
had the discussion, reached a conclusion, and moved on with the next topic.
From what I remember, the key points were:
- No support for types on static properties.
- No support for taking references to typed properties.
- Performance: Feature was not entirely free if not used.
FTR, Bob and me plan to bring this RFC back up for PHP 7.3 soon, with
support for static properties and for references. A mostly finished
implementation has been lying around for a while already, so we think it's
time to wrap this up and give it another try.
Nikita
FTR, Bob and me plan to bring this RFC back up for PHP 7.3 soon, with
support for static properties and for references. A mostly finished
implementation has been lying around for a while already, so we think it's
time to wrap this up and give it another try.
I presume you mean 7.4, since 7.3 is in alpha already, and this is quite a
major change?
But good to hear there's still will to work on this; I shall be interested
to hear the details of where this will take the language.
Regards,
Rowan Collins
[IMSoP]
On Fri, Jun 8, 2018 at 1:28 PM Rowan Collins rowan.collins@gmail.com
wrote:
FTR, Bob and me plan to bring this RFC back up for PHP 7.3 soon, with
support for static properties and for references. A mostly finished
implementation has been lying around for a while already, so we think
it's
time to wrap this up and give it another try.I presume you mean 7.4, since 7.3 is in alpha already, and this is quite a
major change?But good to hear there's still will to work on this; I shall be interested
to hear the details of where this will take the language.Regards,
Rowan Collins
[IMSoP]
AFAIK, alpha1 was tagged but it still didn't branch off master. That'll
only happen on July 17th. (https://wiki.php.net/todo/php73)
With that said, basically any RFC that goes to vote before July 3rd should
still be on time to make it into 7.3.
Regards,
Pedro
On Fri, Jun 8, 2018 at 1:28 PM Rowan Collins rowan.collins@gmail.com
wrote:I presume you mean 7.4, since 7.3 is in alpha already, and this is quite a
major change?AFAIK, alpha1 was tagged but it still didn't branch off master. That'll
only happen on July 17th. (https://wiki.php.net/todo/php73)With that said, basically any RFC that goes to vote before July 3rd should
still be on time to make it into 7.3.
I'm partly just surprised because the list has been so quiet recently; is
there actually a long list of previously undiscussed features that people
are going to try to get into 7.3 at the last minute?
Maybe I'm being over-cautious, but it feels like landing big features like
this just before beta would make any testing of alpha releases rather
pointless.
Regards,
Rowan Collins
[IMSoP]
Den 2018-06-08 kl. 17:31, skrev Rowan Collins:
On Fri, Jun 8, 2018 at 1:28 PM Rowan Collins rowan.collins@gmail.com
wrote:I presume you mean 7.4, since 7.3 is in alpha already, and this is quite a
major change?AFAIK, alpha1 was tagged but it still didn't branch off master. That'll
only happen on July 17th. (https://wiki.php.net/todo/php73)With that said, basically any RFC that goes to vote before July 3rd should
still be on time to make it into 7.3.I'm partly just surprised because the list has been so quiet recently; is
there actually a long list of previously undiscussed features that people
are going to try to get into 7.3 at the last minute?Maybe I'm being over-cautious, but it feels like landing big features like
this just before beta would make any testing of alpha releases rather
pointless.Regards,
Maybe one could argue that given the not so fat feature list for 7.3,
it alleviates the testing of the alpha when bringing in new features
(given that they are not so many of course).
I also think it's a welcome addition that makes the 7.3 release more
attractive.
r//Björn
...
Has there ever been a discussion about adding some of those features
syntactically, but ignoring them during runtime?
That's what Hack does, and one of the main reasons we dropped Hack in
favor of PHP.
PHP is a reflective language - if we add e.g. generics or property
type-hints, omitting run-time reflection and/or run-time type-checks
would be inconsistent with PHP as a language in general.
Inconsistencies in a language are surprising and generally "bad" - if
type-hints lead to run-time type-checks, it's natural to expect that
to work predictably no matter where you type-hint. You shouldn't have
to learn where or when type-hints actually work at run-time and where
they don't.
Similarly, if type-hints are reflected, it's natural to expect all
type-hints to exist in the reflection model somewhere, anywhere that
type-hinting is possible. You shouldn't have to search the manual to
learn that type-hints aren't reflected for properties for some reason,
perhaps because it just hasn't been implemented yet.
Much of the "good" that we expect to be able to accomplish with
generics, for example, won't be possible (or won't make sense) without
being consistently reflected and run-time type-checked.
For example, in a DI container, I'd expect to be able to do something like this:
class Container {
public function get<T>(?string $name): T {
// ...
}
// ...
}
When calling get(), I'd expect a type-check for the the generic
return-type T, to protect me against internal errors in the Container
implementation - if it returns the wrong type, I want it to fail
immediately at that point, rather than potentially exiting the
call-stack that made this error traceable, making this extremely
difficult to debug.
Similarly, if we had property type-hints:
class Foo {
int $bar;
}
$foo = new Foo();
$foo->bar = "oops";
Here, I'd expect a type-check when assigning to $bar - omitting that
would be extremely bad, as, very likely, by the time something else
fails because this object is in an invalid state, we've exited the
call stack where the bad value was assigned, making this potentially
very difficult to debug.
I'd also expect to be able to reflect on the property-types in a DI
container, or perhaps in a class that maps form post-data to
properties and performs conversions, etc.
I'm the author of the generics RFC and one of the property-type RFCs,
and both of those RFCs call for both reflection and run-time
type-checking, for the sake of keeping the language consistent.
Hack made some very regrettable decisions in this area, and ultimately
those features were useful at design-time only, for IDE-support - but
we have php-doc for that purpose, and in my opinion, adding those
features before (or unless) we're willing/able to also make them work
consistently with the language, does more harm than good. Making these
features appear to be language features, when in fact that they're
only implemented in the parser and ignored by the interpreter, would
make for an extremely confusing experience.
Hi Rasmus,
While I agree with your general point regarding consistency, I just want to
take issue with sentence:
Hack made some very regrettable decisions in this area, and ultimately
those features were useful at design-time only, for IDE-support - but
we have php-doc for that purpose, and in my opinion, adding those
features before (or unless) we're willing/able to also make them work
consistently with the language, does more harm than good.
As far as I know, every other language which has added type annotations to
a dynamically typed language has done so either using an offline tool
(treating them like compiler warnings), or as a debug-only run-time flag
(treating them like assertions). The creator of "gradual typing", which is
explicitly the basis of Python's type annotations, and at least implicitly
used by many other languages, specifically stated that it was intended to
be checked at compile-time, not run-time [1]:
A gradual type checker is a type checker that checks, at compile-time,
for type errors in some parts of a program, but not others, as directed by
which parts of the program have been annotated with types.
Arguably, it is PHP which made the regrettable decision in adding run-time
type hints in the first place. If we removed those, we could implement
gradual typing, and maybe add an ability to reflect on the type
annotations, without the headache of how this interacts with run-time
performance.
Nonetheless, we are where we are, so I agree that it would be bad now to
add type annotations which did not behave at run-time like the existing
ones.
[1] http://wphomes.soic.indiana.edu/jsiek/what-is-gradual-typing/
--
Rowan Collins
[IMSoP]
On Mon, Jun 11, 2018 at 11:32 PM, Rowan Collins rowan.collins@gmail.com
wrote:
Hi Rasmus,
While I agree with your general point regarding consistency, I just want to
take issue with sentence:Hack made some very regrettable decisions in this area, and ultimately
those features were useful at design-time only, for IDE-support - but
we have php-doc for that purpose, and in my opinion, adding those
features before (or unless) we're willing/able to also make them work
consistently with the language, does more harm than good.As far as I know, every other language which has added type annotations to
a dynamically typed language has done so either using an offline tool
(treating them like compiler warnings), or as a debug-only run-time flag
(treating them like assertions). The creator of "gradual typing", which is
explicitly the basis of Python's type annotations, and at least implicitly
used by many other languages, specifically stated that it was intended to
be checked at compile-time, not run-time [1]:
Making "type hint" a "true type hint" is useful with DbC as well as static
analysis tools.
Perhaps,
declare(strict_types=-1); // -1 indicates assert()
type check. i.e. asset
is disabled, no type checks.
How it should behave with object would be debatable.
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net