Good evening,
PHP’s type hinting system is rather incomplete as it does not support scalars, only arrays, callables and objects. In 2012, Anthony Ferrara created an RFC which proposed type hinting for scalar types (int, float, bool, string and resource) with casting, with behaviour nearly the same as that of zend_parse_parameters. Sadly, he later left PHP internals and withdrew his RFCs.
Since I am very much in favour of scalar type hints, I’ve updated the patch to master and made some minor improvements, and I am re-opening the RFC with the intent to try and get it into PHP 5.7. The patch is mostly there. It needs some more tests and there are some edge cases I need to deal with, but it otherwise works, and I expect I can finish fixing it up very soon.
The RFC is here: https://wiki.php.net/rfc/scalar_type_hinting_with_cast
A pull request is here: https://github.com/php/php-src/pull/717
I’m hoping I can get this into PHP 5.7. I think scalar type hinting would be a valuable addition to PHP’s existing type hinting system.
Thanks!
Andrea Faulds
http://ajf.me/
Hi!
PHP’s type hinting system is rather incomplete as it does not support
scalars, only arrays, callables and objects. In 2012, Anthony Ferrara
created an RFC which proposed type hinting for scalar types (int,
float, bool, string and resource) with casting, with behaviour nearly
the same as that of zend_parse_parameters. Sadly, he later left PHP
internals and withdrew his RFCs.
I have one request: could we please stop calling it "hinting"?
The dictionary says (http://www.thefreedictionary.com/hint) that
the word "hint" means:
- A slight indication or intimation: wanted to avoid any hint of scandal.
a. A brief or indirect suggestion; a tip: stock-trading hints.
b. A statement conveying information in an indirect fashion; a clue:
Give me a hint about the big news.
- A barely perceptible amount: just a hint of color.
What we have in PHP and what is being proposed it not a "slight
indication", not "suggestion" and not "conveying information in indirect
fashion" (what Python does in PEP-3107 could be called that way, but
it's not what is proposed here). It is very direct specification of
either strict parameter typing or coercive parameter typing. I don't
think using confusing terminology helps anything here. I think it was a
mistake to introduce this term from the start and we should stop
propagating it.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
It is very direct specification of
either strict parameter typing or coercive parameter typing. I don't
think using confusing terminology helps anything here. I think it was a
mistake to introduce this term from the start and we should stop
propagating it.
It does come across as as an attempt to hide the 'strict parameter
typing' which is something that is very much less attractive. If I
wanted that then I'd simply switch back to C/C++ direct which is perhaps
where we are now heading anyway with the increasing use of pre-compiled
application code?
One of the reasons I persist with PHP is the fact that many of my users
can adjust the odd PHP file correcting sequence or modifying text
without having to learn the intricacies of formal programming. It's
adding all these complex layers that is taking PHP away from it's more
novice friendly base ... If you want a formal programming language then
just use one?
--
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
It is very direct specification of
either strict parameter typing or coercive parameter typing. I don't
think using confusing terminology helps anything here. I think it was a
mistake to introduce this term from the start and we should stop
propagating it.It does come across as as an attempt to hide the 'strict parameter
typing' which is something that is very much less attractive. If I
wanted that then I'd simply switch back to C/C++ direct which is perhaps
where we are now heading anyway with the increasing use of pre-compiled
application code?One of the reasons I persist with PHP is the fact that many of my users
can adjust the odd PHP file correcting sequence or modifying text
without having to learn the intricacies of formal programming. It's
adding all these complex layers that is taking PHP away from it's more
novice friendly base ... If you want a formal programming language then
just use one?--
Lester Caine - G8HFLContact - 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--
Type hinting worked as a phrase when classes, interfaces a traits were
the majority of what was going on. The fact that I can say I would
like a Foo and get a Bar (which extends or implements Foo) means that
"hint" is a perfectly valid word to use.
If we move onto scalars theb you two are both right, "hint" is no
longer a hint. It is too strict for hint to work, as it is a way to
specifically ask for a certain piece of data.
Now, if we can accept that and move away from arguing semantics, there
is a more useful conversation to be had:
Should we have this thing, regardless of the name?
To paraphrase Lester Caine's last message: PHP can't have nice things.
His argument is one that I see repeatedly on internals: "If you want a
formal programming language then just use one?"
I think this misses the point of why many people (myself included) use
PHP. Despite PHP's various and extensive list of often rather comical
flaws, I continue to use PHP (and probably will for another decade)
because it is the most popular language on the internet. I can ship
something that can be downloaded and installed by drastically more
people than other languages. Until that situation changes, I build
software like PyroCMS, release packages like those on The League of
Extraordinary Packages, help write standards for the PHP-FIG, and do
it all with this crazy hodge-podge language we all know and "love."
If I had the choice of picking and choosing whichever language I
wanted to use all the time, I would be using Python, Ruby, Hack, Go,
or whatever language I felt like using that morning, and I often do.
Because I don't always get that choice, and because I legitimately
am stuck with PHP, I do like to see it continue to grow and improve
over time.
I believe I am not unique in this regard.
I, like Lester, do not want to see PHP get more difficult over time,
just because I am growing as a developer over time and eventually want
more and more formal features in the language. Luckily that is not
what is being suggested here.
Type hinting (strict parameter typing) is not some crazy C/C++ only
feature that junior developers will be entirely baffled by. I assume
at some point if you but a "square" into a $circle then you will get
an error, or a warning, or some sort of "Hi, this is wrong." which
will either be gob-smackingly self explanatory, or a quick google
away.
People here have often suggested that googling an error is a solution,
like the fantastic defense of T_PAAMAYIM_NEKUDOTAYIM
a few years back
(and multiple times before and after):
"Come on people, what exactly is the problem with a once-in-a-lifetime
investment of 5 seconds of your time to google some stupid error
message. Something you, as a developer, spend your life doing.
Please, stop complaining about a minor (yes, it is minor, use the
fricking search engine!) annoyance and accept php's heritage."
If googling error messages is used as a reason to keep completely
useless things like T_PAAMAYIM_NEKUDOTAYIM, then that same argument
cannot be used as a reason to block genuinely useful features. One or
the other folks.
If we can move forward without anyone else saying "AAAH THATS C++" (or
my other favorite "AAAH THATS JAVA") then it would be interesting to
hear how people feel about this article, which covers a lot of the
difficulties of type hinting parameters in PHP:
https://nikic.github.io/2012/03/06/Scalar-type-hinting-is-harder-than-you-think.html
I'm sure you've all read it of course, but I would be interested to
see which of you support which approach.
If we can (for now) continue to use "hinting" without accusations of
being sneaky, then the RFC is discussion uses "Casting weak type
hinting." I would not hate to see "Casting weak type hinting" used,
but would prefer "Strict weak type hinting" myself.
It is very direct specification of
either strict parameter typing or coercive parameter typing. I don't
think using confusing terminology helps anything here. I think it was a
mistake to introduce this term from the start and we should stop
propagating it.It does come across as as an attempt to hide the 'strict parameter
typing' which is something that is very much less attractive. If I
wanted that then I'd simply switch back to C/C++ direct which is perhaps
where we are now heading anyway with the increasing use of pre-compiled
application code?One of the reasons I persist with PHP is the fact that many of my users
can adjust the odd PHP file correcting sequence or modifying text
without having to learn the intricacies of formal programming. It's
adding all these complex layers that is taking PHP away from it's more
novice friendly base ... If you want a formal programming language then
just use one?
I don't see the current PHP type juggling as 'formal programming'. It makes
things easy but can also lead to bugs where unexpected values (& so types) end
up being inappropriately used.
This RFC does not mandate the use of type hinting so your users can still get
away with quick/sloppy programming. That does not change.
However: it does allow others to gain extra assurance that their programs are
not dealing with bad values (& so types) if they wish to. I can see that the
first areas where this will be used will be in objects/libraries that others
use. It will be good to use type hinting to bring out bugs where a bad value has
slipped by validation. The users of such libraries would not need to make
changes as a result of this.
I can see that it will also allow run time optimisation. If a value is known to
contain an integer then code like ''$a == $b'' could be an integer comparison
rather than having to first determine what the types might be and then end up
doing integer compare.
So: I strongly support this RFC.
I would also like to suggest an addition. That is the ability to declare local
variables to functions maybe using the using the keyword 'var'. So you would go:
function foo(int $a)
{
var $b; // $b has no type hinting
var float $c; // $c is a float
string $d; // alternative to the syntax used for $c (see below)
}
I would like, eventually, PHP to have a mode where use of an undeclared variable
would lead to an error being raised. A model for this is perl's ''use strict''.
The way that this could be done in PHP is that if a variable is declared with
'var' then strict mode is switched on for the function. This would provide a
distinction between the above declarations for $c and $d ($c switches on strict
mode, $d does not).
This would be OPTIONAL - ie if you do not want it then do not use 'var' and it
will not impinge; if you use it then you get the extra checking that it brings.
Should I raise an RFC for this ?
--
Alain Williams
Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT Lecturer.
+44 (0) 787 668 0256 http://www.phcomp.co.uk/
Parliament Hill Computers Ltd. Registration Information: http://www.phcomp.co.uk/contact.php
#include <std_disclaimer.h
I don't see the current PHP type juggling as 'formal programming'. It
makes
things easy but can also lead to bugs where unexpected values (& so
types)
end up being inappropriately used.
I haven't yet reviewed the conversion table in detail, but unless I'm
missing something, this RFC is in fact much more in the spirit of PHP -
and implements type juggling - unlike the previous incarnation of strict
typing that almost made it into PHP. It's a bit too strict to my liking
(especially around conversion of floating point to int, which should pass
and perhaps generate a notice IMHO), but this is a big step towards the
spirit of what I proposed together with Lukas back in 2010
(https://wiki.php.net/rfc/typecheckingstrictandweak) - which was an
alternative to the strong typing suggested by several others.
Type juggling is an inherent feature of PHP. Paraphrasing what Rasmus
said several years ago(*), 'if you implement this [strong typing], please
don't call it PHP'.
Again, luckily, what Andrea proposes isn't strong typing. It still
maintains the most important properties of type juggling - e.g. the
ability to work with strings coming in as input (GET/POST/etc.) without
having to worry about typing.
Zeev
(*) I couldn't find that email quickly enough so apologies if I'm not
completely accurate on this.
I haven't yet reviewed the conversion table in detail, but unless I'm
missing something, this RFC is in fact much more in the spirit of PHP -
and implements type juggling - unlike the previous incarnation of strict
typing that almost made it into PHP. It's a bit too strict to my liking
(especially around conversion of floating point to int, which should pass
and perhaps generate a notice IMHO), but this is a big step towards the
spirit of what I proposed together with Lukas back in 2010
(https://wiki.php.net/rfc/typecheckingstrictandweak) - which was an
alternative to the strong typing suggested by several others.Type juggling is an inherent feature of PHP. Paraphrasing what Rasmus
said several years ago(*), 'if you implement this [strong typing], please
don't call it PHP'.Again, luckily, what Andrea proposes isn't strong typing. It still
maintains the most important properties of type juggling - e.g. the
ability to work with strings coming in as input (GET/POST/etc.) without
having to worry about typing.
Right. I think this RFC would strengthen PHP’s weak typing guarantees, because while internal functions will convert to the right type and hence avoid issues with strings and such not acting quite like integers in some situations, userland functions usually don’t. This RFC would mean that, at least for “hinted” functions, user_land_function($_GET[‘id’]) should work just as well as internal_function($_GET[‘id’]).
Also, it’s not really “what Andrea proposes”, it’s Anthony’s proposal, even if he is sadly absent from the list these days. I’m just trying to fix up the patch, iron out remaining wrinkles, and get this into PHP.
--
Andrea Faulds
http://ajf.me/
Type juggling is an inherent feature of PHP. Paraphrasing what Rasmus
said several years ago(*), 'if you implement this [strong typing], please
don't call it PHP'.Again, luckily, what Andrea proposes isn't strong typing. It still
maintains the most important properties of type juggling - e.g. the
ability to work with strings coming in as input (GET/POST/etc.) without
having to worry about typing.
I think that you need to look at how and where this will be used. In (what I
shall call) the outer parts of programs it may not be useful, but it will in the
inner parts.
Let me explain:
The outer part of a program which will work with things like $_GET['age'] which
might have values like: '10', 'ten', '10.5', '' or even be unset. Even assigning
a value to '$age' and have PHP do type checking is not what you want.
Type juggling is an important part of outer code.
Input (form) variables are then type/... checked by validation tests, this will
reject 'ten', '', unset and maybe '10.5'. I see this as a kind of firewall.
The inner side only uses values that have been through the 'firewall', ie I know
that $age will contain an integer. I can then do integer operations on it
without further checking - indeed I do NOT want to have to do further checking
since that just adds to the code size/complexity/ugliness.
It is in this 'inner' code where I will want to use PHP type hinting as
currently discussed. Although my values should have been though the firewall, I
do make mistakes, etc, so the inner code either occasionally fails in an obscure
way or assertions are done. Some means of having PHP help here would be very much
appreciated.
Which of the two below is clearer:
function CanDrive($age)
{
if( !is_numeric($age))
throw new Error("\$age is not integer (CanDrive())");
return $age >= 17;
}
function CanDrive(int $age)
{
return $age >= 17;
}
The above is how I write programs. [I do realise that the 2 above are not
exactly the same.]
(*) I couldn't find that email quickly enough so apologies if I'm not
completely accurate on this.
--
Alain Williams
Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT Lecturer.
+44 (0) 787 668 0256 http://www.phcomp.co.uk/
Parliament Hill Computers Ltd. Registration Information: http://www.phcomp.co.uk/contact.php
#include <std_disclaimer.h
Which of the two below is clearer:
function CanDrive($age) { if( !is_numeric($age)) throw new Error("\$age is not integer (CanDrive())");
return $age >= 17;
}function CanDrive(int $age) {
return $age >= 17;
}
I think we're on the same page here that the 2nd one looks better, which
is the point of the RFC.
But the way I see it, the RFC should focus pretty much exclusively on
sanitizing information coming from the 'outer code' and into the 'inner
code', as opposed to enforcing strict typing within the inner code (a
function that unless I'm missing something it does not attempt to do,
thankfully).
The point of the RFC is that as the author of the API, you wouldn't have
to worry about input sanity, while still allowing the dynamic nature of
PHP - AKA type juggling - so that users who call that API don't need to be
bothered with the mechanics of their types either.
Zeev
It is very direct specification of
either strict parameter typing or coercive parameter typing. I don't
think using confusing terminology helps anything here. I think it was a
mistake to introduce this term from the start and we should stop
propagating it.It does come across as as an attempt to hide the 'strict parameter
typing' which is something that is very much less attractive. If I
wanted that then I'd simply switch back to C/C++ direct which is perhaps
where we are now heading anyway with the increasing use of pre-compiled
application code?One of the reasons I persist with PHP is the fact that many of my users
can adjust the odd PHP file correcting sequence or modifying text
without having to learn the intricacies of formal programming. It's
adding all these complex layers that is taking PHP away from it's more
novice friendly base ... If you want a formal programming language then
just use one?I don't see the current PHP type juggling as 'formal programming'. It makes
things easy but can also lead to bugs where unexpected values (& so types)
end
up being inappropriately used.This RFC does not mandate the use of type hinting so your users can still
get
away with quick/sloppy programming. That does not change.However: it does allow others to gain extra assurance that their programs
are
not dealing with bad values (& so types) if they wish to. I can see that
the
first areas where this will be used will be in objects/libraries that
others
use. It will be good to use type hinting to bring out bugs where a bad
value has
slipped by validation. The users of such libraries would not need to make
changes as a result of this.I can see that it will also allow run time optimisation. If a value is
known to
contain an integer then code like ''$a == $b'' could be an integer
comparison
rather than having to first determine what the types might be and then end
up
doing integer compare.So: I strongly support this RFC.
I would also like to suggest an addition. That is the ability to declare
local
variables to functions maybe using the using the keyword 'var'. So you
would go:function foo(int $a) { var $b; // $b has no type hinting var float $c; // $c is a float string $d; // alternative to the syntax used for $c (see below) }
I would like, eventually, PHP to have a mode where use of an undeclared
variable
would lead to an error being raised. A model for this is perl's ''use
strict''.
The way that this could be done in PHP is that if a variable is declared
with
'var' then strict mode is switched on for the function. This would
provide a
distinction between the above declarations for $c and $d ($c switches on
strict
mode, $d does not).This would be OPTIONAL - ie if you do not want it then do not use 'var'
and it
will not impinge; if you use it then you get the extra checking that it
brings.Should I raise an RFC for this ?
I think it would be better to reuse declare() instead of reusing var.
What error level would it emit though?
I anything below E_RECOVERABLE_ERROR, then it doesn't do anything, but
prints a line to the error log(and or displays it), which we already do,
because using an undefined variable will emit an E_NOTICE
I think it is a good thing if we make it easier to spot programming errors
and bail out early instead of trying to guess the developer's intention,
but I don't think that adding more fatal errors or
E_RECOVERABLE_ERRORs(which will be fatal if there is no userland error
handler defined which explicitly allows to continue the execution).
--
Ferenc Kovács
@Tyr43l - http://tyrael.hu
function foo(int $a) { var $b; // $b has no type hinting var float $c; // $c is a float string $d; // alternative to the syntax used for $c (see below) }
I think it would be better to reuse declare() instead of reusing var.
As a matter of curiosity, why ?
The nice thing about 'var' is that it is the syntax used by other languages, eg
Javascript.
What error level would it emit though?
I anything below E_RECOVERABLE_ERROR, then it doesn't do anything, but
prints a line to the error log(and or displays it), which we already do,
because using an undefined variable will emit anE_NOTICE
I think it is a good thing if we make it easier to spot programming errors
and bail out early instead of trying to guess the developer's intention,
but I don't think that adding more fatal errors or
E_RECOVERABLE_ERRORs(which will be fatal if there is no userland error
handler defined which explicitly allows to continue the execution).
This sort of error should be picked up the first time that the script is
compiled, it does not need to be executed (other than conditional includes).
This means that these errors will be picked up very quickly.
--
Alain Williams
Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT Lecturer.
+44 (0) 787 668 0256 http://www.phcomp.co.uk/
Parliament Hill Computers Ltd. Registration Information: http://www.phcomp.co.uk/contact.php
#include <std_disclaimer.h
Alain Williams wrote (on 14/07/2014):
This sort of error should be picked up the first time that the script is
compiled, it does not need to be executed (other than conditional includes).
This means that these errors will be picked up very quickly.
So, it doesn't need to be executed ... except when it does (I can think
of a few other cases where it's non-trivial to write a compile-time check).
There are plenty of static analysis tools which will pick up this kind
of thing, but if you want a language with strict compile-time checks,
use Hack, which eliminates certain dynamic PHP features in order to make
stronger guarantees.
Regards,
Rowan Collins
[IMSoP]
function foo(int $a) { var $b; // $b has no type hinting var float $c; // $c is a float string $d; // alternative to the syntax used for $c (see
below)
}
I think it would be better to reuse declare() instead of reusing var.
As a matter of curiosity, why ?
The nice thing about 'var' is that it is the syntax used by other
languages, eg
Javascript.
in javascript var itself only defines the variable scope/context.
what you really proposing here is "strict" mode (use strict in javascript),
and for that declare would be suitable, as that is the current method of
passing information for the compiler about a file or a codeblock.
What error level would it emit though?
I anything below E_RECOVERABLE_ERROR, then it doesn't do anything, but
prints a line to the error log(and or displays it), which we already do,
because using an undefined variable will emit anE_NOTICE
I think it is a good thing if we make it easier to spot programming
errors
and bail out early instead of trying to guess the developer's intention,
but I don't think that adding more fatal errors or
E_RECOVERABLE_ERRORs(which will be fatal if there is no userland error
handler defined which explicitly allows to continue the execution).This sort of error should be picked up the first time that the script is
compiled, it does not need to be executed (other than conditional
includes).
This means that these errors will be picked up very quickly.
that's true, but you didn't really answered my question about the error
level.
--
Ferenc Kovács
@Tyr43l - http://tyrael.hu
I have one request: could we please stop calling it "hinting"?
The dictionary says (http://www.thefreedictionary.com/hint) that
the word "hint" means:
- A slight indication or intimation: wanted to avoid any hint of scandal.
a. A brief or indirect suggestion; a tip: stock-trading hints.
b. A statement conveying information in an indirect fashion; a clue:
Give me a hint about the big news.
- A barely perceptible amount: just a hint of color.
What we have in PHP and what is being proposed it not a "slight
indication", not "suggestion" and not "conveying information in indirect
fashion" (what Python does in PEP-3107 could be called that way, but
it's not what is proposed here). It is very direct specification of
either strict parameter typing or coercive parameter typing. I don't
think using confusing terminology helps anything here. I think it was a
mistake to introduce this term from the start and we should stop
propagating it.
I agree that “type hinting” is a bad name for it. Perhaps “optional typing” would be better. It conveys that these specifiers are completely optional, and that there is a system of typing, but it doesn’t say anything about its strictness.
Regardless, this RFC will stick with the current terminology, but changing the terminology would be quite simple, you could just update the manual and possibly change some of the internal names.
--
Andrea Faulds
http://ajf.me/
I have one request: could we please stop calling it "hinting"?
I've always thought the current "type hinting" should be called "type
assertion", since passing the wrong data type is detected only at
runtime, and causes an error in much the same way as if you wrote
assert($param instanceof HintedClass).
What this RFC proposes is more like "type validation" - detecting that
the given input can be safely coerced to the given type, and performing
the coercion in the process. As Andrea points, out, it's similar to what
Nikita called[1] "strict weak type hinting", but with the added step of
performing the cast, which is really just a convenience, since if you've
asked for a value to be validated as an int, you're presumably about to
use it as one.
[1]
http://nikic.github.io/2012/03/06/Scalar-type-hinting-is-harder-than-you-think.html
--
Rowan Collins
[IMSoP]
Am 13.07.2014 07:22, schrieb Stas Malyshev:
I think it was a mistake to introduce this term from the start and
we should stop propagating it.
What would be a better term? Optional strict typing in function and
method signatures?
Am 13.07.2014 07:22, schrieb Stas Malyshev:
I think it was a mistake to introduce this term from the start and
we should stop propagating it.What would be a better term? Optional strict typing in function and
method signatures?
This proposal’s scalar type hints (except for booleans) can’t really be called “strict”. Perhaps “firm typing”? (It’s not weak, but it’s not quite strong either)
Andrea Faulds
http://ajf.me/
2014.07.20. 14:43, "Andrea Faulds" ajf@ajf.me ezt írta:
Am 13.07.2014 07:22, schrieb Stas Malyshev:
I think it was a mistake to introduce this term from the start and
we should stop propagating it.What would be a better term? Optional strict typing in function and
method signatures?This proposal’s scalar type hints (except for booleans) can’t really be
called “strict”. Perhaps “firm typing”? (It’s not weak, but it’s not quite
strong either)
Stas and Sebastian are talking about the unfortunate naming of the current
(non-scalar) typehints.
This proposal’s scalar type hints (except for booleans) can’t really be called “strict”. Perhaps “firm typing”? (It’s not weak, but it’s not quite strong either)
Stas and Sebastian are talking about the unfortunate naming of the current (non-scalar) type hints.
Oh, of course. Perhaps we could say that the non-scalar type hints are “optional strict typing” and the scalar type hints are “optional firm typing”?
--
Andrea Faulds
http://ajf.me/
Hi!
What would be a better term? Optional strict typing in function and
method signatures?
Parameter typing, or typed parameters if you will. One of the options,
of course, there could be many others.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
We are using hack’s syntax (int, float, bool, string, no integer/double/boolean aliases).
The patch actually warns you if you try to do this now:
function foo(double $foo) {}
foo(1.0);If you use one of the non-existent aliases (double), and pass the type that alias is supposed to hint for (a float), the error message notes you might be looking for the actual type hint (
float
).
It seems odd to me to not support the aliases. Since I can do this:
$foo = (integer)$bar;
I would expect to be able to do this:
function foo(integer $param) {}
Also, do int, float, and numeric accept numbers in octal, hex, scientific notation, etc.? I don’t believe there are any examples in the RFC that intentionally or accidentally show what happens with, say, 0x2f as a value.
--
Bob Williams
SVP, Software Development
Newtek Business Services, Inc.
“The Small Business Authority”
http://www.thesba.com/
Notice: This communication, including attachments, may contain information that is confidential. It constitutes non-public information intended to be conveyed only to the designated recipient(s). If the reader or recipient of this communication is not the intended recipient, an employee or agent of the intended recipient who is responsible for delivering it to the intended recipient, or if you believe that you have received this communication in error, please notify the sender immediately by return e-mail and promptly delete this e-mail, including attachments without reading or saving them in any manner. The unauthorized use, dissemination, distribution, or reproduction of this e-mail, including attachments, is prohibited and may be unlawful. If you have received this email in error, please notify us immediately by e-mail or telephone and delete the e-mail and the attachments (if any).
It seems odd to me to not support the aliases. Since I can do this:
$foo = (integer)$bar;
I would expect to be able to do this:
function foo(integer $param) {}
Aliases mean inconsistency. We shouldn’t unnecessarily have multiple names for the same thing, just one. Also, for every alias we support, another reserved word is added. Hence we only allow one set of names. This is also Facebook’s approach with Hack, which removes the aliases entirely for type casting. I might propose we deprecate/remove the aliases in a future RFC.
Also, do int, float, and numeric accept numbers in octal, hex, scientific notation, etc.? I don’t believe there are any examples in the RFC that intentionally or accidentally show what happens with, say, 0x2f as a value.
Ooh, you’ve caught me out there. The patch as it stands would permit such non-decimal numbers, which isn’t what it should do as convert_to_long_base_safe should actually permit only the specified base.
So, yes it does permit non-decimal numbers, but it’s a bug I need to fix.
--
Andrea Faulds
http://ajf.me/
Aliases mean inconsistency. We shouldn’t unnecessarily have multiple names for the same thing, just one. Also, for every alias we support, another reserved word is added. Hence we only allow one set of names. This is also Facebook’s approach with Hack, which removes the aliases entirely for type casting. I might propose we deprecate/remove the aliases in a future RFC.
I agree the aliases, by definition, represent inconsistency. However, that inconsistency is already in the language, and those keywords already exist. By not supporting the aliases in new functionality that’s so closely related, the inconsistency is itself inconsistent.
Although I don’t have voting rights, I would completely support a separate RFC to remove the aliases in PHP 6/7. But in the mean time, as long as they’re still in the language, I think they need to be fully supported anywhere their “real” counterparts can be used. Hack didn’t just remove them in some cases, it removed them across the board. And I think that’s the right approach: they’re supported across the board until they’re no longer supported, and then they’re not supported anywhere.
So, yes it does permit non-decimal numbers, but it’s a bug I need to fix.
I’m not sure I follow. If I have function foo(int $bar) {}, what happens in these cases:
foo(0x2f);
foo(‘0x2f’);
Related, is “numeric" basically the union of “int” and “float” (as appears to be the case from the chart in the RFC), or is it something more along the lines of is_numeric()
? There could be consistency issues lurking here, too.
Regards,
Bob
--
Robert E. Williams, Jr.
Senior Vice President of Software Development
Newtek Businesss Services, Inc. -- The Small Business Authority
https://www.newtekreferrals.com/rewjr
http://www.thesba.com/
Notice: This communication, including attachments, may contain information that is confidential. It constitutes non-public information intended to be conveyed only to the designated recipient(s). If the reader or recipient of this communication is not the intended recipient, an employee or agent of the intended recipient who is responsible for delivering it to the intended recipient, or if you believe that you have received this communication in error, please notify the sender immediately by return e-mail and promptly delete this e-mail, including attachments without reading or saving them in any manner. The unauthorized use, dissemination, distribution, or reproduction of this e-mail, including attachments, is prohibited and may be unlawful. If you have received this email in error, please notify us immediately by e-mail or telephone and delete the e-mail and the attachments (if any).
Although I don’t have voting rights, I would completely support a separate RFC to remove the aliases in PHP 6/7. But in the mean time, as long as they’re still in the language, I think they need to be fully supported anywhere their “real” counterparts can be used. Hack didn’t just remove them in some cases, it removed them across the board. And I think that’s the right approach: they’re supported across the board until they’re no longer supported, and then they’re not supported anywhere.
Right, but none of the aliases are reserved words already and I really don’t want to introduce more reserved words than I have to, otherwise it’s going to upset a lot of people.
Andrea Faulds
http://ajf.me/
Also, do int, float, and numeric accept numbers in octal, hex, scientific notation, etc.? I don’t believe there are any examples in the RFC that intentionally or accidentally show what happens with, say, 0x2f as a value.
Ooh, you’ve caught me out there. The patch as it stands would permit such non-decimal numbers, which isn’t what it should do as convert_to_long_base_safe should actually permit only the specified base.
So, yes it does permit non-decimal numbers, but it’s a bug I need to fix.
Said bug has been fixed in the proposed patch now. “0xa” is no longer valid for int, float or numeric. It never should’ve been valid, but the implementation of convert_to_(long_base|double|numeric)_safe was incorrect.
--
Andrea Faulds
http://ajf.me/
Good evening,
PHP’s type hinting system is rather incomplete as it does not support
scalars, only arrays, callables and objects. In 2012, Anthony Ferrara
created an RFC which proposed type hinting for scalar types (int, float,
bool, string and resource) with casting, with behaviour nearly the same as
that of zend_parse_parameters. Sadly, he later left PHP internals and
withdrew his RFCs.Since I am very much in favour of scalar type hints, I’ve updated the
patch to master and made some minor improvements, and I am re-opening the
RFC with the intent to try and get it into PHP 5.7. The patch is mostly
there. It needs some more tests and there are some edge cases I need to
deal with, but it otherwise works, and I expect I can finish fixing it up
very soon.The RFC is here: https://wiki.php.net/rfc/scalar_type_hinting_with_cast
A pull request is here: https://github.com/php/php-src/pull/717
I’m hoping I can get this into PHP 5.7. I think scalar type hinting would
be a valuable addition to PHP’s existing type hinting system.Thanks!
I think the approach described in this proposal is the best way to
implement scalar typehinting, as it allows typical loosely-typed usage
patterns, while still providing type guarantees within the function.
I haven't yet closely reviewed the details of what is and isn't allowed,
but one things I would strongly recommend against is introducing any
"accept but throw a notice" cases. Either a value is allowed or it isn't.
"12foo" to an int/float argument should throw a recoverable fatal error,
like everything else. (I'd change that in zpp as well, but that's a
different discussion).
The question of passing floats like 12.5 to an int param is somewhat
tricky. One could argue that it's possible to end up with floats like
12.0000000001, which are nearly integers but not quite there, and a user
might expect them to behave the same as the integer 12. On the other hand
one can also argue that it's easy to end up with the inverse, namely
11.999999999999. In this case the end user might also expect it to be
treated as integer 12, however an integer cast will truncate it to 11.
The truncation behavior of the float to int cast is why I tend towards the
behavior the RFC currently proposes (forbid non-integral floats): It is
rather unlikely that truncation is what was intended, as such an explicit
rounding call is necessary anyways.
Nikita
Hi,
Would it possible to control the implicit casting through a PHP variable
? (or perhaps modify E_STRICT
to display a warning if this kind of
implicit cast is done ?)
I mean specifying explicitly a type is often useful to make sure the
proper type is passed to the function, and there's no bug in the calling
func.
e.g. safety check like
function foo($bar) {
if (!is_int($bar)) {
throw new Exception('Invalid parameter type');
}
}
will not be "equivalent" to
function foo(int $bar) {
}
and there will be no way to have an equivalent behaviour once "type
hinting" is used !
Thanks,
Jocelyn
Le 13/07/2014 14:09, Nikita Popov a écrit :
Good evening,
PHP’s type hinting system is rather incomplete as it does not support
scalars, only arrays, callables and objects. In 2012, Anthony Ferrara
created an RFC which proposed type hinting for scalar types (int, float,
bool, string and resource) with casting, with behaviour nearly the same as
that of zend_parse_parameters. Sadly, he later left PHP internals and
withdrew his RFCs.Since I am very much in favour of scalar type hints, I’ve updated the
patch to master and made some minor improvements, and I am re-opening the
RFC with the intent to try and get it into PHP 5.7. The patch is mostly
there. It needs some more tests and there are some edge cases I need to
deal with, but it otherwise works, and I expect I can finish fixing it up
very soon.The RFC is here: https://wiki.php.net/rfc/scalar_type_hinting_with_cast
A pull request is here: https://github.com/php/php-src/pull/717
I’m hoping I can get this into PHP 5.7. I think scalar type hinting would
be a valuable addition to PHP’s existing type hinting system.Thanks!
I think the approach described in this proposal is the best way to
implement scalar typehinting, as it allows typical loosely-typed usage
patterns, while still providing type guarantees within the function.I haven't yet closely reviewed the details of what is and isn't allowed,
but one things I would strongly recommend against is introducing any
"accept but throw a notice" cases. Either a value is allowed or it isn't.
"12foo" to an int/float argument should throw a recoverable fatal error,
like everything else. (I'd change that in zpp as well, but that's a
different discussion).The question of passing floats like 12.5 to an int param is somewhat
tricky. One could argue that it's possible to end up with floats like
12.0000000001, which are nearly integers but not quite there, and a user
might expect them to behave the same as the integer 12. On the other hand
one can also argue that it's easy to end up with the inverse, namely
11.999999999999. In this case the end user might also expect it to be
treated as integer 12, however an integer cast will truncate it to 11.The truncation behavior of the float to int cast is why I tend towards the
behavior the RFC currently proposes (forbid non-integral floats): It is
rather unlikely that truncation is what was intended, as such an explicit
rounding call is necessary anyways.Nikita
Would it possible to control the implicit casting through a PHP variable ? (or perhaps modify
E_STRICT
to display a warning if this kind of implicit cast is done ?)
No. I mean, yes, it’s possible, but allowing the effective function signature of a function to change based on some variable or ini setting does not sound like a good idea to me.
I mean specifying explicitly a type is often useful to make sure the proper type is passed to the function, and there's no bug in the calling func.
e.g. safety check like
function foo($bar) {
if (!is_int($bar)) {
throw new Exception('Invalid parameter type');
}
}will not be "equivalent" to
function foo(int $bar) {
}
and there will be no way to have an equivalent behaviour once "type hinting" is used !
You just demonstrated one:
function foo($bar) {
if (!is_int($bar)) {
throw new Exception('Invalid parameter type');
}
}
If you really want to continue doing that, nothing would stop you.
Andrea Faulds
http://ajf.me/
I haven't yet closely reviewed the details of what is and isn't allowed,
but one things I would strongly recommend against is introducing any
"accept but throw a notice" cases. Either a value is allowed or it isn't.
"12foo" to an int/float argument should throw a recoverable fatal error,
like everything else. (I'd change that in zpp as well, but that's a
different discussion).
I’ve changed this case in the RFC and my patch. Previously, “12foo” would just throw an E_NOTICE, but now it is not accepted:
Integer hints:
function foo(int $a) {
var_dump($a);
}
foo(1); // int(1)
foo("1"); // int(1)
foo(1.0); // int(1)
foo("1a"); // E_RECOVERABLE_ERROR
foo("a"); // E_RECOVERABLE_ERROR
foo(999999999999999999999999999999999999); // E_RECOVERABLE_ERROR
(since it's not exactly representable by an int)
foo(1.5); // E_RECOVERABLE_ERROR
Float hints:
function foo(float $a) {
var_dump($a);
}
foo(1); // float(1)
foo("1"); // float(1)
foo(1.0); // float(1)
foo("1a"); // E_RECOVERABLE_ERROR
foo("a"); // E_RECOVERABLE_ERROR
foo(1.5); // float(1.5)
--
Andrea Faulds
http://ajf.me/
I think this is a big step in the wrong direction to one of the most
common auto-conversion use cases out there (HTTP input variables). See my
note to Nikita...
This RFC is a huge deal, I suggest we let more people voice their opinion
in before changing it in each direction :)
Zeev
-----Original Message-----
From: Andrea Faulds [mailto:ajf@ajf.me]
Sent: Sunday, July 13, 2014 5:21 PM
To: Nikita Popov
Cc: PHP internals
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)I haven't yet closely reviewed the details of what is and isn't
allowed, but one things I would strongly recommend against is
introducing any "accept but throw a notice" cases. Either a value is
allowed
or it isn't.
"12foo" to an int/float argument should throw a recoverable fatal
error, like everything else. (I'd change that in zpp as well, but
that's a different discussion).I've changed this case in the RFC and my patch. Previously, "12foo"
would just
throw an E_NOTICE, but now it is not accepted:Integer hints:
function foo(int $a) {
var_dump($a);
}
foo(1); // int(1)
foo("1"); // int(1)
foo(1.0); // int(1)
foo("1a"); //E_RECOVERABLE_ERROR
foo("a"); //E_RECOVERABLE_ERROR
foo(999999999999999999999999999999999999); //
E_RECOVERABLE_ERROR
(since it's not exactly representable by an int)
foo(1.5); //E_RECOVERABLE_ERROR
Float hints:
function foo(float $a) {
var_dump($a);
}
foo(1); // float(1)
foo("1"); // float(1)
foo(1.0); // float(1)
foo("1a"); //E_RECOVERABLE_ERROR
foo("a"); //E_RECOVERABLE_ERROR
foo(1.5); // float(1.5)--
Andrea Faulds
http://ajf.me/--
To unsubscribe,
visit:
http://www.php.net/unsub.php
I think this is a big step in the wrong direction to one of the most
common auto-conversion use cases out there (HTTP input variables). See my
note to Nikita...This RFC is a huge deal, I suggest we let more people voice their opinion
in before changing it in each direction :)Zeev
Yes, I might have acted a little too quickly. However, I’m not sure “12a” is such a common case. With the strict behaviour, foobar(“ 12”) and foobar(“12”) still work, however foobar(“12 “) unfortunately would not.
Andrea Faulds
http://ajf.me/
-----Original Message-----
From: Andrea Faulds [mailto:ajf@ajf.me]
Sent: Sunday, July 13, 2014 5:34 PM
To: Zeev Suraski
Cc: Nikita Popov; PHP internals
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)I think this is a big step in the wrong direction to one of the most
common auto-conversion use cases out there (HTTP input variables).
See my note to Nikita...This RFC is a huge deal, I suggest we let more people voice their
opinion in before changing it in each direction :)Zeev
Yes, I might have acted a little too quickly. However, I'm not sure
"12a" is such
a common case. With the strict behaviour, foobar(" 12") and foobar("12")
still
work, however foobar("12 ") unfortunately would not.
I don't think it's a common intentional case, but when writing code
defensively - you need to be prepared for whatever someone might through
at you... Say I have a form that accepts 'age', and I expect users to
type in their age. As one that develops the backend, it's great if I can
simply stick an 'int' in the function signature that deals with this
$_GET['age'], and know that whatever the user typed in - it would turn it
to the most sane integer value. In other words, if someone types in '12a'
(by mistake or intentionally), I think it's a very sane behavior to just
treat it as 12, as opposed to forcing me (the developer) to write error
handling code with a try/catch block, and a fairly hairy try/catch block
too. Your example of "12 " (that I didn't even think about before) is an
even a more likely scenario, but I think there's no strong reason not to
allow both.
Zeev
I don't think it's a common intentional case, but when writing code
defensively - you need to be prepared for whatever someone might through
at you... Say I have a form that accepts 'age', and I expect users to
type in their age. As one that develops the backend, it's great if I can
simply stick an 'int' in the function signature that deals with this
$_GET['age'], and know that whatever the user typed in - it would turn it
to the most sane integer value. In other words, if someone types in '12a'
(by mistake or intentionally), I think it's a very sane behavior to just
treat it as 12, as opposed to forcing me (the developer) to write error
handling code with a try/catch block, and a fairly hairy try/catch block
too. Your example of "12 " (that I didn't even think about before) is an
even a more likely scenario, but I think there's no strong reason not to
allow both.
I can see what you’re getting at, but then I also think allowing “12a” and the like could be a source of bugs. In this particular case, I’d probably explicitly cast the age myself before doing anything with it.
Forbidding “12a” is closer to the other type hints, which are strict, but is also further away from zpp. I’m a big conflicted.
For now, I’ll leave it as E_RECOVERABLE_ERROR. While user input might be problematic, it can just be filtered.
--
Andrea Faulds
http://ajf.me/
Le 13/07/2014 16:41, Zeev Suraski a écrit :
-----Original Message-----
From: Andrea Faulds [mailto:ajf@ajf.me]
Sent: Sunday, July 13, 2014 5:34 PM
To: Zeev Suraski
Cc: Nikita Popov; PHP internals
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)I think this is a big step in the wrong direction to one of the most
common auto-conversion use cases out there (HTTP input variables).
See my note to Nikita...This RFC is a huge deal, I suggest we let more people voice their
opinion in before changing it in each direction :)Zeev
Yes, I might have acted a little too quickly. However, I'm not sure
"12a" is such
a common case. With the strict behaviour, foobar(" 12") and foobar("12")
still
work, however foobar("12 ") unfortunately would not.I don't think it's a common intentional case, but when writing code
defensively - you need to be prepared for whatever someone might through
at you... Say I have a form that accepts 'age', and I expect users to
type in their age. As one that develops the backend, it's great if I can
simply stick an 'int' in the function signature that deals with this
$_GET['age'], and know that whatever the user typed in - it would turn it
to the most sane integer value. In other words, if someone types in '12a'
(by mistake or intentionally), I think it's a very sane behavior to just
treat it as 12, as opposed to forcing me (the developer) to write error
handling code with a try/catch block, and a fairly hairy try/catch block
too. Your example of "12 " (that I didn't even think about before) is an
even a more likely scenario, but I think there's no strong reason not to
allow both.
From my point of view, if the type annotations are doing implicit cast
(with or without E_NOTICE/E_STRICT warning), they should behave exactly
the same than an explicit cast. If it behaves differently, I'll be
really difficult for a developer to guess what will be the PHP behaviour
with this new syntax.
Jocelyn
From my point of view, if the type annotations are doing implicit cast
(with or
without E_NOTICE/E_STRICT warning), they should behave exactly the same
than an explicit cast. If it behaves differently, I'll be really difficult
for a
developer to guess what will be the PHP behaviour with this new syntax.
Coming to think of it, this is probably the cleanest and most productive
approach. +1.
Zeev
From my point of view, if the type annotations are doing implicit cast
(with or
without E_NOTICE/E_STRICT warning), they should behave exactly the same
than an explicit cast. If it behaves differently, I'll be really difficult
for a
developer to guess what will be the PHP behaviour with this new syntax.Coming to think of it, this is probably the cleanest and most productive
approach. +1.
If we interpret that to mean just casting everything with no error cases, but E_NOTICE
on some, then it is one of the three main proposals suggested for scalar type hinting:
- Casting type hints
- Strict type hints
- Scalar type hinting with casts
(There are others, but I won’t talk about them)
I’m not of the opinion that the first option, where we just cast and never error, is ideal. It does ensure the values are of the correct type when they get to you, so it keeps PHP’s type juggling, but it is unlikely to catch bugs where the wrong value has been passed.
The second option, while appealing to some, goes completely against PHP’s type juggling. You’d have to manually cast everything yourself. As I understand it, this is essentially what Hack does, but PHP is not Hack and I don’t really think this is a good idea.
A fourth option would be to allow both by using different syntaxes for casting and strict, but I don’t think we should add two different ways because we can’t agree; we should do it just one way.
The final option, which this RFC proposes, is something of a compromise between the two proposals. I think it’s sufficiently strict to prevent bugs, and the parameter will be the right type, but it does not stop type-juggling.
Nikita wrote about the subject of the different approaches here in 2012: http://nikic.github.io/2012/03/06/Scalar-type-hinting-is-harder-than-you-think.html
However, I don’t propose “strict weak” typing, I propose this RFC.
--
Andrea Faulds
http://ajf.me/
-----Original Message-----
From: Andrea Faulds [mailto:ajf@ajf.me]
Sent: Sunday, July 13, 2014 6:19 PM
To: Zeev Suraski
Cc: Jocelyn Fournier; PHP internals
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)
- Casting type hints
- Strict type hints
- Scalar type hinting with casts
(There are others, but I won't talk about them)
I'm not of the opinion that the first option, where we just cast and
never
error, is ideal. It does ensure the values are of the correct type when
they get
to you, so it keeps PHP's type juggling, but it is unlikely to catch
bugs where
the wrong value has been passed.
Let's stop for a moment right here.
If we emit notices, or even new E_CAST, do we not get the exact same
ability to catch errors you'd get from E_RECOVERABLE_ERROR?
Even reading Nikita's piece, he's saying he dislikes that option for
'obvious reasons', but I see nothing obviously wrong with this approach.
In fact, it gives you the full power of ensuring the correct types in the
'inner code', allows you to catch 'bad conversions' if you wish to (many
don't, but I agree some and perhaps many would), and allows you to use
this feature in the most widespread way possible while minimizing the
amount of code you need to write in order to use it (no inflation in
necessary try/catch blocks). Unlike what's suggested in that piece, it's
not equivalent at all to docblocks, as it is in fact enforced, and as you
said, has the benefit of being able to write the 'inner code' without
worrying about the input types.
Whether we go for option #1 or #3 doesn't change the amount of bugs you
can find *if you wish to, unless I'm missing something. Option #3 forces
you to explicitly deal with 'error' situations (which may or may not be
errors), while option #1 leaves it up to the developer whether he wants
to write 'E_CAST clean' code or not, similarly to E_STRICT
(assuming we
introduce E_CAST, we can choose an existing error level too).
Zeev
Even reading Nikita's piece, he's saying he dislikes that option for
'obvious reasons', but I see nothing obviously wrong with this approach.
[...] Unlike what's suggested in that piece, it's
not equivalent at all to docblocks, as it is in fact enforced, and as you
said, has the benefit of being able to write the 'inner code' without
worrying about the input types.
I think you're muddling two sections of Nikita's article [1]. The option
which is dismissed "for obvious reasons" is "unenforced type hinting" -
keywords which do absolutely nothing other than give a literal hint to
non-critical tools like documentation and reflection.
The next section is about "casting weak type hinting", which is
described as "one of the more interesting proposals". It certainly has
merit, although in my opinion it's less powerful than the other options
in what it adds to the language, as the equivalent userland boilerplate
is really minimal (e.g. $foo = (int)$foo).
As I've mentioned elsewhere, and indeed was mentioned in Anthony's
proposal at the time [2], the addition of warnings on lossy casts is a
completely separate issue to the ability to sugar those casts into a
function signature.
Now, what is being proposed here is effectively "casting strict type
hinting", a variant of what Nikita called "strict weak type hinting",
with the additional step of actually applying the lossless cast, rather
than just asserting that it's possible. This actually provides a lot of
functionality which is fiddly to implement in userland, and I can't see
a lot of uses for asserting that a cast would be non-lossy, if you're
not about to perform that cast (which is what "strict weak type hinting"
allows).
[1]
http://nikic.github.io/2012/03/06/Scalar-type-hinting-is-harder-than-you-think.html
[2] http://blog.ircmaxell.com/2012/03/parameter-type-casting-in-php.html
--
Rowan Collins
[IMSoP]
-----Original Message-----
From: Rowan Collins [mailto:rowan.collins@gmail.com]
Sent: Sunday, July 13, 2014 7:09 PM
To: internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)Even reading Nikita's piece, he's saying he dislikes that option for
'obvious reasons', but I see nothing obviously wrong with this approach.
[...] Unlike what's suggested in that piece, it's not equivalent at
all to docblocks, as it is in fact enforced, and as you said, has the
benefit of being able to write the 'inner code' without worrying about
the input types.I think you're muddling two sections of Nikita's article [1]. The option
which is
dismissed "for obvious reasons" is "unenforced type hinting" - keywords
which do absolutely nothing other than give a literal hint to non-critical
tools
like documentation and reflection.
You're absolutely right. My bad. BTW, auto-converting type hints were
proposed by Lukas and me back in 2010, even though I see them attributed to
Anthony in 2012 :)
The next section is about "casting weak type hinting", which is described
as
"one of the more interesting proposals". It certainly has merit, although
in my
opinion it's less powerful than the other options in what it adds to the
language, as the equivalent userland boilerplate is really minimal (e.g.
$foo =
(int)$foo).
That's not a bad thing in my book - another way to describe it is that it's
consistent with the rest of the language and doesn't require developers to
learn another new set of 'similar, but different' semantics.
In terms of value that it does bring to the table, it gives you a standard
way to do something that's very common in a shorter way and increases
quality of APIs (it's much more likely people will use this to describe
their APIs than docblocks), and we can use better warning semantics than we
currently have on conversions (without changing the rules), and it allows
you to do all that without having to add tons of defensive code (in the
calling code) that is often unnecessary. Making it easy to implement means
it'll get used more - and so far I fail to see what we stand to lose (more
on that below).
As I've mentioned elsewhere, and indeed was mentioned in Anthony's
proposal at the time [2], the addition of warnings on lossy casts is a
completely
separate issue to the ability to sugar those casts into a function
signature.
I don't see why they would be separate, especially if the key reason for
going for 'option #3' is that it helps find bugs better. Option #1 with the
added logic of warning about lost data or 'bogus' conversions has all the
advantages of option #3 but also other advantages.
Now, what is being proposed here is effectively "casting strict type
hinting", a
variant of what Nikita called "strict weak type hinting", with the
additional step
of actually applying the lossless cast, rather than just asserting that
it's
possible. This actually provides a lot of functionality which is fiddly to
implement in userland, and I can't see a lot of uses for asserting that a
cast
would be non-lossy, if you're not about to perform that cast (which is
what
"strict weak type hinting"
allows).
Again, option #1 as I see it (and is mostly described in the 2010 RFC
https://wiki.php.net/rfc/typecheckingstrictandweak) - it's identical in
terms of rules to those of PHP's casting, but with warnings emitted for lost
data and 'bogus' conversions. If we introduce this feature in a major
version, we could also consider change the casting code to emit these same
warnings so that we get full consistency - but that I think is in fact a
separate decision.
Zeev
BTW, auto-converting type hints were
proposed by Lukas and me back in 2010, even though I see them attributed to
Anthony in 2012 :)
Aha, seems like a case of convergent thinking, with the exception that
Anthony proposed using distinct syntax to represent the casts (the wiki
isn't rendering properly for me, so apologies if that is also covered in
your older proposal).
As I've mentioned elsewhere, having the same syntax mean "assert" for
scalars but "cast" for non-scalars leads to an ambiguity with arrays,
for which both actions are available (and current code performs an
assertion).
The next section is about "casting weak type hinting", which is described
as
"one of the more interesting proposals". It certainly has merit, although
in my
opinion it's less powerful than the other options in what it adds to the
language, as the equivalent userland boilerplate is really minimal (e.g.
$foo =
(int)$foo).
That's not a bad thing in my book - another way to describe it is that it's
consistent with the rest of the language and doesn't require developers to
learn another new set of 'similar, but different' semantics.In terms of value that it does bring to the table, it gives you a standard
way to do something that's very common in a shorter way and increases
quality of APIs (it's much more likely people will use this to describe
their APIs than docblocks), and we can use better warning semantics than we
currently have on conversions (without changing the rules), and it allows
you to do all that without having to add tons of defensive code (in the
calling code) that is often unnecessary. Making it easy to implement means
it'll get used more - and so far I fail to see what we stand to lose (more
on that below).
I think a lot of this hinges on the next question, of whether the
warning semantics are inherently tied to this new syntax, or a separate
issue.
To me, it makes perfect sense for the following to be equivalent, with
one just a more expressive way of writing it:
function casts_as_array($foo) { $foo = (array)$foo; /* ... / }
function casts_as_array((array)$foo) { / ... */ }
As I've mentioned elsewhere, and indeed was mentioned in Anthony's
proposal at the time [2], the addition of warnings on lossy casts is a
completely
separate issue to the ability to sugar those casts into a function
signature.
I don't see why they would be separate, especially if the key reason for
going for 'option #3' is that it helps find bugs better. Option #1 with the
added logic of warning about lost data or 'bogus' conversions has all the
advantages of option #3 but also other advantages.
Other than isolating the change for backwards compatibility, I don't see
a big reason to treat them as separate. If the aim is to make the scalar
type hints "just like an existing cast", then lossy casts should work
the same way in both places.
On the other hand, if the aim is to make it easier to detect lossy
casts, then a way to do that outside function signatures is just as
useful as a way embedded in them.
In fact, thinking about it, several of these proposals add implicit
functionality in the function signature which would remain tricky in
userland code. Current type-hinting does not do this (it can be emulated
fairly easily with is_array()
, is_callable()
, and instanceof).
If we don't want all casts to emit warnings on loss, perhaps a new
function or keyword request them - e.g. (strict int)$foo, or
strict_cast($foo, 'int').
Regards,
--
Rowan Collins
[IMSoP]
Again, option #1 as I see it (and is mostly described in the 2010 RFC
https://wiki.php.net/rfc/typecheckingstrictandweak) - it's identical in
terms of rules to those of PHP's casting, but with warnings emitted for lost
data and 'bogus' conversions. If we introduce this feature in a major
version, we could also consider change the casting code to emit these same
warnings so that we get full consistency - but that I think is in fact a
separate decision.Zeev
I want to call out this point because I think it's key. Remember that
when an E_* is emitted, if it's not trapped then code execution
continues. That means we can, and should, think about what the
resulting value is independently of what if any E_* message is emitted.
That is:
function give_int(int $foo) { }
give_int('123abc');
The value of $foo should be 123 (int), because that's what casting rules
say. However, because that's lossy an E_* should get emitted to warn
the developer "hey, not what I meant!" If the error handler doesn't
terminate the process, though, then give_array() will continue to
execute and in that case the value that results from the cast MUST be
the same as if it were done explicitly.
We can discuss when the E_* should be emitted separately from what the
cast result is.
The one caveat to that is arrays, as someone else noted:
Current PHP:
function give_array(array $foo) { var_dump($foo); }
give_array('abc');
// Catchable fatal error.
Whereas if it follows the hint rules, apparently:
array(1) { [0]=> string(3) "abc" }
Which as a developer I wouldn't want, since that's likely to break my
code's assumptions. Array is weird in that we'd be changing from a type
specifier to a type caster. (ie, less like objects, more like
primitives.) As long as it's an error of some kind it may be OK, but
perhaps we want to leave array as is (strict behavior) rather than
changing it to the primitive logic (cast behavior)?
--Larry Garfield
We can discuss when the E_* should be emitted separately from what the cast result is.
Is there any actual controversy over what the result of casts should be. This RFC just has the normal casting result. Is anyone really in disagreement there?
As long as it's an error of some kind it may be OK, but perhaps we want to leave array as is (strict behavior) rather than changing it to the primitive logic (cast behaviour)?
I think the discussion about how arrays should be casted too for consistency is a bit silly. What makes sense for non-scalar types (strict hinting) may not work so well for scalar types; casting to array is rarely useful, while casting to the scalar types is readily. Also, frankly, function foobar((int) $a, array $b) is inconsistent and ugly.
Note too that the non-scalar types, while they can be casted from, can’t always be casted to. You can cast to an object, but only StdClass, and you can’t cast to resource at all.
I really don’t think there’s anything wrong with having one system for the scalar types and one for the non-scalar types since they’re so different.
Andrea Faulds
http://ajf.me/
We can discuss when the E_* should be emitted separately from what the cast result is.
Is there any actual controversy over what the result of casts should be. This RFC just has the normal casting result. Is anyone really in disagreement there?
Well, I think the behaviour of ' 42' and '42 ' passed as int could be
worth reviewing.
As long as it's an error of some kind it may be OK, but perhaps we want to leave array as is (strict behavior) rather than changing it to the primitive logic (cast behaviour)?
I think the discussion about how arrays should be casted too for consistency is a bit silly. What makes sense for non-scalar types (strict hinting) may not work so well for scalar types; casting to array is rarely useful, while casting to the scalar types is readily.
I'm not sure I agree with this. I regularly use foreach( (array)$foo as
$bar ) for instance - it has the convenient behaviour of looping zero
times for null, once for a scalar, and leaving an existing array alone.
Objects are definitely a different case, because they have a lot of
unique behaviour (class hierarchies, additional reference indirection,
etc). It sometimes makes sense to bundle arrays with objects, in terms
of "scalar vs non-scalar", but other times it makes more sense to think
of "simple types (including arrays) vs objects". A mutable, unbounded
string isn't really "scalar" in the same way as a fixed-size integer,
anyway.
Also, frankly, function foobar((int) $a, array $b) is inconsistent and ugly.
Ugly, maybe, but less inconsistent than having function foobar(int $a,
array $b) { } foobar('a', 'b'); perform a cast to 0 on $a but a fatal
error for $b.
If there were a mixed syntax, you'd probably be using the cast type for
both anyway: function foobar((int) $a, (array) $b)
Still, the mixed validate-and-cast approach of this RFC gets around this
nicely, because there is no "safe cast" to an array available, so no
case that needs addressing. This doesn't really have to do with it being
"non-scalar" per se, just that there's no "natural" type-juggling like
there is for '123' => int or '1.5' => float.
--
Rowan Collins
[IMSoP]
Hello!
As a user land developer I do think that over thinking this is going to end
up in disaster.
We already have quite good implementation for the array and object hints,
they do their job and do it good. No need to change those at all - leave
them as is - no need to add magic with casts and all that. Function/method
requires an array? Make casts explicitly and pass it an array and not an
integer.
Primitive type hints are a little different - they are easily cast into
each other for the most part. The only edge case is when we loose data. In
this case we need a E_STRICT
or something like that (I would vote for
E_TYPEHINT_CAST - because you will be able to disable only typehint
warnings/errors without disabling E_STRICT), so we can collect these errors
and fix our code by adding checks/casts/whatever. But this automatic
casting should work only between string, integer, float, bool and null
types and only between these. No automatic casting of these 5 to arrays or
objects.
PHP does not need a type hinting system forces you to first make a
prototype without any type hints because you get catchable errors - you can
handle them, but you can't actually just continue right where the error
occurred. You just need to get a warning, that you can disable via
error_reporting, and just make your prototype with all the type hints you
need and deal with the cast warnings in the type hints later on.
P.S. And on that "var integer $variable" in methods/functions. People, when
you have internal functions returning null|array, bool|array and so on -
this is pointless.
Arvids Godjuks wrote (on 14/07/2014):
We already have quite good implementation for the array and object hints,
they do their job and do it good. No need to change those at all - leave
them as is - no need to add magic with casts and all that. Function/method
requires an array? Make casts explicitly and pass it an array and not an
integer.
Yes, I totally agree. What I don't think makes sense is for the keyword
"array" in a function signature to mean "error if a string is passed",
but the keyword "int" in exactly the same place to mean "happily accept
any string (or even an array) and cast it to int, even if it's a lossy
conversion".
If there is to be a short-hand for casts in function signatures, it
should not reuse the current syntax for type assertions, as they are not
equivalent facilities.
But this automatic
casting should work only between string, integer, float, bool and null
types and only between these. No automatic casting of these 5 to arrays or
objects.
Rather than special-casing this for "static types" (despite the fact
that arrays can be cast from other types) I would prefer to see it
only happen where it can be lossless (which is never the case for
arrays, thus making the current logic consistent with the new rule).
This is essentially what the current RFC proposes.
I don't think that's actually overthinking it any more than the scalar
vs non-scalar version would, as it's a pretty easy rule to express.
Broadly, if (source_type)(target_type)$var == $var, that's a lossless
cast. (There are a couple of odd exceptions with very specific values,
such as (int)(array)1 == 1, but it's not too much of a stretch to say
"all array casts are considered lossy".)
You just need to get a warning, that you can disable via
error_reporting, and just make your prototype with all the type hints you
need and deal with the cast warnings in the type hints later on.
As I've said elsewhere, I see the usefulness of emitting warnings of
some kind for "lossy" casts as a separate question from the usefulness
of performing such casts inline in function signatures. It makes sense
for the language to implement both at once, but for the user to be able
to use them separately (e.g. catch lossy conversion in existing uses of
(int)$foo).
Regards,
Rowan Collins
[IMSoP]
2014-07-14 15:41 GMT+03:00 Rowan Collins rowan.collins@gmail.com:
Arvids Godjuks wrote (on 14/07/2014):
We already have quite good implementation for the array and object hints,
they do their job and do it good. No need to change those at all - leave
them as is - no need to add magic with casts and all that. Function/method
requires an array? Make casts explicitly and pass it an array and not an
integer.Yes, I totally agree. What I don't think makes sense is for the keyword
"array" in a function signature to mean "error if a string is passed", but
the keyword "int" in exactly the same place to mean "happily accept any
string (or even an array) and cast it to int, even if it's a lossy
conversion".If there is to be a short-hand for casts in function signatures, it should
not reuse the current syntax for type assertions, as they are not
equivalent facilities.But this automatic
casting should work only between string, integer, float, bool and null
types and only between these. No automatic casting of these 5 to arrays or
objects.Rather than special-casing this for "static types" (despite the fact that
arrays can be cast from other types) I would prefer to see it only happen
where it can be lossless (which is never the case for arrays, thus making
the current logic consistent with the new rule). This is essentially what
the current RFC proposes.I don't think that's actually overthinking it any more than the scalar vs
non-scalar version would, as it's a pretty easy rule to express. Broadly,
if (source_type)(target_type)$var == $var, that's a lossless cast. (There
are a couple of odd exceptions with very specific values, such as
(int)(array)1 == 1, but it's not too much of a stretch to say "all array
casts are considered lossy".)
There is no special casing, Array and Object type hints are already
implemented and are in the language for quite a long time. Just don't touch
them, that's all I ask. Implement scalar hints and because of the nature of
PHP - they need to have type casting built in. Otherwise you are forced to
typecast on your own everything that comes from the outside sources:
GET/POST/Databases/API's/REST/the whole lot. If it was a correct string
that was converted to an int/float without any data loss - keep calm and
carry on.
Arvids Godjuks wrote (on 14/07/2014):
There is no special casing, Array and Object type hints are already
implemented and are in the language for quite a long time. Just don't
touch them, that's all I ask.
The special case existing for backwards compatibility doesn't make it
less of a special case. Imagine you're writing a tutorial, from scratch,
after this feature is implemented: you will need to document two
divergent behaviours.
From my point of view, if the type annotations are doing implicit cast (with or without E_NOTICE/E_STRICT warning), they should behave exactly the same than an explicit cast. If it behaves differently, I'll be really difficult for a developer to guess what will be the PHP behaviour with this new syntax.
Well, they do. The results of implicit scalar type hint casts are, so far as I know, the same as explicit casts, but some cases lead to errors which don’t in an explicit casts.
--
Andrea Faulds
http://ajf.me/
From my point of view, if the type annotations are doing implicit cast
(with or without E_NOTICE/E_STRICT warning), they should behave
exactly the same than an explicit cast. If it behaves differently,
I'll be really difficult for a developer to guess what will be the PHP
behaviour with this new syntax.
The problem is, in PHP an explicit type cast never fails - (int)'abc'
simply gives you the value 0, not an error. If you let scalar typehints
just generate unchecked casts, we'd have this:
wants_object(object $foo) { var_dump($foo); }
wants_int(int $foo) { var_dump($foo); }
wants_object('abc'); // fails with E_RECOVERABLE_ERROR
wants_int('abc'); // succeeds and prints int(0)
That seems both inconsistent and less useful than a hybrid juggling +
validation approach.
--
Rowan Collins
[IMSoP]
From my point of view, if the type annotations are doing implicit cast (with or without E_NOTICE/E_STRICT warning), they should behave exactly the same than an explicit cast. If it behaves differently, I'll be really difficult for a developer to guess what will be the PHP behaviour with this new syntax.
The problem is, in PHP an explicit type cast never fails - (int)'abc' simply gives you the value 0, not an error. If you let scalar typehints just generate unchecked casts, we'd have this:
wants_object(object $foo) { var_dump($foo); }
wants_int(int $foo) { var_dump($foo); }wants_object('abc'); // fails with
E_RECOVERABLE_ERROR
wants_int('abc'); // succeeds and prints int(0)
Depending on the final implementation, the latter may raise a notice about information loss.
That seems both inconsistent and less useful than a hybrid juggling + validation approach.
While this is indeed inconsistent, scalars and objects aren’t the same thing, though, and I think it’s okay to treat them differently.
--
Rowan Collins
[IMSoP]
Le 13/07/2014 17:17, Rowan Collins a écrit :
From my point of view, if the type annotations are doing implicit cast
(with or without E_NOTICE/E_STRICT warning), they should behave
exactly the same than an explicit cast. If it behaves differently,
I'll be really difficult for a developer to guess what will be the PHP
behaviour with this new syntax.The problem is, in PHP an explicit type cast never fails - (int)'abc'
simply gives you the value 0, not an error.
Yes, but if you add a E_NOTICE
/ E_STRICT
warning with this cast, you'll
be aware something wrong could happen with this code, and you'd better
explicit cast your variable.
If you let scalar typehints
just generate unchecked casts, we'd have this:wants_object(object $foo) { var_dump($foo); }
wants_int(int $foo) { var_dump($foo); }wants_object('abc'); // fails with
E_RECOVERABLE_ERROR
wants_int('abc'); // succeeds and prints int(0)
Actually it would be
wants_object('abc'); // fails with E_RECOVERABLE_ERROR
wants_int('abc'); // succeeds and prints int(0) + E_NOTICE
/ E_STRICT
warning
That seems both inconsistent and less useful than a hybrid juggling +
validation approach.
Than means you find currently inconsistant than
$foo = (int) 'abc';
works but not
$bar = (object) 'abc';
? :)
Jocelyn
That seems both inconsistent and less useful than a hybrid juggling +
validation approach.Than means you find currently inconsistant than
$foo = (int) 'abc';
works but not
$bar = (object) 'abc';
? :)
Well, the ability to cast to an object at all is pretty wacky, since PHP
has no standard base class for objects, nor any mechanism to cast to or
from specific classes, etc.
Perhaps this example is more appropriate:
function wants_array(array $foo) { var_dump($foo); }
wants_array('abc'); // Error
wants_array( (array)'abc' ); // OK - parameter passed is array(0 => 'abc')
As you can see, it's perfectly possible for the value to be cast, but
the "type hint" does not do so, it rejects the value.
Previous proposals (e.g. 1) have suggested a distinct syntax for the
"automatic cast" which you seem to be favouring, which would allow us to
write this, avoiding the inconsistency:
function casts_to_array((array) $foo) { var_dump($foo); }
casts_to_array('abc'); // OK - parameter interpreted as (array)'abc' and
thus array(0 => 'abc')
This is just sugar for:
function casts_to_array($foo) { $foo = (array)$foo; var_dump($foo); }
As such, it neither requires, nor is required for, additional warnings
around lossy casts.
--
Rowan Collins
[IMSoP]
Well, the ability to cast to an object at all is pretty wacky, since PHP has no standard base class for objects, nor any mechanism to cast to or from specific classes, etc.
Somewhat off-topic, but maybe we should make StdClass be the actual base class? I mean, it’s already used as a generic object, and you could then put StdClass as a type hint if you’re using an object as a key/value store but want to allow sophisticated objects to be passed.
Also, we don’t have a mechanism to cast between classes mostly because we don’t need it; if Bar extends Foo and a function takes a Foo, it can also take a Bar.
Andrea Faulds
http://ajf.me/
Le 13/07/2014 17:51, Rowan Collins a écrit :
That seems both inconsistent and less useful than a hybrid juggling +
validation approach.Than means you find currently inconsistant than
$foo = (int) 'abc';
works but not
$bar = (object) 'abc';
? :)
Well, the ability to cast to an object at all is pretty wacky, since PHP
has no standard base class for objects, nor any mechanism to cast to or
from specific classes, etc.Perhaps this example is more appropriate:
function wants_array(array $foo) { var_dump($foo); }
wants_array('abc'); // Error
wants_array( (array)'abc' ); // OK - parameter passed is array(0 => 'abc')As you can see, it's perfectly possible for the value to be cast, but
the "type hint" does not do so, it rejects the value.
If "type hint" is doing exactly the same than explicit cast, it should
not fail on wants_array('abc'), but give a warning about the implicit
cast conversion.
Jocelyn
If "type hint" is doing exactly the same than explicit cast, it should
not fail on wants_array('abc'), but give a warning about the implicit
cast conversion.
Agreed, but that's a very big "if", and is not what this RFC is
proposing at all. Nor could it cleanly use the current syntax, since
function foo(array $foo) is already valid, and does not perform such a cast.
If you haven't already, please do read Nikita's article which has been
linked several times in this thread, which discusses the different
options. This proposal is closer to "strict weak type hinting" than
"casting weak type hinting"; it differs in performing a non-lossy
cast, rather than just asserting the possibility of one.
Regards,
--
Rowan Collins
[IMSoP]
Le 13/07/2014 18:15, Rowan Collins a écrit :
If "type hint" is doing exactly the same than explicit cast, it should
not fail on wants_array('abc'), but give a warning about the implicit
cast conversion.Agreed, but that's a very big "if", and is not what this RFC is
proposing at all. Nor could it cleanly use the current syntax, since
function foo(array $foo) is already valid, and does not perform such a
cast.
I agree if we cast, the current "array" behaviour needs to be changed.
And if we don't change this behaviour, it would be logical the "type
hint" correspond to a strict check for all the type used (there's no
reason why array should be an exception).
If you haven't already, please do read Nikita's article which has been
linked several times in this thread, which discusses the different
options. This proposal is closer to "strict weak type hinting" than
"casting weak type hinting"; it differs in performing a non-lossy
cast, rather than just asserting the possibility of one.
I do, but I just voice that as a PHP developer I don't like this
approach much, and I prefer the approach of casting + warning as a good
compromise :)
Jocelyn
In other words, if someone types in '12a'
(by mistake or intentionally), I think it's a very sane behavior to just
treat it as 12, as opposed to forcing me (the developer) to write error
handling code with a try/catch block, and a fairly hairy try/catch block
too.
Sure, but what if they type 'abc'? You might want that to be cast as 0
(not for an age input, obviously, but perhaps a "minimum price" field),
so you could argue for always casting, rather than erroring. On the
other hand, you might well want to default to some other value, which
would require custom handling somewhere.
If you want to allow for people accidentally adding letters, why
accept '12a' but not 'a12'? If you want a "best guess", surely both
should come out as 12 (whereas an integer cast would give you 0 for the
latter). If you want validation, both are equally invalid.
To my mind, the more values are let through with a bit of hand-waving,
the less useful the check is. The worst culprit for this is
is_numeric()
, which sounds like a useful general-purpose function, but
will happily accept exotic numbers like '-1e-10', and thus is almost
never what you want.
Your example of "12 " (that I didn't even think about before) is an
even a more likely scenario, but I think there's no strong reason not to
allow both.
I disagree, and think there's a stronger argument to be made for
handling whitespace as a special case. Notably, int casts already do so
- (int)' 12' (leading space) is 12, but (int)'a12' (leading non-digit)
is 0 (no such special case is needed for trailing whitespace, because
any trailing characters are ignored.)
Regards,
--
Rowan Collins
[IMSoP]
I haven't yet closely reviewed the details of what is and isn't allowed,
but one
things I would strongly recommend against is introducing any "accept but
throw a notice" cases. Either a value is allowed or it isn't.
"12foo" to an int/float argument should throw a recoverable fatal error,
like
everything else. (I'd change that in zpp as well, but that's a different
discussion).
The use case of converting string based values into integers and floating
point numbers is a very common one, given anything that comes into PHP as
input is a string. In terms of productivity, it's much easier for me to
stick an 'int' type hint (or whatever we call it) on a piece of $_GET value
that I know needs to be an integer, than it is for me to now surround it in
a try/catch block and protect against a user or a wannabe hacker sending in
'123abc' in there. In such a case treating this as 123 (int) makes perfect
sense, with the erroneous input silently converted to something sane the
code can live with. A key advantage of these casting type hints is saving
the need to write lengthy and somewhat obscure pieces of code that just
validate inputs. If we force developers to surround them with try/catch
blocks, we lose at least half of the value here IMHO.
I therefore think conversion from string to any of the basic types should
never result in an exception even if information is lost; And it does make
The question of passing floats like 12.5 to an int param is somewhat
tricky.
One could argue that it's possible to end up with floats like
12.0000000001,
which are nearly integers but not quite there, and a user might expect
them
to behave the same as the integer 12. On the other hand one can also argue
that it's easy to end up with the inverse, namely 11.999999999999. In this
case the end user might also expect it to be treated as integer 12,
however an
integer cast will truncate it to 11.The truncation behavior of the float to int cast is why I tend towards the
behavior the RFC currently proposes (forbid non-integral floats): It is
rather
unlikely that truncation is what was intended, as such an explicit
rounding call
is necessary anyways.
I'm undecided on this one too.
Zeev
First of all thanks for this proposal. In general I’m hugely in favour of this approach.
One thing however seems like a rather bad idea, and that is exposing the type of resource in this way. Resources are not compatible between each other, making such a hint not very useable. If people start adding this hint to their methods it will also make it much harder to change resources into objects (like it has been done for gmp and I have a pull request for hash)
Best regards
Rouven
First of all thanks for this proposal. In general I’m hugely in favour of this approach.
One thing however seems like a rather bad idea, and that is exposing the type of resource in this way. Resources are not compatible between each other, making such a hint not very useable. If people start adding this hint to their methods it will also make it much harder to change resources into objects (like it has been done for gmp and I have a pull request for hash)
Those are good points. Is there any sane way to hint for them, then?
--
Andrea Faulds
http://ajf.me/
One thing however seems like a rather bad idea, and that is exposing the type of resource in this way. Resources are not compatible between each other, making such a hint not very useable. If people start adding this hint to their methods it will also make it much harder to change resources into objects (like it has been done for gmp and I have a pull request for hash)
Those are good points. Is there any sane way to hint for them, then?
I don’t think so. I suggest leaving them out for now. I hope we’ll see mores resources converted into classes but if that doesn’t happen hinting for resources can still be addressed later.
Best regards
Rouven
One thing however seems like a rather bad idea, and that is exposing the type of resource in this way. Resources are not compatible between each other, making such a hint not very useable. If people start adding this hint to their methods it will also make it much harder to change resources into objects (like it has been done for gmp and I have a pull request for hash)
Those are good points. Is there any sane way to hint for them, then?
I don’t think so. I suggest leaving them out for now. I hope we’ll see mores resources converted into classes but if that doesn’t happen hinting for resources can still be addressed later.
I agree, and after asking Anthony about it, I’ve removed the resource type hint from the RFC and patch. Besides, it isn’t really a scalar type (in its semantics, at least) anyway, and there’s no cast operator for it.
Andrea Faulds
http://ajf.me/
Hello again,
One of the issues with the RFC as it stands is how to handle bool casting. While int, float and string only allow lossless casting (with the exception of objects, but we can’t really do anything about that), bool’s behaviour at the moment is quite different. I don’t think it makes sense so I won’t discuss the current behaviour, only possible new ones.
One option is simply to forget about being lossless and make the bool type hint accept any value, meaning any truthy value or any falsey value would yield what is expected without error. This would ensure that if some stupid programmer (like myself ;) has passed in a non-boolean truthy/falsey value to your function, it’ll be handled correctly. It would mean all your bit hacks ($foo & FLAG etc.) would work, anything you got from $_GET (e.g. ?foobar=1). However, this is unlikely to catch bugs in code, because literally any PHP value would work. For that reason, I’m not sure this is the way forward.
Another option is go completely strict and allow only boolean values, failing everything else. This would be unlike the int, float and string hints, which are flexible and cast, but would be more helpful for catching bugs. However, not casting at all isn’t very “PHP-like”, and forcing people to manually cast with (bool) might not be ideal. If we were to go for this one, I might also accept objects casting to bool (which the default handler does), because I don’t want to stop extension developers from making bool-like objects if they so please.
The final option I’m thinking about is a limited set of values. TRUE, FALSE
and NULL
would be accepted, along with the integer and float values 1 and 0 (which are the int/float TRUE
and FALSE
cast to, respectively), ‘1’ and the empty string (which are the string values TRUE
and FALSE
cast to), and ‘0’ (which (string)(int)FALSE would give you), along with objects casting to boolean. It’s not a perfect solution, but I currently feel that this is the most sensible option bar going for full strictness.
I’m not really decided, however. Every time I try to think about this, I usually end up going in circles. Anthony doesn’t seem to be decided either. Hence I’m putting this up for discussion.
What are your thoughts?
--
Andrea Faulds
http://ajf.me/
One of the issues with the RFC as it stands is how to handle bool casting. While int, float and string only allow lossless casting (with the exception of objects, but we can’t really do anything about that), bool’s behaviour at the moment is quite different. I don’t think it makes sense so I won’t discuss the current behaviour, only possible new ones.
One option is simply to forget about being lossless and make the bool type hint accept any value, meaning any truthy value or any falsey value would yield what is expected without error. This would ensure that if some stupid programmer (like myself ;) has passed in a non-boolean truthy/falsey value to your function, it’ll be handled correctly. It would mean all your bit hacks ($foo & FLAG etc.) would work, anything you got from $_GET (e.g. ?foobar=1). However, this is unlikely to catch bugs in code, because literally any PHP value would work. For that reason, I’m not sure this is the way forward.
I don’t think that "scalar casts” should do any additional error-catching. they target a very different usecase.
It shouldn’t guarantee correctness of the whole program. It should guarantee that variable types are fixed inside of function.
In my opinion, this patch should act 100% similar to zpp.
And if, at some later point zpp-behaviour changes similar change should happen to userland "scalar casts"
Some people talk about inconsistency, which is introduced by reusing same syntax for "strict parameter types" and "scalar parameter casts”. There’s some truth there.
Let’s use different syntax.
This might work:
function foo((int) $a)
{
var_dump($a);
}
I would read it as declaration-level casting
--
Alexey Zakhlestin
CTO at Grids.by/you
https://github.com/indeyets
PGP key: http://indeyets.ru/alexey.zakhlestin.pgp.asc
Hi,
Some people talk about inconsistency, which is introduced by reusing same syntax for "strict parameter types" and "scalar parameter casts”. There’s some truth there.
Let’s use different syntax.This might work:
function foo((int) $a) { var_dump($a); }
I would read it as declaration-level casting
I strongly support this.
What we currently have with class/array typing is a different behavior
(regardless of the details behind it), and this syntax would make that
noticeable, which is a great thing.
Cheers,
Andrey.
Andrey Andreev wrote (on 14/07/2014):
Hi,
Some people talk about inconsistency, which is introduced by reusing same syntax for "strict parameter types" and "scalar parameter casts”. There’s some truth there.
Let’s use different syntax.This might work:
function foo((int) $a) { var_dump($a); }
I would read it as declaration-level casting
I strongly support this.What we currently have with class/array typing is a different behavior
(regardless of the details behind it), and this syntax would make that
noticeable, which is a great thing.Cheers,
Andrey.
Please could you both read the existing messages in this thread. Yes,
that has been proposed already, and several people support it.
It is not, however, what is currently proposed in this RFC, or what
Andrea is asking in this post (which is a refinement of the RFC, not an
alternative to it).
(Yes, I realise catching up with the whole thread might be hard work,
I'm just worried we're going round in circles, as each new person to
join the thread brings up all the same points that have been discussed
already.)
Regards,
Rowan Collins
[IMSoP]
Andrey Andreev wrote (on 14/07/2014):
Hi,
On Mon, Jul 14, 2014 at 4:12 PM, Alexey Zakhlestin indeyets@gmail.com
wrote:Some people talk about inconsistency, which is introduced by reusing same
syntax for "strict parameter types" and "scalar parameter casts”. There’s
some truth there.
Let’s use different syntax.This might work:
function foo((int) $a) { var_dump($a); }
I would read it as declaration-level casting
I strongly support this.
What we currently have with class/array typing is a different behavior
(regardless of the details behind it), and this syntax would make that
noticeable, which is a great thing.Cheers,
Andrey.Please could you both read the existing messages in this thread. Yes, that
has been proposed already, and several people support it.It is not, however, what is currently proposed in this RFC, or what Andrea
is asking in this post (which is a refinement of the RFC, not an alternative
to it).(Yes, I realise catching up with the whole thread might be hard work, I'm
just worried we're going round in circles, as each new person to join the
thread brings up all the same points that have been discussed already.)
I've been following the thread so far.
All I'm suggesting is to alter the proposed syntax, keeping the rest
of the RFC the same.
Cheers,
Andrey.
Hi,
Le 14/07/2014 15:19, Andrey Andreev a écrit :
Hi,
Some people talk about inconsistency, which is introduced by reusing same syntax for "strict parameter types" and "scalar parameter casts”. There’s some truth there.
Let’s use different syntax.This might work:
function foo((int) $a) { var_dump($a); }
I would read it as declaration-level casting
I strongly support this.
What we currently have with class/array typing is a different behavior
(regardless of the details behind it), and this syntax would make that
noticeable, which is a great thing.
Actually both syntax could exists :
function foo((int) $a)
{
=> scalar parameter casts syntax
function foo(int $a)
{
=> strict type checking syntax (consistant with array / class syntax)
I like this approach as well.
Jocelyn
Actually both syntax could exists :
function foo((int) $a)
{=> scalar parameter casts syntax
function foo(int $a)
{=> strict type checking syntax (consistant with array / class syntax)
I believe supporting both syntaxes has also been proposed in the past. That isn’t this proposal and this proposal is not going to become that one.
--
Andrea Faulds
http://ajf.me/
Oh, goodness, deary me -- this sounded so familiar I just had to do some delving and hey presto! I refer you to: http://marc.info/?l=php-internals&m=124655821522388
(...which, interestingly, even predates Zeev's 2010 claim, and I believe may have taken inspiration from yet earlier suggestions back around 2006!!)
--
Mike Ford, Electronic Information Developer, Libraries and Learning Innovation
Leeds Metropolitan University, 403a Sheila Silver Library, Leslie Silver Building, City Campus, Leeds LS1 3ES, United Kingdom
Tel: +44 113 812 4730 | Email: m.ford@leedsmet.ac.uk
-----Original Message-----
From: Jocelyn Fournier [mailto:jocelyn.fournier@gmail.com]
Sent: 14 July 2014 14:30
To: narf@devilix.net
Cc: internals@lists.php.net; indeyets@gmail.com; Andrea Faulds
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-
opening)Hi,
Le 14/07/2014 15:19, Andrey Andreev a écrit :
Hi,
On Mon, Jul 14, 2014 at 4:12 PM, Alexey Zakhlestin
indeyets@gmail.com wrote:Some people talk about inconsistency, which is introduced by
reusing same syntax for "strict parameter types" and "scalar
parameter casts”. There’s some truth there.
Let’s use different syntax.This might work:
function foo((int) $a) { var_dump($a); }
I would read it as declaration-level casting
I strongly support this.
What we currently have with class/array typing is a different
behavior
(regardless of the details behind it), and this syntax would make
that
noticeable, which is a great thing.Actually both syntax could exists :
function foo((int) $a)
{=> scalar parameter casts syntax
function foo(int $a)
{=> strict type checking syntax (consistant with array / class
syntax)I like this approach as well.
Jocelyn
--
From 22 September 2014 Leeds Metropolitan University will become Leeds Beckett University.
Find out more at http://www.leedsbeckett.ac.uk
To view the terms under which this email is distributed, please go to:-
http://www.leedsmet.ac.uk/email-disclaimer.htm
Ford, Mike wrote (on 15/07/2014):
Oh, goodness, deary me -- this sounded so familiar I just had to do some delving and hey presto! I refer you to:http://marc.info/?l=php-internals&m=124655821522388
(...which, interestingly, even predates Zeev's 2010 claim, and I believe may have taken inspiration from yet earlier suggestions back around 2006!!)
Ooh, skimming that, I see suggestions for prefixes and suffixes to
represent types of cast (or hint).
That fits nicely with my thoughts on making "strict cast" a first-class
citizen of the language, rather than isolating it to function
signatures, e.g.:
$foo = 'abc'; $foo = (int)$foo; // OK, evaluates to int(0)
$foo = 'abc'; $foo = (int!)$foo; // ERROR
$foo = '42'; $foo = (int!)$foo; // OK, evaluates to int(42)
Ooh, skimming that, I see suggestions for prefixes and suffixes to represent types of cast (or hint).
That fits nicely with my thoughts on making "strict cast" a first-class citizen of the language, rather than isolating it to function signatures, e.g.:
$foo = 'abc'; $foo = (int)$foo; // OK, evaluates to int(0)
$foo = 'abc'; $foo = (int!)$foo; // ERROR
$foo = '42'; $foo = (int!)$foo; // OK, evaluates to int(42)
It’s a shame Nikita’s Exceptions in the Engine RFC failed, as being able to do this would be nice:
try {
$foo = (int!)$foo;
} catch (RecoverableError) {
$foo = 1;
}
Perhaps some sort of similar syntax? (int!)$foo else 0
?
Andrea Faulds
http://ajf.me/
I don’t think that "scalar casts” should do any additional error-catching. they target a very different usecase.
It shouldn’t guarantee correctness of the whole program. It should guarantee that variable types are fixed inside of function.
That is exactly what is being proposed though. People (including Anthony himself, along with other proposals) have previously suggested type hints which just casted. However, I don’t think this is terribly useful. You can already do that really easily ($foo = (int)$foo;
), and it’s too lenient; the non-scalar type hints are useful because they validate your types, and the scalar ones, while casting, should validate to a degree.
In my opinion, this patch should act 100% similar to zpp.
And if, at some later point zpp-behaviour changes similar change should happen to userland "scalar casts”
Keeping close to zpp would be nice, but zpp’s behaviour isn’t always the most sensible and useful one, but we should try to keep somewhat close to it.
Some people talk about inconsistency, which is introduced by reusing same syntax for "strict parameter types" and "scalar parameter casts”. There’s some truth there.
Let’s use different syntax.This might work:
function foo((int) $a)
{
var_dump($a);
}I would read it as declaration-level casting
That has already been proposed. That is not this proposal. I’d suggest you read back in this thread; I’ve previously explained my issues with just casting with no validation, pure strict type hints, why it’s fine to reüse the syntax, and linked to Nikita Popov’s blog post on the subject.
--
Andrea Faulds
http://ajf.me/
I don’t think that "scalar casts” should do any additional error-catching. they target a very different usecase.
It shouldn’t guarantee correctness of the whole program. It should guarantee that variable types are fixed inside of function.That is exactly what is being proposed though.
My bad, I meant “that is not what is being proposed”.
Andrea Faulds
http://ajf.me/
Hi!
That is exactly what is being proposed though. People (including
Anthony himself, along with other proposals) have previously
suggested type hints which just casted. However, I don’t think this
is terribly useful. You can already do that really easily ($foo = (int)$foo;
), and it’s too lenient; the non-scalar type hints are
useful because they validate your types, and the scalar ones, while
casting, should validate to a degree.
PHP is weakly typed language, and 100% of existing code is written under
such assumption. If you mean to convert it to strictly typed language,
it won't be PHP. If you mean to make one small piece of it strictly
typed, while the rest is not, it would not give you the advantage of
strict typing (since you still can not prove anything about your code
beyond a very small piece of it) but give you all the disadvantages such
as increased development effort, more boilterplate code, etc.
Keeping close to zpp would be nice, but zpp’s behaviour isn’t always
the most sensible and useful one, but we should try to keep somewhat
close to it.
If zpp behavior is not sensible, we should change it. However, having
consistent conversion rules is much better than have two sets of rules,
each of which make only a little sense, and forcing users to guess by
which set of rules they play each time. We have PHP.next where we can
break things, if some things in ZPP make no sense, we can break them and
fix them and have a good set of rules that does make sense. It is much
better than having two of them.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
Hello again,
One of the issues with the RFC as it stands is how to handle bool casting. While int, float and string only allow lossless casting (with the exception of objects, but we can’t really do anything about that), bool’s behaviour at the moment is quite different. I don’t think it makes sense so I won’t discuss the current behaviour, only possible new ones.
One option is simply to forget about being lossless and make the bool type hint accept any value, meaning any truthy value or any falsey value would yield what is expected without error. This would ensure that if some stupid programmer (like myself ;) has passed in a non-boolean truthy/falsey value to your function, it’ll be handled correctly. It would mean all your bit hacks ($foo & FLAG etc.) would work, anything you got from $_GET (e.g. ?foobar=1). However, this is unlikely to catch bugs in code, because literally any PHP value would work. For that reason, I’m not sure this is the way forward.
Another option is go completely strict and allow only boolean values, failing everything else. This would be unlike the int, float and string hints, which are flexible and cast, but would be more helpful for catching bugs. However, not casting at all isn’t very “PHP-like”, and forcing people to manually cast with (bool) might not be ideal. If we were to go for this one, I might also accept objects casting to bool (which the default handler does), because I don’t want to stop extension developers from making bool-like objects if they so please.
The final option I’m thinking about is a limited set of values. TRUE,
FALSE
andNULL
would be accepted, along with the integer and float values 1 and 0 (which are the int/floatTRUE
andFALSE
cast to, respectively), ‘1’ and the empty string (which are the string valuesTRUE
andFALSE
cast to), and ‘0’ (which (string)(int)FALSE would give you), along with objects casting to boolean. It’s not a perfect solution, but I currently feel that this is the most sensible option bar going for full strictness.I’m not really decided, however. Every time I try to think about this, I usually end up going in circles. Anthony doesn’t seem to be decided either. Hence I’m putting this up for discussion.
What are your thoughts?
--
Andrea Faulds
http://ajf.me/
I've already said this in IRC but summing up for the benefit of everyone else:
-
We already have a place where there is an implicit boolean cast,
namely if ($var). Personally I would find it somewhat
counter-intuitive if a parameter declared as bool didn't behave the
same way. -
A common-ish use case here would be:
function foo(bool $bool) {}
foo($flags & A_FLAG);
The intent of the expression $flags & A_FLAG is obvious to the reader
as fetching a boolean, but the result will often be an integer that is
neither 1 nor 0. This cannot be handled by foo((bool)$flags & A_FLAG);
because of precedence, foo((bool)($flags & A_FLAG)); is messy. Andrea
suggested foo($flags & A_FLAG != 0); which is better but still a
little messy.
Personally I would rather just accept data loss and stay consistent
with the rest of the language (i.e. condition evaluation), but I do
understand the PoV of those resistant to it.
- A common-ish use case here would be:
function foo(bool $bool) {}
foo($flags & A_FLAG);The intent of the expression $flags & A_FLAG is obvious to the reader
as fetching a boolean, but the result will often be an integer that is
neither 1 nor 0. This cannot be handled by foo((bool)$flags & A_FLAG);
because of precedence, foo((bool)($flags & A_FLAG)); is messy. Andrea
suggested foo($flags & A_FLAG != 0); which is better but still a
little messy.Personally I would rather just accept data loss and stay consistent
with the rest of the language (i.e. condition evaluation), but I do
understand the PoV of those resistant to it.
Yeah, that’s the problem for me. I want things like ($flags & A_FLAG) to work, but I don’t want “foo” to work.
I suggested on IRC that empty strings, TRUE, FALSE, NULL, and values that validate for the int type hint could be accepted. Is that a good idea? Though it feels a bit loose, I think it covers all the important common use cases.
--
Andrea Faulds
http://ajf.me/
Hi!
I suggested on IRC that empty strings, TRUE, FALSE, NULL, and values
that validate for the int type hint could be accepted. Is that a good
idea? Though it feels a bit loose, I think it covers all the
important common use cases.
Then you need to make all internal functions that accept bool work this
way too. But I'm not sure why you need this. You accept that if("foo")
works. Then why "function foo(bool $x) { if($x) { ... " should work
differently? Yes, it is an edge case and bad code style. So are many
other legal constructs. In my opinion, it is better to permit edge cases
and be consistent than try to carve out perfect set of "what can be
boolean" and get lost in the maze of exceptions and conditions. E.g. if
we say we treat 1 and "1" mostly the same, then we should say "unless we
convert them to bool in a context of a function call where they are
not". I think it should be kept simpler - if we accept "foo" in boolean
context, then we should just accept it.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
-----Original Message-----
From: Stas Malyshev [mailto:smalyshev@sugarcrm.com]
Sent: Tuesday, July 15, 2014 2:00 AM
To: Andrea Faulds; Chris Wright
Cc: PHP internals
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)Hi!
I suggested on IRC that empty strings, TRUE, FALSE, NULL, and values
that validate for the int type hint could be accepted. Is that a good
idea? Though it feels a bit loose, I think it covers all the important
common use cases.Then you need to make all internal functions that accept bool work this
way
too. But I'm not sure why you need this. You accept that if("foo") works.
Then
why "function foo(bool $x) { if($x) { ... " should work differently? Yes,
it is an
edge case and bad code style. So are many other legal constructs. In my
opinion, it is better to permit edge cases and be consistent than try to
carve
out perfect set of "what can be boolean" and get lost in the maze of
exceptions and conditions. E.g. if we say we treat 1 and "1" mostly the
same,
then we should say "unless we convert them to bool in a context of a
function
call where they are not". I think it should be kept simpler - if we accept
"foo"
in boolean context, then we should just accept it.
Exactly.
Zeev
Stas Malyshev wrote (on 14/07/2014):
But I'm not sure why you need this. You accept that if("foo")
works. Then why "function foo(bool $x) { if($x) { ... " should work
differently?
The answer - which is definitely a matter of opinion - is that allowing
any string reduces the usefulness of the type hint.
I realise there is not consensus on whether scalar hints should
represent validation, cast, or a mixture, but if we go down the route
of validation, then we have to choose which values are valid and which
are not.
My preference is to keep that strict: the example others have posted of
some_func($foo & BIT_FLAG) seems no more like a "real" boolean to me
than some_func(strlen($foo)) or any other expression which yields an
integer.
In fact, I'd find the behaviour more obvious if it were written
some_func((bool)$foo & BIT_FLAG) - it makes clear that some_func is not
itself aware of the flag, that's just the caller's way of making the
decision. That the type hint encouraged that would therefore seem like a
Good Thing.
(I'd post that comment on the appropriate sub-thread where that example
was raised, but don't have time to find it...)
Regards,
Rowan Collins
[IMSoP]
Stas Malyshev wrote (on 14/07/2014):
But I'm not sure why you need this. You accept that if("foo")
works. Then why "function foo(bool $x) { if($x) { ... " should work
differently?The answer - which is definitely a matter of opinion - is that allowing any string reduces the usefulness of the type hint.
I realise there is not consensus on whether scalar hints should represent validation, cast, or a mixture, but if we go down the route of validation, then we have to choose which values are valid and which are not.
My preference is to keep that strict: the example others have posted of some_func($foo & BIT_FLAG) seems no more like a "real" boolean to me than some_func(strlen($foo)) or any other expression which yields an integer.
In fact, I'd find the behaviour more obvious if it were written some_func((bool)$foo & BIT_FLAG) - it makes clear that some_func is not itself aware of the flag, that's just the caller's way of making the decision. That the type hint encouraged that would therefore seem like a Good Thing.
(I'd post that comment on the appropriate sub-thread where that example was raised, but don't have time to find it…)
Right. For the sake of consistency with the other scalar type hints, I’m current leaning to what I’ve made the RFC do, i.e. be completely strict for booleans. This is because we have string, float and int only allow losslessly convertible, equivalent values. Unfortunately, I’d argue there aren’t really such things for booleans except for true and false. Furthermore, forcing people to cast here isn’t such a bad thing; a cast to bool will always be somewhat lossy, and while explicitly casting to int or float might be dangerous, I can’t think of any place where it’s actually a bad idea to explicitly cast to bool.
--
Andrea Faulds
http://ajf.me/
Hi!
The answer - which is definitely a matter of opinion - is that allowing
any string reduces the usefulness of the type hint.
IMO, having consistent rules is much more, orders of magnitude more
important than serving any particular use case. We will always have use
cases in which any particular check would not be enough. We should not
sacrifice the simplicity of the language to try and capture every one of
them.
In fact, I'd find the behaviour more obvious if it were written
some_func((bool)$foo & BIT_FLAG) - it makes clear that some_func is not
itself aware of the flag, that's just the caller's way of making the
decision. That the type hint encouraged that would therefore seem like a
Good Thing.
What you want is strict typing then. And if() working the same way -
after all, if function can be unaware of the flag, if() is definitely
unaware of it. So you'll always have to write if(($foo & BIT_FLAG) !=
0). Some would say it's an improvement. I am not among them. If you want
to enforce code style, we already have tools for that, but I don't think
this particular one should be in the language.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
Stas Malyshev wrote (on 15/07/2014):
IMO, having consistent rules is much more, orders of magnitude more
important than serving any particular use case
We are adding a new feature to a language which is already inconsistent.
We can only make it consistent with one part of the language by making
it inconsistent with another.
If we take consistency as such a priority that we create a feature that
is not actually useful, we will have wasted our effort, and made the
language worse, not better. Saying "who cares if its useful, as long as
it matches some other part of the language" is a very poor argument IMO.
That's an extreme, and I'm not saying anyone is saying precisely that,
but I am getting rather weary of the back-and-forth over what is
"consistent", rather than thinking about what we want to achieve, and
what is the best way to achieve that.
What you want is strict typing then.
No, I want to introduce the notion of a "lossless cast", allowing things
like (int)'123' to be valid. This distinction has been explained many times.
And if() working the same way -
after all, if function can be unaware of the flag, if() is definitely
unaware of it.
Not necessarily. An if() statement is clearly and unambiguously working
with boolean values. Anyone looking at if( $foo & BIT_FLAG ) can know,
based on basic knowledge of the language, that an implicit cast is
taking place.
Someone looking at my_super_function( $foo & BIT_FLAG ) cannot know
whether that parameter is being interpreted as a boolean or is actually
being measured against that same BIT_FLAG (or some other integer
operation) without consulting the source code (or, at least, trusting
the documentation).
I am not among them. If you want
to enforce code style, we already have tools for that, but I don't think
this particular one should be in the language.
The logical conclusion from that is not to have type hints at all. So
far, that is in fact the only consensus the PHP community has ever
reached - not to have scalar type hints. (I don't mean that you
necessarily hold that position, but it is the logical conclusion of that
particular line of reasoning.)
Regards,
Rowan Collins
[IMSoP]
Stas Malyshev wrote (on 15/07/2014):
IMO, having consistent rules is much more, orders of magnitude more
important than serving any particular use caseWe are adding a new feature to a language which is already inconsistent. We can only make it consistent with one part of the language by making it inconsistent with another.
If we take consistency as such a priority that we create a feature that is not actually useful, we will have wasted our effort, and made the language worse, not better. Saying "who cares if its useful, as long as it matches some other part of the language" is a very poor argument IMO.
That's an extreme, and I'm not saying anyone is saying precisely that, but I am getting rather weary of the back-and-forth over what is "consistent", rather than thinking about what we want to achieve, and what is the best way to achieve that.
I’d argue it’s better to do the right thing here, which is easier, and then do the right thing in the other place later, which is harder, than it is to do the wrong thing now because the other place also does the wrong thing. Having saner implicit casting for scalar type hints will be easier than changing the behaviour of zend_parse_parameters.
What you want is strict typing then.
No, I want to introduce the notion of a "lossless cast", allowing things like (int)'123' to be valid. This distinction has been explained many times.
And if() working the same way -
after all, if function can be unaware of the flag, if() is definitely
unaware of it.Not necessarily. An if() statement is clearly and unambiguously working with boolean values. Anyone looking at if( $foo & BIT_FLAG ) can know, based on basic knowledge of the language, that an implicit cast is taking place.
Someone looking at my_super_function( $foo & BIT_FLAG ) cannot know whether that parameter is being interpreted as a boolean or is actually being measured against that same BIT_FLAG (or some other integer operation) without consulting the source code (or, at least, trusting the documentation).
I am not among them. If you want
to enforce code style, we already have tools for that, but I don't think
this particular one should be in the language.The logical conclusion from that is not to have type hints at all. So far, that is in fact the only consensus the PHP community has ever reached - not to have scalar type hints. (I don't mean that you necessarily hold that position, but it is the logical conclusion of that particular line of reasoning.)
Regards,
Rowan Collins[IMSoP]
--
I, myself, generally agree with all this, though I’m not sure quite whether Anthony does at the moment.
Andrea Faulds
http://ajf.me/
The logical conclusion from that is not to have type hints at all. So far,
that is in fact the only consensus the PHP community has ever reached - not
to have scalar type hints.
I'm sorry, I know what you mean here and I'm not criticizing you
specifically (in fact, I'm intentionally taking it ouf of context),
but that's "PHP internals", not "PHP community".
The PHP community that I know, wants to have both type cast hinting
and strict type declarations.
PHP internals on the other hand, would rather argue to death over
which specific version of the two is the one and true way to rule them
all. We had that with the ArrayOf hints too, which turned into ArrayOf
vs Generics.
Heritage this, history that, consistent with X, inconsistent with Y,
don't forget the special case Z, "use another language", "that's been
proposed already" ... That is why an Nth iteration of scalar type
hinting is being discussed, not because it's so damn hard to do it
right. Doing it right here means to understand that everybody wants
scalar type hinting for different use cases and to try to satisfy use
case A without excluding use case B as a possibility in the future.
Sorry about the rather aggressive remark, but somebody had to say it.
Cheers,
Andrey.
I'm sorry, I know what you mean here and I'm not criticizing you
specifically (in fact, I'm intentionally taking it ouf of context),
but that's "PHP internals", not "PHP community".The PHP community that I know, wants to have both type cast hinting
and strict type declarations.
I’m not sure that’s quite the case. There are camps wanting one, there are camps wanting the other, I suppose some want both, but to me that seems like a not-a-compromise compromise solution. The point of this RFC, to some extent, is to be a reasonable compromise between completely strict declarations and cast hinting, providing the safety of the first and the flexibility of the second. I think it strikes the balance well.
It’s also that I, myself, actually would prefer this proposal to either cast hinting or strict declarations… so that’s three ways to support if we’re going down that route.
Really, I think we should settle on a compromise, not on one way, the other, or both. This RFC is a compromise.
--
Andrea Faulds
http://ajf.me/
I'm sorry, I know what you mean here and I'm not criticizing you
specifically (in fact, I'm intentionally taking it ouf of context),
but that's "PHP internals", not "PHP community".The PHP community that I know, wants to have both type cast hinting
and strict type declarations.I’m not sure that’s quite the case. There are camps wanting one, there are camps wanting the other, I suppose some want both, but to me that seems like a not-a-compromise compromise solution. The point of this RFC, to some extent, is to be a reasonable compromise between completely strict declarations and cast hinting, providing the safety of the first and the flexibility of the second. I think it strikes the balance well.
Unless you really force the camps to pick one by saying "you can't
have Y if we've got X" (to which there's no technical limitation, so
that's not true), then a camp that wants X doesn't mean a camp that
doesn't want Y, so we end up with:
Camps wanting one + camps wanting another == a larger camp that
wants all of it
A compromise isn't excluded by this. It would just have to be a "ok,
let's do X right now and we'll think about Y later" compromise (point
being, don't exclude Y) instead of a "let's have a mixed something
between the two that nobody really, really likes" one.
Unless you really force the camps to pick one by saying "you can't
have Y if we've got X" (to which there's no technical limitation, so
that's not true)
No technical limitation, sure, but it would be really weird for PHP to go in two completely opposite directions at the same time!
I’d prefer a middle path, a “third way” of sorts (hah, another thing stolen from political politics), rather than going in two opposing directions simultaneously.
Andrea Faulds
http://ajf.me/
I'm sorry, I know what you mean here and I'm not criticizing you
specifically (in fact, I'm intentionally taking it ouf of context),
but that's "PHP internals", not "PHP community".The PHP community that I know, wants to have both type cast hinting
and strict type declarations.I’m not sure that’s quite the case. There are camps wanting one, there are camps wanting the other, I suppose some want both, but to me that seems like a not-a-compromise compromise solution. The point of this RFC, to some extent, is to be a reasonable compromise between completely strict declarations and cast hinting, providing the safety of the first and the flexibility of the second. I think it strikes the balance well.
Unless you really force the camps to pick one by saying "you can't
have Y if we've got X" (to which there's no technical limitation, so
that's not true), then a camp that wants X doesn't mean a camp that
doesn't want Y, so we end up with:Camps wanting one + camps wanting another == a larger camp that
wants all of it
A compromise isn't excluded by this. It would just have to be a "ok,
let's do X right now and we'll think about Y later" compromise (point
being, don't exclude Y) instead of a "let's have a mixed something
between the two that nobody really, really likes" one.
To further clarify, it also doesn't mean a promise on Y, just don't
provocate people to bring it up again when it's not the current task.
My $0.02.
Andrey Andreev wrote (on 15/07/2014):
I'm sorry, I know what you mean here and I'm not criticizing you
specifically (in fact, I'm intentionally taking it ouf of context),
but that's "PHP internals", not "PHP community".
Point taken, but there's plenty of overlap between the two; it's not
like everyone on this list is a 1337 hardcore C hacker who only writes
PHP code to test their latest cool patch to the Zend Engine. It would be
interesting to have this debate at a PHP conference or large user-group
and see if it came out the same way, but I've no particular reason to
suppose it wouldn't.
Unless you really force the camps to pick one by saying "you can't
have Y if we've got X" (to which there's no technical limitation, so
that's not true)
That's fine, as long as you don't count the syntax as part of the
feature. Since everybody would like their preferred version to be
written the same way, then, yes, there's a very obvious technical
limitation: given
function foo(int $bar)
there has to be a single interpretation. As soon as that interpretation
is chosen, it is chosen for all time, and there is no way we can make it
mean something else later.
Now, one form of compromise is to use variants of the syntax, such as...
function foo((int) $bar)
function foo(-int $bar)
function foo(+int $bar)
function foo(~int $bar)
function foo(int! $bar)
etc
...but we still have to decide which behaviour to implement first, and
which syntax to give it.
There's also variants of some of the features that really wouldn't make
sense to pick two of: I don't think anyone wants a language which has
"weak cast", "strict cast", and "really strict cast" alongside each
other. So we can't just say "implement all the versions and let users
choose", either.
I appreciate the frustration of the debate going round in circles, I
feel it too. But without a benevolent dictator, we have to somehow reach
a compromise. Feel free to suggest your preferred compromise, as long as
it's not "just do the one I want and maybe other people can add theirs
later with an as-yet-unspecified syntax" (not that that is what you were
asking for, exactly, I've taken it to extremes to make a point).
Regards,
Rowan Collins
[IMSoP]
Unless you really force the camps to pick one by saying "you can't
have Y if we've got X" (to which there's no technical limitation, so
that's not true)No technical limitation, sure, but it would be really weird for PHP to go in two completely opposite directions at the same time!
Depending on what we're talking about, it could be two directions or
two very high-level features that wouldn't have room for more
improvement, making them boundaries, not directions.
By trying to be abstract in my previous writing, I guess I didn't
clarify what I'm referring to by X and Y. Read below please. :)
Andrey Andreev wrote (on 15/07/2014):
I'm sorry, I know what you mean here and I'm not criticizing you
specifically (in fact, I'm intentionally taking it ouf of context),
but that's "PHP internals", not "PHP community".Point taken, but there's plenty of overlap between the two; it's not like
everyone on this list is a 1337 hardcore C hacker who only writes PHP code
to test their latest cool patch to the Zend Engine. It would be interesting
to have this debate at a PHP conference or large user-group and see if it
came out the same way, but I've no particular reason to suppose it wouldn't.
That is true to some extent, but the majority of regular participants
in these discussions are the ones who write the C code. Also, the
conclusion that I quoted is (I believe) based on previously rejected
proposals for scalar type hints. Ultimately, only that same group of
people can reject it, because they are the voters.
Unless you really force the camps to pick one by saying "you can't
have Y if we've got X" (to which there's no technical limitation, so
that's not true)That's fine, as long as you don't count the syntax as part of the feature.
Since everybody would like their preferred version to be written the same
way, then, yes, there's a very obvious technical limitation: givenfunction foo(int $bar)
there has to be a single interpretation. As soon as that interpretation is
chosen, it is chosen for all time, and there is no way we can make it mean
something else later.Now, one form of compromise is to use variants of the syntax, such as...
function foo((int) $bar)
function foo(-int $bar)
function foo(+int $bar)
function foo(~int $bar)
function foo(int! $bar)
etc...but we still have to decide which behaviour to implement first, and which
syntax to give it.
Exactly my point. I had already expressed my support for using another
syntax, because if the current one is used for type cast hints, then
strict type hints would be practically impossible in the future.
There's also variants of some of the features that really wouldn't make
sense to pick two of: I don't think anyone wants a language which has "weak
cast", "strict cast", and "really strict cast" alongside each other. So we
can't just say "implement all the versions and let users choose", either.I appreciate the frustration of the debate going round in circles, I feel it
too. But without a benevolent dictator, we have to somehow reach a
compromise. Feel free to suggest your preferred compromise, as long as it's
not "just do the one I want and maybe other people can add theirs later with
an as-yet-unspecified syntax" (not that that is what you were asking for,
exactly, I've taken it to extremes to make a point).
Of course, I am not suggesting to introduce 3 different kinds of
casting rules. X vs Y in my case point was type cast hints vs strict
type hints.
I understand that this RFC is about type cast hints and that's fine
with me. My problem with it is that every suggestion for a change in
it is shot down via rhetorics built around the dogma that PHP is a
weakly typed language or that we're talking about a different feature
here, completely ignoring the concern that keeping it as is may
prevent another useful feature from being implemented in the future.
Andrey Andreev wrote (on 16/07/2014):
I understand that this RFC is about type cast hints and that's fine
with me.
It is and it isn't. It's about a hybrid approach which deliberately
mixes casting and validation.
Having the mixture alongside pure casts or pure validation is less
attractive than having the two "pure" forms side by side, but the
mixture provides something which can't easily be emulated by either of
the "pure" forms.
Therein lies the problem.
-----Original Message-----
From: Andrea Faulds [mailto:ajf@ajf.me]
Sent: Tuesday, July 15, 2014 10:48 PM
To: Andrey Andreev
Cc: Rowan Collins; Stas Malyshev; internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)I'm sorry, I know what you mean here and I'm not criticizing you
specifically (in fact, I'm intentionally taking it ouf of context),
but that's "PHP internals", not "PHP community".The PHP community that I know, wants to have both type cast hinting
and strict type declarations.I'm not sure that's quite the case. There are camps wanting one, there
are
camps wanting the other, I suppose some want both, but to me that seems
like
a not-a-compromise compromise solution. The point of this RFC, to some
extent, is to be a reasonable compromise between completely strict
declarations and cast hinting, providing the safety of the first and the
flexibility
of the second. I think it strikes the balance well.
For me the introduction of a new set of rules is a deal breaker.
I'm -1 on the RFC the way it is, and +1 if we implement these 'hints' as
implicit casts, plus change implicit casts to emit E_CAST in case of loss
of data or 'bogus' conversions.
Why insist E_RECOVERABLE_ERROR
and introduce this effectively new set of
rules, instead of switching to E_CAST and maintain consistency?
Maintaining consistency is a HUGE deal. Every such feature we add that
you need to learn more rules/exceptions for make PHP harder to learn.
Zeev
For me the introduction of a new set of rules is a deal breaker.
I'm -1 on the RFC the way it is, and +1 if we implement these 'hints' as
implicit casts, plus change implicit casts to emit E_CAST in case of loss
of data or 'bogus' conversions.
I am -1 in yet another error (as in E_*), which will be just as painful to
deal with than any other.
Zeev Suraski wrote (on 16/07/2014):
For me the introduction of a new set of rules is a deal breaker.
I'm -1 on the RFC the way it is, and +1 if we implement these 'hints' as
implicit casts, plus change implicit casts to emit E_CAST in case of loss
of data or 'bogus' conversions.
Just to be clear, implementing E_CAST would require introducing a set of
rules for when to throw it. By a strict reading of your message, that's
a deal breaker.
In other words, you can't make an omelette without breaking eggs. We can
choose not to make the omelette, or we can choose which eggs to break.
-----Original Message-----
From: Rowan Collins [mailto:rowan.collins@gmail.com]
Sent: Wednesday, July 16, 2014 1:25 PM
To: internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)Zeev Suraski wrote (on 16/07/2014):
For me the introduction of a new set of rules is a deal breaker.
I'm -1 on the RFC the way it is, and +1 if we implement these 'hints'
as implicit casts, plus change implicit casts to emit E_CAST in case
of loss of data or 'bogus' conversions.Just to be clear, implementing E_CAST would require introducing a set of
rules
for when to throw it. By a strict reading of your message, that's a deal
breaker.
Well, not really.
First, like all strict notices, they'd be off by default, so standard
behavior won't change at all from now, and 'type hints' behavior will be
identical to that, so again, nothing new to learn other than the new syntax.
Secondly, if you do enable E_CAST - you may have to slightly modify your
understanding of implicit casts, but you won't have to learn two different
sets of rules. New users will see just one consistent set.
Zeev
Zeev Suraski wrote (on 16/07/2014):
Secondly, if you do enable E_CAST - you may have to slightlymodify your
understanding of implicit casts, but you won't have to learn two different
sets of rules. New users will see just one consistent set.
I think I've got a bit lost: I thought you were saying implement the
concept of a "lossless cast", but only emit a warning, not an error.
Wherever and however we use it, we would have to invent a set of rules
for what "lossless cast" means, since we don't currently have one.
I'm not sure what "two different sets of rules" you think other
proposals would create that this one doesn't.
-----Original Message-----
From: Rowan Collins [mailto:rowan.collins@gmail.com]
Sent: Wednesday, July 16, 2014 3:18 PM
To: internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)Zeev Suraski wrote (on 16/07/2014):
Secondly, if you do enable E_CAST - you may have to slightlymodify
your understanding of implicit casts, but you won't have to learn two
different sets of rules. New users will see just one consistent set.I think I've got a bit lost: I thought you were saying implement the
concept of a
"lossless cast", but only emit a warning, not an error.
It's more of a lossy cast, exactly as we have today, that has an
(effectively-optional-since-it's-off-by-default) to warn you about loss of
data.
For the vast majority of users who use the defaults, there'll be nothing new
to learn except for the availability of those implicit casts in function
signatures.
For those who want to take advantage of 'loss protection', they'd have to
learn about this extra warning type and clean their code so that it adheres
to it. But there too, they'd have consistency, just one set of rules for
implicit cast of scalar values across all of PHP.
Wherever and however we use it, we would have to invent a set of rules for
what "lossless cast" means, since we don't currently have one.I'm not sure what "two different sets of rules" you think other proposals
would create that this one doesn't.
The proposal currently on the table implements two, simultaneously active
sets of rules that in the long run everyone will have to be aware of. It
has both the lossy and lossless concepts active in the same time, which
means everyone will have to become familiar with the lossless rules, whether
he's interested in that or not.
Zeev
Zeev Suraski wrote (on 16/07/2014):
But there too, they'd have consistency, just one set of rules for
implicit cast of scalar values across all of PHP.
The way I see it is that there's an existing set of rules for the result
of any cast, implicit or explicit; these are in some cases "lossy".
Various proposals here rely on a separate set of rules, which doesn't
modify the result of any casts, but checks that the cast will be
"lossless".
The RFC as drafted proposes using these new checks in one specific place
(function calls when declared with type hints) and with a particular
outcome (catchable error).
As far as I understand it, you propose defining the same set of rules,
but applying them in a different place (whenever an implicit cast
occurs) with a different outcome (emit a new E_CAST message).
The proposal currently on the table implements two, simultaneously active
sets of rules that in the long run everyone will have to be aware of. It
has both the lossy and lossless concepts active in the same time, which
means everyone will have to become familiar with the lossless rules, whether
he's interested in that or not.
Right, so it's not actually about the existence of the rules, just the
likelihood that someone will be able to ignore them? Someone writing
code from scratch can, of course, not use any type hints, and so ignore
the checks either way, but I guess if some project or library adopts
them, developers will need to learn how they work to interact with that
project/library.
It's more of a lossy cast, exactly as we have today, that has an
(effectively-optional-since-it's-off-by-default) to warn you about loss of
data.
For the vast majority of users who use the defaults, there'll be nothing new
to learn except for the availability of those implicit casts in function
signatures.
For those who want to take advantage of 'loss protection', they'd have to
learn about this extra warning type and clean their code so that it adheres
to it. But there too, they'd have consistency, just one set of rules for
implicit cast of scalar values across all of PHP.
The problem with making this RFC do the lossy thing is it then removes one key advantage of it: that this RFC provides a measure of strictness. Without that, we have no real compromise proposal, and we might as well introduce a second set of “strict” type hints. The whole point of the current behaviour is that it compromises between the weak typing and strict typing camps; doing what zpp does is giving in to the former camp, and then it’s not a compromise any more, is it?
Andrea Faulds
http://ajf.me/
It's more of a lossy cast, exactly as we have today, that has an
(effectively-optional-since-it's-off-by-default) to warn you about loss of
data.
For the vast majority of users who use the defaults, there'll be nothing new
to learn except for the availability of those implicit casts in function
signatures.
For those who want to take advantage of 'loss protection', they'd have to
learn about this extra warning type and clean their code so that it adheres
to it. But there too, they'd have consistency, just one set of rules for
implicit cast of scalar values across all of PHP.The problem with making this RFC do the lossy thing is it then removes one key advantage of it: that this RFC provides a measure of strictness. Without that, we have no real compromise proposal, and we might as well introduce a second set of “strict” type hints. The whole point of the current behaviour is that it compromises between the weak typing and strict typing camps; doing what zpp does is giving in to the former camp, and then it’s not a compromise any more, is it?
This is exactly why I really like this proposal. While I love the idea of super strict type annotations, I totally understand why they shouldn't be added to PHP. The RFC as it stands strikes a great balance between keeping with "the PHP way" of weak typing, while still making scalar type annotations useful.
If I'm writing an app and an API I'm using has been annotated to take an "int" parameter, and I pass something that cannot possibly be an int, I want to know that, I want to know it now, and I don't want the program to keep executing (possibly writing bad data to a database or doing any number of other crazy things that could happen when my not-an-int gets converted to an int). The entire utility of the type annotation there is that the API developer has said "I expect an int here, if you don't pass one, you're not using the API correctly". As others have argued, the API could technically implement the "lossless conversion" logic itself, but it's fiddly at best to get right, and very error-prone. In the other direction, if the API really does want a cast-to-int-no-matter-what, it can just omit the type annotation and do that -- it's easy and not at all error-prone.
I understand the argument about consistency, but I think this can be mitigated if you couch the feature correctly when documenting it, announcing it, etc, so that people get the right mental model in their heads when they first hear about it. I wouldn't talk about the type annotations this RFC proposes in terms of casts, since they aren't really quite casts (as the folks making the consistency argument have stated). They're something else -- they're type annotations (or type hints, or whatever you want to call them). In that vein, they are consistent with the existing strict enforcement of object type annotations, with the added detail that "strict enforcement" for scalars is defined in terms of "lossless conversion" as outlined in the RFC, since that's the "PHP way" of loosely dealing with scalar types. The idea of "lossless conversion" has just never been relevant before since there is no such thing as a lossless conversion to any object type, or from any type to an array -- but it's a completely consistent way of extending the way we deal with the existing annotations. (And not inconsistent with casts since it isn't a cast!)
Josh Watzman
Hi!
The problem with making this RFC do the lossy thing is it then
removes one key advantage of it: that this RFC provides a measure of
strictness. Without that, we have no real compromise proposal, and we
might as well introduce a second set of “strict” type hints. The
whole point of the current behaviour is that it compromises between
the weak typing and strict typing camps; doing what zpp does is
giving in to the former camp, and then it’s not a compromise any
more, is it?
I think if the compromise is having multiple set of rules for implicit
casts then this compromise is not worth it. If you answer to the
question of "what happens if I use a string in boolean context" with
"well, it depends, if it's boolean context in syntax construct, it's one
rule, if it's internal function, another, if it's user function, yet
another" - it's not a good compromise. Any solution where you can give
an actual answer like "empty string is false, all others are true" is
much better. I'm not a fan of strict types in PHP, but having
inconsistent rules is IMO so bad that even strict types would be better.
At least you'd then know on which planet you are.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
I think if the compromise is having multiple set of rules for implicit
casts then this compromise is not worth it. If you answer to the
question of "what happens if I use a string in boolean context" with
"well, it depends, if it's boolean context in syntax construct, it's one
rule, if it's internal function, another, if it's user function, yet
another" - it's not a good compromise. Any solution where you can give
an actual answer like "empty string is false, all others are true" is
much better. I'm not a fan of strict types in PHP, but having
inconsistent rules is IMO so bad that even strict types would be better.
At least you'd then know on which planet you are.
To be fair, the RFC as it stands has booleans be strict, with true and false the only allowed values. Also, strings, integers and floats have (IMO) easy-to-explain rules under this RFC.:
- bools: bools and objects that convert to bools only
- strings: Anything that can be losslessly converted to a string works (any int, float, string, or object with toString)
- float: Anything that can be losslessly converted to a float (any int, float, numeric-only string, or object that converts to float)
- int: Anything that can be losslessly converted to an int (any int, float that’s integral, integral numeric-only string, or object that converts to int)
Actually, objects are a special case here, unfortunately, but I didn’t really have a choice because they cast weirdly.
This compares to the current zpp rules (as well as I can remember them, anyway):
- bools: Any int, string, float, bool, or object that can cast to bool; if it’s an int, then non-zero is true; if it’s a float, then non-zero is true; if it’s a string, then it’s true unless it’s an empty string or zero
- strings: Anything, unless it’s an object that doesn’t implement toString (I think that’s the rule, anyway)
- int: Any int, float, bool, object that casts to int, or string that begins with numeric digits (this is sometimes a notice)
- float: Any int, float, bool, object that casts to float, or string that begins with float-like digits (this is sometimes a notice)
However, I honestly can’t remember zpp’s exact behaviour and I might have made some mistakes there.
Is zend_parse_parameters’s behaviour actually documented in the manual? A quick search finds nothing.
--
Andrea Faulds
http://ajf.me/
For me the introduction of a new set of rules is a deal breaker.
I'm -1 on the RFC the way it is, and +1 if we implement these 'hints' as
implicit casts, plus change implicit casts to emit E_CAST in case of loss
of data or 'bogus' conversions.Why insist
E_RECOVERABLE_ERROR
and introduce this effectively new set of
rules, instead of switching to E_CAST and maintain consistency?
Maintaining consistency is a HUGE deal. Every such feature we add that
you need to learn more rules/exceptions for make PHP harder to learn.
As has been pointed out already, that would be inconsistent with existing type hints. zend_parse_parameters emits E_WARNING
and returns FAILURE, while type hints raise E_RECOVERABLE_ERROR. To make scalar type hints not emit E_RECOVERABLE_ERROR
and instead do something weaker would introduce more inconsistency, not less.
Also, again, while these new rules aren’t quite the same as zpp’s, they are largely the same, and these rules are able to be summed up clearly in a single sentence, unlike the confusing and inconsistent zpp rules. We could fix zpp later, but that would be harder as it would break backwards-compatibility. And again, these new rules only different from zpp in very few places (integral values, “123abc” and booleans).
Andrea Faulds
http://ajf.me/
Hi!
As has been pointed out already, that would be inconsistent with
existing type hints. zend_parse_parameters emitsE_WARNING
and
returns FAILURE, while type hints raise E_RECOVERABLE_ERROR. To make
scalar type hints not emitE_RECOVERABLE_ERROR
and instead do
something weaker would introduce more inconsistency, not less.
That's why it is proposed to unify that and always produce E_CAST when
implicit cast makes an "iffy" decision. As for the mode of failure where
conversion can not be done - we can unify that too. The only reason why
internals produced E_WARNING
and not E_ERROR
was because we did not have
E_RECOVERABLE_ERROR
but in general I see no problem with doing
E_RECOVERABLE_ERROR
every time cast can not be made, if it's done in
PHP.next. Usually if you pass something unusable to the function, it's a
sign of serious breakage, and function can not really continue. I don't
see much problem with making it consistent E_RECOVERABLE_ERROR.
Also, again, while these new rules aren’t quite the same as zpp’s,
they are largely the same, and these rules are able to be summed up
clearly in a single sentence, unlike the confusing and inconsistent
zpp rules. We could fix zpp later, but that would be harder as it
would break backwards-compatibility. And again, these new rules only
different from zpp in very few places (integral values, “123abc” and
booleans). -- Andrea Faulds http://ajf.me/
You say it as if it is an advantage. It is not. Having a rule that is
subtly different in 10% of places is actually worse than having one
totally different, because you start relying on it being the same, and
you don't change your tests to capture the elusive 10%, and everything
works just fine, and then you get in production scenario where data
happens to hit that 10% and your code goes bananas.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
You say it as if it is an advantage. It is not. Having a rule that is
subtly different in 10% of places is actually worse than having one
totally different, because you start relying on it being the same, and
you don't change your tests to capture the elusive 10%, and everything
works just fine, and then you get in production scenario where data
happens to hit that 10% and your code goes bananas.
It could cause problems, sure, but it’s worth pointing out that the rules this RFC uses are a strict subset of those zpp does; anything this RFC permits will be permitted by zpp, it’s the reverse that isn’t necessarily true. If you write your code to work with the stricter rules of scalar hints, it’ll work fine for internal functions.
At the moment, of course, there’s no scalar type hints for userland functions, so it’s already inconsistent.
--
Andrea Faulds
http://ajf.me/
anything this RFC permits will
be permitted by zpp, it's the reverse that isn't necessarily true.
Right, so it needs to be fixed. It makes no sense to force a new agenda
on the language that's inconsistent with the rest of the language. Align
your new feature to the rest of the language, not the other way around.
Zeev
anything this RFC permits will
be permitted by zpp, it's the reverse that isn't necessarily true.Right, so it needs to be fixed. It makes no sense to force a new agenda
on the language that's inconsistent with the rest of the language. Align
your new feature to the rest of the language, not the other way around.
But to do so would be to make the feature less useful, nor satisfy people who want stricter hinting.
Argh, we’re going in circles. I should perhaps not continue arguing with you, as your position is clear and it’s unlikely to change, and the same is true of mine.
Andrea Faulds
http://ajf.me/
-----Original Message-----
From: Andrea Faulds [mailto:ajf@ajf.me]
Sent: Wednesday, July 16, 2014 11:45 PM
To: Zeev Suraski
Cc: Stas Malyshev; Andrey Andreev; Rowan Collins;
internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)anything this RFC permits will
be permitted by zpp, it's the reverse that isn't necessarily true.Right, so it needs to be fixed. It makes no sense to force a new
agenda on the language that's inconsistent with the rest of the
language. Align your new feature to the rest of the language, not the
other
way around.But to do so would be to make the feature less useful, nor satisfy
people who
want stricter hinting.
Stricter typing does not belong in PHP. If it did, we'd have it in
internal functions, implicit casting and the rest of the language in
general. We don't.
And I insist that much like you said people can catch E_RECOVERABLE_ERROR
and turn ignore it, they can do the same with E_CASE - except now they
won't have to learn about this new behavior unless they explicitly want
to. While you think it may not be strict enough for some people, and I
think it'd be too strict for others - the consistency argument should make
the decision between the two obvious.
Also, I tend to agree with Stas that we can consider to do
E_RECOVERABLE_ERROR
on the obviously 'bogus' conversions - like array or
object to int. But E_RECOVERABLE_ERROR
on simple data loss is radically
inconsistent with the rest of PHP.
Sorry, I introduced hinting into PHP; I intentionally did not add typing
for scalars as it goes against the fundamentals of the language, and I
fought this off back in 2008, 2010 and mildly also in 2012. Call me
persistent :)
FWIW, I think the distance between where you and I stand is not that big -
and if we go in the direction of E_CAST for data loss across the board
(any implicit casts, not just in type hints), and E_RECOVERABLE_ERROR
for
completely broken type conversions - this is a big win for PHP, beyond
just type hints.
Zeev
Stricter typing does not belong in PHP. If it did, we'd have it in
internal functions, implicit casting and the rest of the language in
general. We don’t.
This proposal isn’t that much stricter than zpp, aside from booleans I suppose. It’s not like we allow literally anything as function arguments for internal functions.
And I insist that much like you said people can catch
E_RECOVERABLE_ERROR
and turn ignore it, they can do the same with E_CASE - except now they
won't have to learn about this new behavior unless they explicitly want
to. While you think it may not be strict enough for some people, and I
think it'd be too strict for others - the consistency argument should make
the decision between the two obvious.
E_CAST is problematic. Having something we encourage some people to make an error and some people not to means that in some cases your library works fine and rosy in other people’s environments and sometimes it crashes your app. This is not good. We must not encourage people to make things errors conditionally. It’s either an error or not. I’d veer towards error.
Also, it’s worth pointing out that people will have to learn the new behaviour anyway; no matter how we do scalar type hints, we don’t currently have them, and once implemented, everyone will have to get used to their existence (and probably the fact they will raise E_RECOVERABLE_ERROR).
Also, I tend to agree with Stas that we can consider to do
E_RECOVERABLE_ERROR
on the obviously 'bogus' conversions - like array or
object to int. ButE_RECOVERABLE_ERROR
on simple data loss is radically
inconsistent with the rest of PHP.Sorry, I introduced hinting into PHP; I intentionally did not add typing
for scalars as it goes against the fundamentals of the language, and I
fought this off back in 2008, 2010 and mildly also in 2012. Call me
persistent :)FWIW, I think the distance between where you and I stand is not that big -
and if we go in the direction of E_CAST for data loss across the board
(any implicit casts, not just in type hints), andE_RECOVERABLE_ERROR
for
completely broken type conversions - this is a big win for PHP, beyond
just type hints.
I really don’t like E_CAST for the reasons mentioned above. If it’s a glorified E_NOTICE, it’s pointless, if it’s a glorified E_RECOVERABLE_ERROR, you gain nothing, and if it’s an error in some environments and not in others, we’ve just completely broken our ecosystem.
Andrea Faulds
http://ajf.me/
-----Original Message-----
From: Andrea Faulds [mailto:ajf@ajf.me]
Sent: Thursday, July 17, 2014 12:17 AM
To: Zeev Suraski
Cc: Stas Malyshev; Andrey Andreev; Rowan Collins;
internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)Stricter typing does not belong in PHP. If it did, we'd have it in
internal functions, implicit casting and the rest of the language in
general. We don't.This proposal isn't that much stricter than zpp, aside from booleans I
suppose.
It's not like we allow literally anything as function arguments for
internal
functions.
We do, mostly. We accept "42 ", " 42" and "42asd" as 42. We accept
1000.17 as 1000 in integer context.
This is a big deal, it's not a minor detail.
And I insist that much like you said people can catch
E_RECOVERABLE_ERROR
and turn ignore it, they can do the same with
E_CASE - except now they won't have to learn about this new behavior
unless they explicitly want to. While you think it may not be strict
enough for some people, and I think it'd be too strict for others -
the consistency argument should make the decision between the two
obvious.E_CAST is problematic. Having something we encourage some people to make
an error and some people not to means that in some cases your library
works
fine and rosy in other people's environments and sometimes it crashes
your
That's the point. Many people will not consider this an error, myself
included, and I suspect that also Rasmus and Andi who created the language
concept for the language many many years ago. PHP doesn't consider it to
be an error today across the language.
Can you explain how a library that works for you won't work for someone
else?
The code inside the library will ALWAYS get valid input, in both options.
Always. There's no difference. If it misbehaves, it will be because of
the supplied argument - and it will be clear to the user. Much like in
most of the cases when an API doesn't work right, it's because it's not
being used correctly and not because of a bug in the implementation.
Also, it's worth pointing out that people will have to learn the new
behaviour
anyway; no matter how we do scalar type hints, we don't currently have
them,
and once implemented, everyone will have to get used to their existence
(and
probably the fact they will raise E_RECOVERABLE_ERROR).
Of course they'd have to learn something new - the new syntax at the very
least. But they wouldn't have to learn something new and inconsistent.
Also, I tend to agree with Stas that we can consider to do
E_RECOVERABLE_ERROR
on the obviously 'bogus' conversions - like array
or object to int. ButE_RECOVERABLE_ERROR
on simple data loss is
radically inconsistent with the rest of PHP.Sorry, I introduced hinting into PHP; I intentionally did not add
typing for scalars as it goes against the fundamentals of the
language, and I fought this off back in 2008, 2010 and mildly also in
- Call me persistent :)
FWIW, I think the distance between where you and I stand is not that
big - and if we go in the direction of E_CAST for data loss across the
board (any implicit casts, not just in type hints), and
E_RECOVERABLE_ERROR
for completely broken type conversions - this is a
big win for PHP, beyond just type hints.I really don't like E_CAST for the reasons mentioned above. If it's a
glorified
E_NOTICE, it's pointless,
It's not, not at all. It helps you clean your code from these issues IF
you care about them, and it doesn't bug others who don't. E_NOTICE's and
E_STRICT
work remarkably well - I know many people who choose to ignore
them, and many people who wouldn't deploy code before it's 100% clean of
them. While I'm sure you have an opinion on what this setting should be
(and I might even be able to guess it), PHP's philosophy was letting the
users (developers) choose.
Ultimately it seems you dislike a very fundamental concept in PHP, that
scalar types are 'transient' and can convert without notice depending on
the context. You also don't seem to be too fond of the 'notice/strict'
type errors :) I can understand that, but nonetheless, the former is a
very basic fundamental part of PHP and we shouldn't add features that go
against it, and the latter is a concept that's been serving us well for
years.
Zeev
That's the point. Many people will not consider this an error, myself
included, and I suspect that also Rasmus and Andi who created the language
concept for the language many many years ago. PHP doesn't consider it to
be an error today across the language.
Can you explain how a library that works for you won't work for someone
else?
Someone relies on E_CAST not being fatal. Someone wanting strictness makes an error handler making it fatal. Bam, an awful lot of code breaks. E_CAST is a terrible idea if we want software interoperability. We can’t have it both ways; type hints must be either strict or not strict, if they’re conditionally strict by environment then we will destroy our ecosystem.
Of course, we could just make it a glorified E_NOTICE, but then what’s the point? E_NOTICE
already exists.
The code inside the library will ALWAYS get valid input, in both options.
Always. There's no difference. If it misbehaves, it will be because of
the supplied argument - and it will be clear to the user. Much like in
most of the cases when an API doesn't work right, it's because it's not
being used correctly and not because of a bug in the implementation.
Right. The code inside the library will, sure. The point is that the library will now crash the program because it wasn’t written with a strictly-interpreted E_CAST in mind.
Of course they'd have to learn something new - the new syntax at the very
least. But they wouldn't have to learn something new and inconsistent.
It’s inconsistent anyway. Type hints don’t act like zpp does, unless you want me to make them emit E_WARNING
and return NULL.
It's not, not at all. It helps you clean your code from these issues IF
you care about them, and it doesn't bug others who don't. E_NOTICE's and
E_STRICT
work remarkably well - I know many people who choose to ignore
them, and many people who wouldn't deploy code before it's 100% clean of
them. While I'm sure you have an opinion on what this setting should be
(and I might even be able to guess it), PHP's philosophy was letting the
users (developers) choose.
As I’ve explained earlier, letting them choose to make this fatal would be a horrible, horrible idea.
Ultimately it seems you dislike a very fundamental concept in PHP, that
scalar types are 'transient' and can convert without notice depending on
the context.
Nope, I have zero problem with this basic feature. I may have in the past, sure, but I have come to like PHP’s weak typing.
Also, they don’t universally convert without notice, they only do when they fit a certain set of conditions. This RFC just makes userland type hints (which much of the community apparently wants to be fully strict?) have a slightly tighter ruleset that’s more logical, if somewhat inconsistent with the rest of PHP.
You also don't seem to be too fond of the 'notice/strict'
type errors :)
E_NOTICE
makes sense, I just don’t think it’s the right approach for type hints.
(Though speaking of which, the default object casting handler’s behaviour of just emitting a notice instead of actually failing is really weird. Why is that an E_NOTICE? What on earth is the failure case for, then? Surely it’s the caller’s job to emit the notice?)
I can understand that, but nonetheless, the former is a
very basic fundamental part of PHP and we shouldn't add features that go
against it, and the latter is a concept that's been serving us well for
years.
This is obviously a matter of opinion, but I really don’t think this RFC goes against that. This RFC encourages automatic type conversion, it’s just slightly less lenient than zpp is to help write less buggy software. I suppose it fits the existing mould, where internal functions are really tolerant and won’t make much fuss (a mere E_WARNING
and NULL) while userland type hints are much more draconian.
Andrea Faulds
http://ajf.me/
Hi!
E_CAST is problematic. Having something we encourage some people to
make an error and some people not to means that in some cases your
library works fine and rosy in other people’s environments and
sometimes it crashes your app. This is not good. We must not
encourage people to make things errors conditionally. It’s either an
error or not. I’d veer towards error.
I think this is not correct. It can be OK in one context and error in
another. I.e., if you say "let's ask users how many gizmos they want"
and the user gives "1 " (note the space) and we tell them "we don't know
what this even means, there's an extra character there" - doing this
would just annoy the user. Silently converting it to 1 would do the
right thing.
If you say making any distinction between "1" and "1 " is useless for
you - well, I can accept that. I can see use cases where it makes sense
to make distinction but they are a minority. I think there's a level
between E_RECOVERABLE_ERROR
and silence where it's not "I can't make any
sense out of this garbage" but also not "it's clean data". But I can
also live without this level, if that is what the majority comes to. In
that case, I'd rather have "1 " converted to 1 silently.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
I think this is not correct. It can be OK in one context and error in
another. I.e., if you say "let's ask users how many gizmos they want"
and the user gives "1 " (note the space) and we tell them "we don't know
what this even means, there's an extra character there" - doing this
would just annoy the user. Silently converting it to 1 would do the
right thing.If you say making any distinction between "1" and "1 " is useless for
you - well, I can accept that. I can see use cases where it makes sense
to make distinction but they are a minority. I think there's a level
betweenE_RECOVERABLE_ERROR
and silence where it's not "I can't make any
sense out of this garbage" but also not "it's clean data". But I can
also live without this level, if that is what the majority comes to. In
that case, I'd rather have "1 " converted to 1 silently.
There are really only two levels of error IMO, those that are log file messages (silenced or no), and those that actually stop the script unless handled. I worry about making E_CAST the former but allowing people to make it the latter, because then people would and suddenly code relying on it being the former would make your app stop working.
--
Andrea Faulds
http://ajf.me/
Hi!
There are really only two levels of error IMO, those that are log
file messages (silenced or no), and those that actually stop the
script unless handled. I worry about making E_CAST the former but
allowing people to make it the latter, because then people would and
suddenly code relying on it being the former would make your app stop
working.
This is already a possibility. You can turn E_NOTICE
or E_STRICT
into a
fatal error by using error handlers. In fact, phpunit does it all the
time, turning errors into exceptions. So are you saying other error
levels are worthless too because libraries can work with one set of
error handlers and fail with another?
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
Hi,
anything this RFC permits will
be permitted by zpp, it's the reverse that isn't necessarily true.Right, so it needs to be fixed. It makes no sense to force a new agenda
on the language that's inconsistent with the rest of the language. Align
your new feature to the rest of the language, not the other way around.But to do so would be to make the feature less useful, nor satisfy people who want stricter hinting.
tl;dr:
-
I'd like to have E_CAST on all castings/type jugglings even if we do
not get scalar type hinting. -
I propose to say/implement "scalar parameter casting" instead of
"scalar type hinting" with a casting syntax:function foo( (int) $i, ...)
That way we lower expectations, explain the different syntax/semantics
in contrast to hints, give a hint what scalar parameter casting does,
and I see the use-cases of both parties fulfilled.
I didn't follow the complete thread in detail. And I have to confess
that I'm a big fan of strictly "defining types of parameters", because I
see how it could help me in my work.
BUT: As I see it, E_CAST (with the existing type juggling rules/casts)
plus "scalar parameter casting" is the best compromise in the
spirit/history of PHP without BC breaks and I think all use-cases are
satisfied:
-
E_CAST notifies me about data loss on type juggling.
-
"scalar parameter casting" should just be a convenience for coding:
function foo( (int) $i, (string) $s )
{
}is the same as:
function foo( $i, $s )
{
$i = (int) $i;
$s = (string) $s;
}or perhaps better::
$i = (int) $i;
$s = (string) $s;foo( $i, $s );
That way you decide if you want to be very strict about the data in your
variables or not, and both parties (strict vs. non-strict) can share code:
-
With E_CAST you get additional information on data loss on type
juggling and casting in your complete code base. That's a plus for
everybody who's a little bit scary about type juggling in those cases. -
As a fan of strict mode I can develop my applications and libraries in
E_CAST mode via an error handler that throws exceptions on E_CAST. (We
even run our code withE_ALL
in production to find edge cases.) -
I see the severity of E_CAST on a level like
E_NOTICE
and E_STRICT:
Best practice - if others do not understand/care it's their "problem"
but they can use my code like each other code. -
As a fan of non-strict behavior, you can provide a string for a
parameter that is defined to be an integer. If it contains a number you
are happy that my code works as PHP deals with casting. If your string
does not contain a usable value you have to live with the good old PHP
way when you use code with wrong input data and my code treats it as an
integer and you perhaps have some data loss. But that's not the
responsibility of my code - especially if I interpret the casting syntax
as casting the parameters before hitting my method/function. (BTW: I
don't think that casting should be used as sanitizing of user input like
it was proposed/said to be widely used. I prefer validation over
sanitizing.) -
Depending where and how I define my error handler, I do not see that
my code needs to behave differently if E_CAST is enabled or not. I think
you should implement your error_handler for E_CAST in the spirit of
Symfony's debug mode: In debug mode all errors are converted to
exceptions but they are ignored in production mode. I guess you'd never
say: My application behaves differently. Otherwise you probably use
exceptions for control flow. (I do not say that you have to disable
E_CAST for your production mode. But if your code passes all tests in
E_CAST, there is a good chance that it works without E_CAST as well.
Then it's your decision as product owner if you have to break on errors
in edge cases or not.) -
Regarding consistency to array and object hints: Using the casting
syntax/semantics you could even provide (array) and (object) as "scalar
parameter casting" in contrast to the hints. But of course you can argue
that users are confused about "(array)" vs. "array". I could live with
that confusion as people have to learn about "parameter casting" and
that should be explicitly mentioned in the docs/tutorials/blog posts/... -
I don't know if there is a downside for static code analysis. But
probably you even need defined return types for that.
Regards
Thomas
Thomas Nunninger wrote:
"scalar parameter casting" should just be a convenience for coding:
function foo( (int) $i, (string) $s )
{
}is the same as:
function foo( $i, $s )
{
$i = (int) $i;
$s = (string) $s;
}or perhaps better::
$i = (int) $i;
$s = (string) $s;foo( $i, $s );
That way you decide if you want to be very strict about the data in your
variables or not, and both parties (strict vs. non-strict) can share code:
I agree generally with your mail apart from this bit - people don't
always just call code directly and so can't tell what types parameters
should be.
When you're calling code dynamically, e.g. through a dependency
injection container, you need to be able to inspect what types are
expected from outside the function.
e.g.
$dic->execute(
'foo',
[
'i' => $request->getParam('i'),
's' => $request->getParam('s')
]
);
Without having the type-hinting/casting information available in the
function, it's not possible for the calling code to know what type the
function is expecting, and so it isn't able to cast it to what the
function is expecting.
cheers
Dan
Hi,
anything this RFC permits will
be permitted by zpp, it's the reverse that isn't necessarily true.Right, so it needs to be fixed. It makes no sense to force a new agenda
on the language that's inconsistent with the rest of the language. Align
your new feature to the rest of the language, not the other way around.But to do so would be to make the feature less useful, nor satisfy people
who want stricter hinting.tl;dr:
I'd like to have E_CAST on all castings/type jugglings even if we do not
get scalar type hinting.I propose to say/implement "scalar parameter casting" instead of "scalar
type hinting" with a casting syntax:function foo( (int) $i, ...)
That way we lower expectations, explain the different syntax/semantics in
contrast to hints, give a hint what scalar parameter casting does, and I see
the use-cases of both parties fulfilled.
I didn't follow the complete thread in detail. And I have to confess that
I'm a big fan of strictly "defining types of parameters", because I see how
it could help me in my work.BUT: As I see it, E_CAST (with the existing type juggling rules/casts) plus
"scalar parameter casting" is the best compromise in the spirit/history of
PHP without BC breaks and I think all use-cases are satisfied:
E_CAST notifies me about data loss on type juggling.
"scalar parameter casting" should just be a convenience for coding:
function foo( (int) $i, (string) $s )
{
}is the same as:
function foo( $i, $s )
{
$i = (int) $i;
$s = (string) $s;
}or perhaps better::
$i = (int) $i;
$s = (string) $s;foo( $i, $s );
That way you decide if you want to be very strict about the data in your
variables or not, and both parties (strict vs. non-strict) can share code:
With E_CAST you get additional information on data loss on type juggling
and casting in your complete code base. That's a plus for everybody who's a
little bit scary about type juggling in those cases.As a fan of strict mode I can develop my applications and libraries in
E_CAST mode via an error handler that throws exceptions on E_CAST. (We even
run our code withE_ALL
in production to find edge cases.)I see the severity of E_CAST on a level like
E_NOTICE
and E_STRICT: Best
practice - if others do not understand/care it's their "problem" but they
can use my code like each other code.As a fan of non-strict behavior, you can provide a string for a parameter
that is defined to be an integer. If it contains a number you are happy that
my code works as PHP deals with casting. If your string does not contain a
usable value you have to live with the good old PHP way when you use code
with wrong input data and my code treats it as an integer and you perhaps
have some data loss. But that's not the responsibility of my code -
especially if I interpret the casting syntax as casting the parameters
before hitting my method/function. (BTW: I don't think that casting should
be used as sanitizing of user input like it was proposed/said to be widely
used. I prefer validation over sanitizing.)Depending where and how I define my error handler, I do not see that my
code needs to behave differently if E_CAST is enabled or not. I think you
should implement your error_handler for E_CAST in the spirit of Symfony's
debug mode: In debug mode all errors are converted to exceptions but they
are ignored in production mode. I guess you'd never say: My application
behaves differently. Otherwise you probably use exceptions for control flow.
(I do not say that you have to disable E_CAST for your production mode. But
if your code passes all tests in E_CAST, there is a good chance that it
works without E_CAST as well. Then it's your decision as product owner if
you have to break on errors in edge cases or not.)Regarding consistency to array and object hints: Using the casting
syntax/semantics you could even provide (array) and (object) as "scalar
parameter casting" in contrast to the hints. But of course you can argue
that users are confused about "(array)" vs. "array". I could live with that
confusion as people have to learn about "parameter casting" and that should
be explicitly mentioned in the docs/tutorials/blog posts/...I don't know if there is a downside for static code analysis. But probably
you even need defined return types for that.Regards
Thomas
Hi Dan,
Thomas Nunninger wrote:
"scalar parameter casting" should just be a convenience for coding:
function foo( (int) $i, (string) $s ) { }
is the same as:
function foo( $i, $s ) { $i = (int) $i; $s = (string) $s; }
or perhaps better::
$i = (int) $i; $s = (string) $s; foo( $i, $s );
That way you decide if you want to be very strict about the data in your
variables or not, and both parties (strict vs. non-strict) can share code:I agree generally with your mail apart from this bit - people don't
always just call code directly and so can't tell what types parameters
should be.When you're calling code dynamically, e.g. through a dependency
injection container, you need to be able to inspect what types are
expected from outside the function.e.g.
$dic->execute(
'foo',
[
'i' => $request->getParam('i'),
's' => $request->getParam('s')
]
);Without having the type-hinting/casting information available in the
function, it's not possible for the calling code to know what type the
function is expecting, and so it isn't able to cast it to what the
function is expecting.
Perhaps I miss your point. But what is the difference to current
behavior if you do not know about the types?
With casting the calling code does not need to know how to cast as the
called code accepts the parameter if the value can be used without data
loss. (If the example was misleading because the cast is happening
before calling the function: This should only stress, that providing
usable data is not a responsibility of the called function but the
calling code.)
If the called function is strict it checks the input parameters in the
function and raises some kind of error if information is lost on casting
(not if the type is wrong). If information is lost, E_CAST is raised and
PHP would use type juggling with expected or unexpected result (e.g.
non-numeric strings casted to int). The difference to current behavior
is that the product owner can decide if he wants strict behavior or not.
Or is your point about inspection of parameter type? Why shouldn't
reflection be able to provide information about scalar parameter casting?
Regards
Thomas
Hi,
anything this RFC permits will
be permitted by zpp, it's the reverse that isn't necessarily true.Right, so it needs to be fixed. It makes no sense to force a new agenda
on the language that's inconsistent with the rest of the language. Align
your new feature to the rest of the language, not the other way around.But to do so would be to make the feature less useful, nor satisfy people
who want stricter hinting.tl;dr:
I'd like to have E_CAST on all castings/type jugglings even if we do not
get scalar type hinting.I propose to say/implement "scalar parameter casting" instead of "scalar
type hinting" with a casting syntax:function foo( (int) $i, ...)
That way we lower expectations, explain the different syntax/semantics in
contrast to hints, give a hint what scalar parameter casting does, and I see
the use-cases of both parties fulfilled.
I didn't follow the complete thread in detail. And I have to confess that
I'm a big fan of strictly "defining types of parameters", because I see how
it could help me in my work.BUT: As I see it, E_CAST (with the existing type juggling rules/casts) plus
"scalar parameter casting" is the best compromise in the spirit/history of
PHP without BC breaks and I think all use-cases are satisfied:
E_CAST notifies me about data loss on type juggling.
"scalar parameter casting" should just be a convenience for coding:
function foo( (int) $i, (string) $s )
{
}is the same as:
function foo( $i, $s )
{
$i = (int) $i;
$s = (string) $s;
}or perhaps better::
$i = (int) $i;
$s = (string) $s;foo( $i, $s );
That way you decide if you want to be very strict about the data in your
variables or not, and both parties (strict vs. non-strict) can share code:
With E_CAST you get additional information on data loss on type juggling
and casting in your complete code base. That's a plus for everybody who's a
little bit scary about type juggling in those cases.As a fan of strict mode I can develop my applications and libraries in
E_CAST mode via an error handler that throws exceptions on E_CAST. (We even
run our code withE_ALL
in production to find edge cases.)I see the severity of E_CAST on a level like
E_NOTICE
and E_STRICT: Best
practice - if others do not understand/care it's their "problem" but they
can use my code like each other code.As a fan of non-strict behavior, you can provide a string for a parameter
that is defined to be an integer. If it contains a number you are happy that
my code works as PHP deals with casting. If your string does not contain a
usable value you have to live with the good old PHP way when you use code
with wrong input data and my code treats it as an integer and you perhaps
have some data loss. But that's not the responsibility of my code -
especially if I interpret the casting syntax as casting the parameters
before hitting my method/function. (BTW: I don't think that casting should
be used as sanitizing of user input like it was proposed/said to be widely
used. I prefer validation over sanitizing.)Depending where and how I define my error handler, I do not see that my
code needs to behave differently if E_CAST is enabled or not. I think you
should implement your error_handler for E_CAST in the spirit of Symfony's
debug mode: In debug mode all errors are converted to exceptions but they
are ignored in production mode. I guess you'd never say: My application
behaves differently. Otherwise you probably use exceptions for control flow.
(I do not say that you have to disable E_CAST for your production mode. But
if your code passes all tests in E_CAST, there is a good chance that it
works without E_CAST as well. Then it's your decision as product owner if
you have to break on errors in edge cases or not.)Regarding consistency to array and object hints: Using the casting
syntax/semantics you could even provide (array) and (object) as "scalar
parameter casting" in contrast to the hints. But of course you can argue
that users are confused about "(array)" vs. "array". I could live with that
confusion as people have to learn about "parameter casting" and that should
be explicitly mentioned in the docs/tutorials/blog posts/...I don't know if there is a downside for static code analysis. But probably
you even need defined return types for that.Regards
Thomas
--
--
Dipl.-Inf. Thomas Nunninger
Kartäuserstraße 3
D-79102 Freiburg i. Br.
Tel: +49 761 2171508-0
Mobil: +49 163 7115153
http://nunninger.info
USt-IdNr: DE259832548
Hi Thomas,
Perhaps I miss your point. But what is the difference to current behavior if you do not know about the types?
Not to the current behaviour, to the behaviour that would be possible
with scalar type-hinting.
Or is your point about inspection of parameter type? Why shouldn't reflection be able to provide information about scalar parameter casting?
Yes, reflection should provide that information which makes the code:
function foo( $i, $s ) { $i = (int) $i; $s = (string) $s; }
Not be equivalent to:
function foo( $i, $s ) { $i = (int) $i; $s = (string) $s; }
My point is the reflection then allows the calling code to explicitly
cast the parameters to the type the function expects, with data loss
if required, without triggering any warning on information loss. For
example:
function foo(bool $enabled) {...}
$enabledValue = $request->getParam('enabled');
$dic->execute('foo', ['enabled' => $enabledValue ] )
The DIC should be able to know that the function expects a bool and so
if the value of $enabledValue is the string 'true', that it should
convert it to the boolean true, and so make the function happy. So
that allows no E_CAST being generated, as there has been no implicit
cast, only an explicit conversion somewhere in the DIC.
cheers
Dan
Hi Dan,
Thomas Nunninger wrote:
"scalar parameter casting" should just be a convenience for coding:
function foo( (int) $i, (string) $s ) { }
is the same as:
function foo( $i, $s ) { $i = (int) $i; $s = (string) $s; }
or perhaps better::
$i = (int) $i; $s = (string) $s; foo( $i, $s );
That way you decide if you want to be very strict about the data in your
variables or not, and both parties (strict vs. non-strict) can share
code:I agree generally with your mail apart from this bit - people don't
always just call code directly and so can't tell what types parameters
should be.When you're calling code dynamically, e.g. through a dependency
injection container, you need to be able to inspect what types are
expected from outside the function.e.g.
$dic->execute(
'foo',
[
'i' => $request->getParam('i'),
's' => $request->getParam('s')
]
);Without having the type-hinting/casting information available in the
function, it's not possible for the calling code to know what type the
function is expecting, and so it isn't able to cast it to what the
function is expecting.Perhaps I miss your point. But what is the difference to current behavior if
you do not know about the types?With casting the calling code does not need to know how to cast as the
called code accepts the parameter if the value can be used without data
loss. (If the example was misleading because the cast is happening before
calling the function: This should only stress, that providing usable data is
not a responsibility of the called function but the calling code.)If the called function is strict it checks the input parameters in the
function and raises some kind of error if information is lost on casting
(not if the type is wrong). If information is lost, E_CAST is raised and PHP
would use type juggling with expected or unexpected result (e.g. non-numeric
strings casted to int). The difference to current behavior is that the
product owner can decide if he wants strict behavior or not.Or is your point about inspection of parameter type? Why shouldn't
reflection be able to provide information about scalar parameter casting?Regards
Thomas
Hi,
anything this RFC permits will
be permitted by zpp, it's the reverse that isn't necessarily true.Right, so it needs to be fixed. It makes no sense to force a new
agenda
on the language that's inconsistent with the rest of the language.
Align
your new feature to the rest of the language, not the other way around.But to do so would be to make the feature less useful, nor satisfy
people
who want stricter hinting.tl;dr:
I'd like to have E_CAST on all castings/type jugglings even if we do
not
get scalar type hinting.I propose to say/implement "scalar parameter casting" instead of
"scalar
type hinting" with a casting syntax:function foo( (int) $i, ...)
That way we lower expectations, explain the different syntax/semantics in
contrast to hints, give a hint what scalar parameter casting does, and I
see
the use-cases of both parties fulfilled.
I didn't follow the complete thread in detail. And I have to confess that
I'm a big fan of strictly "defining types of parameters", because I see
how
it could help me in my work.BUT: As I see it, E_CAST (with the existing type juggling rules/casts)
plus
"scalar parameter casting" is the best compromise in the spirit/history
of
PHP without BC breaks and I think all use-cases are satisfied:
E_CAST notifies me about data loss on type juggling.
"scalar parameter casting" should just be a convenience for coding:
function foo( (int) $i, (string) $s )
{
}is the same as:
function foo( $i, $s )
{
$i = (int) $i;
$s = (string) $s;
}or perhaps better::
$i = (int) $i;
$s = (string) $s;foo( $i, $s );
That way you decide if you want to be very strict about the data in your
variables or not, and both parties (strict vs. non-strict) can share
code:
With E_CAST you get additional information on data loss on type
juggling
and casting in your complete code base. That's a plus for everybody who's
a
little bit scary about type juggling in those cases.As a fan of strict mode I can develop my applications and libraries in
E_CAST mode via an error handler that throws exceptions on E_CAST. (We
even
run our code withE_ALL
in production to find edge cases.)I see the severity of E_CAST on a level like
E_NOTICE
and E_STRICT:
Best
practice - if others do not understand/care it's their "problem" but they
can use my code like each other code.As a fan of non-strict behavior, you can provide a string for a
parameter
that is defined to be an integer. If it contains a number you are happy
that
my code works as PHP deals with casting. If your string does not contain
a
usable value you have to live with the good old PHP way when you use code
with wrong input data and my code treats it as an integer and you perhaps
have some data loss. But that's not the responsibility of my code -
especially if I interpret the casting syntax as casting the parameters
before hitting my method/function. (BTW: I don't think that casting
should
be used as sanitizing of user input like it was proposed/said to be
widely
used. I prefer validation over sanitizing.)Depending where and how I define my error handler, I do not see that my
code needs to behave differently if E_CAST is enabled or not. I think you
should implement your error_handler for E_CAST in the spirit of Symfony's
debug mode: In debug mode all errors are converted to exceptions but they
are ignored in production mode. I guess you'd never say: My application
behaves differently. Otherwise you probably use exceptions for control
flow.
(I do not say that you have to disable E_CAST for your production mode.
But
if your code passes all tests in E_CAST, there is a good chance that it
works without E_CAST as well. Then it's your decision as product owner if
you have to break on errors in edge cases or not.)Regarding consistency to array and object hints: Using the casting
syntax/semantics you could even provide (array) and (object) as "scalar
parameter casting" in contrast to the hints. But of course you can argue
that users are confused about "(array)" vs. "array". I could live with
that
confusion as people have to learn about "parameter casting" and that
should
be explicitly mentioned in the docs/tutorials/blog posts/...I don't know if there is a downside for static code analysis. But
probably
you even need defined return types for that.Regards
Thomas
--
--
Dipl.-Inf. Thomas Nunninger
Kartäuserstraße 3
D-79102 Freiburg i. Br.Tel: +49 761 2171508-0
Mobil: +49 163 7115153
http://nunninger.infoUSt-IdNr: DE259832548
Apologies, I pasted the wrong code, it should have read:
"
which makes the code:
function foo( $i, $s ) { $i = (int) $i; $s = (string) $s; }
Not be equivalent to:
function foo( (int) $i, (string) $s )
{
}
As the type-hint information is not available outside the function for
the first one.
"
Hi Thomas,
Perhaps I miss your point. But what is the difference to current behavior if you do not know about the types?
Not to the current behaviour, to the behaviour that would be possible
with scalar type-hinting.Or is your point about inspection of parameter type? Why shouldn't reflection be able to provide information about scalar parameter casting?
Yes, reflection should provide that information which makes the code:
function foo( $i, $s ) { $i = (int) $i; $s = (string) $s; }
Not be equivalent to:
function foo( $i, $s ) { $i = (int) $i; $s = (string) $s; }
My point is the reflection then allows the calling code to explicitly
cast the parameters to the type the function expects, with data loss
if required, without triggering any warning on information loss. For
example:function foo(bool $enabled) {...}
$enabledValue = $request->getParam('enabled');
$dic->execute('foo', ['enabled' => $enabledValue ] )
The DIC should be able to know that the function expects a bool and so
if the value of $enabledValue is the string 'true', that it should
convert it to the boolean true, and so make the function happy. So
that allows no E_CAST being generated, as there has been no implicit
cast, only an explicit conversion somewhere in the DIC.cheers
DanHi Dan,
Thomas Nunninger wrote:
"scalar parameter casting" should just be a convenience for coding:
function foo( (int) $i, (string) $s ) { }
is the same as:
function foo( $i, $s ) { $i = (int) $i; $s = (string) $s; }
or perhaps better::
$i = (int) $i; $s = (string) $s; foo( $i, $s );
That way you decide if you want to be very strict about the data in your
variables or not, and both parties (strict vs. non-strict) can share
code:I agree generally with your mail apart from this bit - people don't
always just call code directly and so can't tell what types parameters
should be.When you're calling code dynamically, e.g. through a dependency
injection container, you need to be able to inspect what types are
expected from outside the function.e.g.
$dic->execute(
'foo',
[
'i' => $request->getParam('i'),
's' => $request->getParam('s')
]
);Without having the type-hinting/casting information available in the
function, it's not possible for the calling code to know what type the
function is expecting, and so it isn't able to cast it to what the
function is expecting.Perhaps I miss your point. But what is the difference to current behavior if
you do not know about the types?With casting the calling code does not need to know how to cast as the
called code accepts the parameter if the value can be used without data
loss. (If the example was misleading because the cast is happening before
calling the function: This should only stress, that providing usable data is
not a responsibility of the called function but the calling code.)If the called function is strict it checks the input parameters in the
function and raises some kind of error if information is lost on casting
(not if the type is wrong). If information is lost, E_CAST is raised and PHP
would use type juggling with expected or unexpected result (e.g. non-numeric
strings casted to int). The difference to current behavior is that the
product owner can decide if he wants strict behavior or not.Or is your point about inspection of parameter type? Why shouldn't
reflection be able to provide information about scalar parameter casting?Regards
Thomas
Hi,
anything this RFC permits will
be permitted by zpp, it's the reverse that isn't necessarily true.Right, so it needs to be fixed. It makes no sense to force a new
agenda
on the language that's inconsistent with the rest of the language.
Align
your new feature to the rest of the language, not the other way around.But to do so would be to make the feature less useful, nor satisfy
people
who want stricter hinting.tl;dr:
I'd like to have E_CAST on all castings/type jugglings even if we do
not
get scalar type hinting.I propose to say/implement "scalar parameter casting" instead of
"scalar
type hinting" with a casting syntax:function foo( (int) $i, ...)
That way we lower expectations, explain the different syntax/semantics in
contrast to hints, give a hint what scalar parameter casting does, and I
see
the use-cases of both parties fulfilled.
I didn't follow the complete thread in detail. And I have to confess that
I'm a big fan of strictly "defining types of parameters", because I see
how
it could help me in my work.BUT: As I see it, E_CAST (with the existing type juggling rules/casts)
plus
"scalar parameter casting" is the best compromise in the spirit/history
of
PHP without BC breaks and I think all use-cases are satisfied:
E_CAST notifies me about data loss on type juggling.
"scalar parameter casting" should just be a convenience for coding:
function foo( (int) $i, (string) $s )
{
}is the same as:
function foo( $i, $s )
{
$i = (int) $i;
$s = (string) $s;
}or perhaps better::
$i = (int) $i;
$s = (string) $s;foo( $i, $s );
That way you decide if you want to be very strict about the data in your
variables or not, and both parties (strict vs. non-strict) can share
code:
With E_CAST you get additional information on data loss on type
juggling
and casting in your complete code base. That's a plus for everybody who's
a
little bit scary about type juggling in those cases.As a fan of strict mode I can develop my applications and libraries in
E_CAST mode via an error handler that throws exceptions on E_CAST. (We
even
run our code withE_ALL
in production to find edge cases.)I see the severity of E_CAST on a level like
E_NOTICE
and E_STRICT:
Best
practice - if others do not understand/care it's their "problem" but they
can use my code like each other code.As a fan of non-strict behavior, you can provide a string for a
parameter
that is defined to be an integer. If it contains a number you are happy
that
my code works as PHP deals with casting. If your string does not contain
a
usable value you have to live with the good old PHP way when you use code
with wrong input data and my code treats it as an integer and you perhaps
have some data loss. But that's not the responsibility of my code -
especially if I interpret the casting syntax as casting the parameters
before hitting my method/function. (BTW: I don't think that casting
should
be used as sanitizing of user input like it was proposed/said to be
widely
used. I prefer validation over sanitizing.)Depending where and how I define my error handler, I do not see that my
code needs to behave differently if E_CAST is enabled or not. I think you
should implement your error_handler for E_CAST in the spirit of Symfony's
debug mode: In debug mode all errors are converted to exceptions but they
are ignored in production mode. I guess you'd never say: My application
behaves differently. Otherwise you probably use exceptions for control
flow.
(I do not say that you have to disable E_CAST for your production mode.
But
if your code passes all tests in E_CAST, there is a good chance that it
works without E_CAST as well. Then it's your decision as product owner if
you have to break on errors in edge cases or not.)Regarding consistency to array and object hints: Using the casting
syntax/semantics you could even provide (array) and (object) as "scalar
parameter casting" in contrast to the hints. But of course you can argue
that users are confused about "(array)" vs. "array". I could live with
that
confusion as people have to learn about "parameter casting" and that
should
be explicitly mentioned in the docs/tutorials/blog posts/...I don't know if there is a downside for static code analysis. But
probably
you even need defined return types for that.Regards
Thomas
--
--
Dipl.-Inf. Thomas Nunninger
Kartäuserstraße 3
D-79102 Freiburg i. Br.Tel: +49 761 2171508-0
Mobil: +49 163 7115153
http://nunninger.infoUSt-IdNr: DE259832548
- I'd like to have E_CAST on all castings/type jugglings even if we do
not get scalar type hinting.
$var = 6.3;
$a = (int) $var;
Or $b = (bool) "1";
This is usual code and it could be wanted to losse information on casting. Triggering errors for that would be extremely annoying.
I propose to say/implement "scalar parameter casting" instead of
"scalar type hinting" with a casting syntax:function foo( (int) $i, ...)
That's bad to read, destroys the possibility to integrate method overloading one day in the future, and it is telling the wrong story.
If I have "function moo(int $var)" it shows that the method expects an integer.
If I have "function moo((int) $var)" it looks like: Give me whatever you want and I cast it into an integer.
Christian
Hi!
The PHP community that I know, wants to have both type cast hinting
and strict type declarations.
No, different members of the community want different options, because
it would serve their particular use cases. But that does not mean it
necessarily must be part of PHP - not all use cases must and can be
served by the language. Something will inevitably be left out.
PHP internals on the other hand, would rather argue to death over
PHP internals would rather have consistent implementation that we can
build on and support for next 10 years than serve one particular use
case which may even not be there in 2 years or create a hodgepodge of
syntaxes just to ensure nobody is left out. Yes, that means sometimes we
argue a lot and sometimes we reject your favorite use case. Figuring
what is right for a tool used by a diverse community of millions is not
easy, and what could seem obviously right to you may seem as obviously
wrong to somebody else. Sometimes it is better to not implement
something than implement it wrong and be stuck with it for the next decade.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
-----Original Message-----
From: Stas Malyshev [mailto:smalyshev@sugarcrm.com]
Sent: Tuesday, July 15, 2014 7:14 PM
To: Rowan Collins; internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)Hi!
The answer - which is definitely a matter of opinion - is that
allowing any string reduces the usefulness of the type hint.IMO, having consistent rules is much more, orders of magnitude more
important than serving any particular use case. We will always have use
cases
in which any particular check would not be enough. We should not sacrifice
the simplicity of the language to try and capture every one of them.
Agreed.
Zeev
Hello again,
One of the issues with the RFC as it stands is how to handle bool casting. While int, float and string only allow lossless casting (with the exception of objects, but we can’t really do anything about that), bool’s behaviour at the moment is quite different. I don’t think it makes sense so I won’t discuss the current behaviour, only possible new ones.
One option is simply to forget about being lossless and make the bool type hint accept any value, meaning any truthy value or any falsey value would yield what is expected without error. This would ensure that if some stupid programmer (like myself ;) has passed in a non-boolean truthy/falsey value to your function, it’ll be handled correctly. It would mean all your bit hacks ($foo & FLAG etc.) would work, anything you got from $_GET (e.g. ?foobar=1). However, this is unlikely to catch bugs in code, because literally any PHP value would work. For that reason, I’m not sure this is the way forward.
Another option is go completely strict and allow only boolean values, failing everything else. This would be unlike the int, float and string hints, which are flexible and cast, but would be more helpful for catching bugs. However, not casting at all isn’t very “PHP-like”, and forcing people to manually cast with (bool) might not be ideal. If we were to go for this one, I might also accept objects casting to bool (which the default handler does), because I don’t want to stop extension developers from making bool-like objects if they so please.
The final option I’m thinking about is a limited set of values. TRUE,
FALSE
andNULL
would be accepted, along with the integer and float values 1 and 0 (which are the int/floatTRUE
andFALSE
cast to, respectively), ‘1’ and the empty string (which are the string valuesTRUE
andFALSE
cast to), and ‘0’ (which (string)(int)FALSE would give you), along with objects casting to boolean. It’s not a perfect solution, but I currently feel that this is the most sensible option bar going for full strictness.I’m not really decided, however. Every time I try to think about this, I usually end up going in circles. Anthony doesn’t seem to be decided either. Hence I’m putting this up for discussion.
What are your thoughts?
We are going round in circles as we are trying to second guess what programmers
will want - how they will try to use it. Part of the problem is that different
programmers will want different things AND the same programmer will want
different things in different parts of the program (think back to my 'inner' and
'outer' program parts).
One of the big items of discussion is: should this be a cast (ie convert to the
desired type) or a check (and error upon type mismatch). There are valid
arguments for both - indeed different use cases for both.
I will argue that they are not incompatible.
So: I see 3 cases and suggest a way of accomodating the different needs.
a) 'outer' code where types are not known, eg an argument might be something
from $_GET.
function CheckAge($age) {
if( is_numeric($age) && $age >= 0 && $age <= 150)
return TRUE;
// throw error/....
}
CheckAge($_GET['age']);
b) 'inner' code where something will have been checked to be convertable to the
desired type, but it might not be that type:
function CanLegallyDrive((int) $age) {
return $age >= 17;
}
if(CheckAge($_GET['age']) && CanLegallyDrive($_GET['age']))
....
Note the use of '(int)' to indicate that the argument should be cast to int.
If a conversion is not possible: the program errors in some nasty way.
The above is prob how this will often be used, so the cast rules should
reflect that, eg: '12' OK, '12 ' OK, '12a' Fail.
c) 'inner' code where the argument is known to be of the type and no convertion
will be done - if there is a type mismatch - generate an error.
function PrintMonth(int $month) {
...
}
for($mon = 0; $mon <= 12; $mon++)
PrintMonth($mon)
I wanted to say something about function return types (good for optimisation)
but decided that that would risk of opening more cans of worms.
--
Alain Williams
Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT Lecturer.
+44 (0) 787 668 0256 http://www.phcomp.co.uk/
Parliament Hill Computers Ltd. Registration Information: http://www.phcomp.co.uk/contact.php
#include <std_disclaimer.h
One of the issues with the RFC as it stands is how to handle bool casting. While int, float and string only allow lossless casting (with the exception of objects, but we can’t really do anything about that), bool’s behaviour at the moment is quite different. I don’t think it makes sense so I won’t discuss the current behaviour, only possible new ones.
Another option is go completely strict and allow only boolean values, failing everything else. This would be unlike the int, float and string hints, which are flexible and cast, but would be more helpful for catching bugs. However, not casting at all isn’t very “PHP-like”, and forcing people to manually cast with (bool) might not be ideal. If we were to go for this one, I might also accept objects casting to bool (which the default handler does), because I don’t want to stop extension developers from making bool-like objects if they so please.
I’ve made the patch and RFC do this, at least for the time being. I’m still not really decided, nor is Anthony. The main advantage of being completely strict is that it’s fully lossless; (bool)(string)$x === $x where $x was a boolean, but (string)(bool)$x !== $x where $x was a string. (Not necessarily, at least).
This would make it an oddball among the scalars as it’s completely strict, and would require you to cast to bool explicitly in many cases… but at the moment it seems to be the most sensible option to me.
Still, we’re both undecided.
--
Andrea Faulds
http://ajf.me/
Hi!
One of the issues with the RFC as it stands is how to handle bool
casting. While int, float and string only allow lossless casting
(with the exception of objects, but we can’t really do anything about
that), bool’s behaviour at the moment is quite different. I don’t
think it makes sense so I won’t discuss the current behaviour, only
possible new ones.
Most cases where bool is used is meant as "yes or no" parameter. In
those cases, getting non-boolean there may mean one of the following:
- A complete error, passing wrong parameter by mistake.
- Passing something that is meant to represent preference, but is not
an actual boolean - i.e. null, empty string, string '1', object, etc.
Traditionally, many languages - including PHP - were lenient in
accepting non-boolean objects in boolean contexts - so you can say
if($obj) and mean "true if $obj is a real object, false if $obj is
something like false or null" instead of if((bool)$obj). In such
context, it is clear what the intent is, and the possibility of error is
very low.
However, when passing parameters the other option - one that implies the
error was passing a different parameter - is an option. The question is
how potential catching such error - noting that it would be caught only
if the other parameter is not boolean and the value is not boolean and
we do not use (bool) - is important over other considerations.
So here I would say we should take a consistent approach. By this I mean
- if we say scalar typing is coercive - i.e. if you say foo(bar $x), it
means $x should be coerced into type "bar" or rejected if it does not
make sense - then we should follow the general rules of boolean
conversion and say any object can be turned into boolean, by the same
rules as if() would take them.
If, on the contrary, we take it as $x must be of type bar, or we reject
it - then we should not accept anything but boolean. This however will
lead us into strict typing, the concept which I personally oppose in
this context, but would not elaborate further here since it was already
done many times.
In any case, I think it is important to realize this decision is not
arbitrary, but connected to the rest of things - if you choose strict,
it makes no sense to be strict only in one place. If you choose
coercive, type casting rules should be consistent for all cases, not
special for every syntax.
work, anything you got from $_GET (e.g. ?foobar=1). However, this is
unlikely to catch bugs in code, because literally any PHP value would
work. For that reason, I’m not sure this is the way forward.
Making it strict would not help here - people would just be trained to
write (bool) everywhere, and thus the same bugs would be masked the same
way, only in much uglier code.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
The RFC is here:
https://wiki.php.net/rfc/scalar_type_hinting_with_cast
I am worried about this big casting conversion matrix. New rules should
not be invented, and the following should always be equivalent:
function foo(typehint $var)
vs:
function foo($var) {
$var = typehint $var;
In general, I am not in favour of casting typehints, as it would be a
different behaviour from the hard-check typehints that we already have
for classes and arrays.
regards,
Derick
--
http://derickrethans.nl | http://xdebug.org
Like Xdebug? Consider a donation: http://xdebug.org/donate.php
twitter: @derickr and @xdebug
Posted with an email client that doesn't mangle email: alpine
I am worried about this big casting conversion matrix. New rules should
not be invented, and the following should always be equivalent:function foo(typehint $var)
vs:
function foo($var) {
$var = typehint $var;In general, I am not in favour of casting typehints, as it would be a
different behaviour from the hard-check typehints that we already have
for classes and arrays.
I’ve talked about this before in this thread, but the justification for differing in behaviour from array and class hints is that these types are scalars (which PHP routinely juggles) and arrays and objects are not scalar (and not routinely juggled). While we are indeed casting, we’re only doing so where the conversion would be lossless. Sure, it’s not a hard check, but it is still quite strict. I don’t like the idea of completely strict type hints here, but I also don’t think that completely loose type hints that cast and do zero validation are for the best either. This RFC tries to strike a compromise.
--
Andrea Faulds
http://ajf.me/
I am worried about this big casting conversion matrix. New rules should
not be invented, and the following should always be equivalent:function foo(typehint $var)
vs:
function foo($var) { $var = typehint $var;
In general, I am not in favour of casting typehints, as it would be a
different behaviour from the hard-check typehints that we already have
for classes and arrays.I’ve talked about this before in this thread, but the justification
for differing in behaviour from array and class hints is that these
types are scalars (which PHP routinely juggles) and arrays and objects
are not scalar (and not routinely juggled). While we are indeed
casting, we’re only doing so where the conversion would be lossless.
Sure, it’s not a hard check, but it is still quite strict. I don’t
like the idea of completely strict type hints here, but I also don’t
think that completely loose type hints that cast and do zero
validation are for the best either. This RFC tries to strike a
compromise.
A compromise by adding more inconsistencies.
I can buy the cast of scalars vs hint--of-complex types, but definitely
not the introduction of a new group of casting rules. Keep it simple.
cheers,
Derick
http://derickrethans.nl | http://xdebug.org
Like Xdebug? Consider a donation: http://xdebug.org/donate.php
twitter: @derickr and @xdebug
Posted with an email client that doesn't mangle email: alpine
A compromise by adding more inconsistencies.
I can buy the cast of scalars vs hint--of-complex types, but definitely
not the introduction of a new group of casting rules. Keep it simple.
It doesn’t change the casting rules; write an error handler that ignores E_RECOVERABLE_ERROR
and you get exactly the same result as a manual cast inside the function. Rather, it simply adds validation. The casting works like casting does everywhere else, but there’s strict lossless validation on the type hint, similar to the non-scalar type hints except more lenient as it allows equivalent values of other types.
Andrea Faulds
http://ajf.me/
A compromise by adding more inconsistencies.
I can buy the cast of scalars vs hint--of-complex types, but definitely
not the introduction of a new group of casting rules. Keep it simple.It doesn’t change the casting rules; write an error handler that ignores
E_RECOVERABLE_ERROR
and you get exactly the same result as a manual cast inside the function. Rather, it simply adds validation. The casting works like casting does everywhere else, but there’s strict lossless validation on the type hint, similar to the non-scalar type hints except more lenient as it allows equivalent values of other types.
ok, it might work for me if formulated like this.
now, the question is, would it be possible to port these rules to zpp in PHP-Next?
if the answer is “yes", then I’m all for it.
otherwise, I’m a bit skeptical as inconsistency between extension-land and user-land code worries me
--
Alexey Zakhlestin
CTO at Grids.by/you
https://github.com/indeyets
PGP key: http://indeyets.ru/alexey.zakhlestin.pgp.asc
-----Original Message-----
From: Andrea Faulds [mailto:ajf@ajf.me]
Sent: Monday, July 14, 2014 5:58 PM
To: Derick Rethans
Cc: PHP internals
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)A compromise by adding more inconsistencies.
I can buy the cast of scalars vs hint--of-complex types, but
definitely not the introduction of a new group of casting rules. Keep
it
simple.It doesn't change the casting rules; write an error handler that ignores
E_RECOVERABLE_ERROR
and you get exactly the same result as a manual cast
inside the function. Rather, it simply adds validation. The casting
works like
casting does everywhere else, but there's strict lossless validation on
the type
hint, similar to the non-scalar type hints except more lenient as it
allows
equivalent values of other types.
It does, as it creates an error (recoverable or not), and it doesn't allow
"13abc" to easily turn into 13 (int), even if you implement an error
handler that ignores E_RECOVERABLE_ERROR.
Zeev
It does, as it creates an error (recoverable or not), and it doesn't allow
"13abc" to easily turn into 13 (int), even if you implement an error
handler that ignores E_RECOVERABLE_ERROR.
Actually, you’re right. In the current patch, if you run this:
set_error_handler(function () { return true; });
function foo(int $a) { var_dump($a); }
foo(“13abc”);
You would get this:
int(0)
However, that could easily be fixed so the error case uses the normal casting behaviour.
--
Andrea Faulds
http://ajf.me/
-----Original Message-----
From: Andrea Faulds [mailto:ajf@ajf.me]
Sent: Monday, July 14, 2014 6:12 PM
To: Zeev Suraski
Cc: Derick Rethans; PHP internals
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)It does, as it creates an error (recoverable or not), and it doesn't
allow "13abc" to easily turn into 13 (int), even if you implement an
error handler that ignores E_RECOVERABLE_ERROR.Actually, you're right. In the current patch, if you run this:
set_error_handler(function () { return true; }); function foo(int $a) { var_dump($a); } foo("13abc");
You would get this:
int(0)
However, that could easily be fixed so the error case uses the normal
casting
behaviour.
Perhaps (I think it's more difficult than you think but perhaps I'm
missing something); Either way, it's the wrong way to do it IMHO
regardless. Having this as either a notice or a special E_CAST has no
meaningful drawbacks, only advantages, and will also enable us to
implement these warnings in regular casts for even greater consistency (a
recoverable error is out of the question for those, of course, as it's a
huge BC break).
Zeev
A compromise by adding more inconsistencies.
I agree.
I can buy the cast of scalars vs hint--of-complex types, but definitely
not the
introduction of a new group of casting rules. Keep it simple.
I agree too.
And it should not be a recoverable error, it should be a notice (or
equivalent).
Zeev
Derick Rethans wrote (on 14/07/2014):
A compromise by adding more inconsistencies.
The only way of not introducing some inconsistencies (or, to put it
another way, new features) is to use strict type hints, which perform no
casting, and error on invalid input, since that's what the existing type
hints do, in particular "array". There's broad consensus that that
wouldn't be very "PHP-ish", and it has been rejected in previous
discussions.
Here are the main variants discussed in this thread:
- add type hints using existing syntax, but which are actually silent
casts, rather than the strict validation performed for existing types - add type hints using existing syntax, which are casts, but also act
differently from existing casts by emitting some kind of notice - add cast hints using a new syntax
- add type hints using existing syntax, which use a new "lossless
cast", i.e. perform validation for completely wrong input ('abc' as an
int param) but allow juggling for "reasonable" input ('123' as an int
param).
Option 2 (or 3) could also be implemented by making all lossy casts
emit some kind of notice.
This RFC currently proposes option 4.
-----Original Message-----
From: Rowan Collins [mailto:rowan.collins@gmail.com]
Sent: Monday, July 14, 2014 6:28 PM
To: internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)Derick Rethans wrote (on 14/07/2014):
A compromise by adding more inconsistencies.
The only way of not introducing some inconsistencies (or, to put it
another
way, new features) is to use strict type hints
Actually there's a pretty simple way that's not strict type hints:
- Add type hints using existing syntax, which are casts; Change casts
(both existing and these new ones) to emit a new E_CAST in case of data
loss or 'bogus' conversions.
Zeev
Actually there's a pretty simple way that's not strict type hints:
- Add type hints using existing syntax, which are casts; Change casts
(both existing and these new ones) to emit a new E_CAST in case of data
loss or 'bogus' conversions.
How is emitting a new E_CAST useful? Most people are not going to write error handlers that will act on it, so it’ll just be an E_WARNING
so far as most people care, and we’ll just end up with casts, which you can already do:
function foo($a) {
$a = (int)$a;
}
--
Andrea Faulds
http://ajf.me/
-----Original Message-----
From: Andrea Faulds [mailto:ajf@ajf.me]
Sent: Monday, July 14, 2014 6:49 PM
To: Zeev Suraski
Cc: Rowan Collins; internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)Actually there's a pretty simple way that's not strict type hints:
- Add type hints using existing syntax, which are casts; Change
casts (both existing and these new ones) to emit a new E_CAST in case
of data loss or 'bogus' conversions.How is emitting a new E_CAST useful? Most people are not going to write
error handlers that will act on it, so it'll just be anE_WARNING
so far
as most
people care, and we'll just end up with casts, which you can already do:function foo($a) { $a = (int)$a; }
I already mentioned before that I don't think consistency is a bad thing
(and that's an understatement). Having the syntax differ and have a
separate, similar set of rules/behaviors is a disadvantage, not an
advantage in my book.
There are several advantages of adding this syntax with the simple casting
behavior:
- It saves a bit of code and improves readability for a very common use
case. - It encourages developers to get the types straight instead of relying
on implicit casts. - It reuses syntax we already use for type hinting so it doesn't drive
complexity up significantly. - It allows people to go extra strict very easily, by turning E_CASE into
errors. My guesstimate is that the majority of people won't, but it'll be
possible and easy to do nonetheless. - It maintains consistency with casts (that's a feature, not a bug :)
Zeev
- It saves a bit of code and improves readability for a very common use
case.
Sure.
- It encourages developers to get the types straight instead of relying
on implicit casts.
Your proposal is to just use implicit casts with no real failure cases; isn’t that encouraging developers not to care about using the correct types? This RFC’s proposal is quite strict, what you are suggesting is very loose and will not encourage anyone to use the correct types, as it is very tolerant.
- It reuses syntax we already use for type hinting so it doesn't drive
complexity up significantly.
As does this RFC.
- It allows people to go extra strict very easily, by turning E_CASE into
errors. My guesstimate is that the majority of people won't, but it'll be
possible and easy to do nonetheless.
I really don’t like that idea. If someone writes a function with type hints, people shouldn’t be able to make those type hints go away or become more or less strict. They should be consistent across environments and contexts.
--
Andrea Faulds
http://ajf.me/
-----Original Message-----
From: Andrea Faulds [mailto:ajf@ajf.me]
Sent: Monday, July 14, 2014 7:12 PM
To: Zeev Suraski
Cc: Rowan Collins; internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)
- It encourages developers to get the types straight instead of
relying on implicit casts.Your proposal is to just use implicit casts with no real failure cases;
isn't that
encouraging developers not to care about using the correct types?
Not at all. It encourages them to care about types in the PHP spirit.
You want to be more strict? No problem, you have a very easy way to carve
out these specific cases by trapping E_CAST.
- It allows people to go extra strict very easily, by turning E_CASE
into errors. My guesstimate is that the majority of people won't, but
it'll be possible and easy to do nonetheless.I really don't like that idea. If someone writes a function with type
hints,
people shouldn't be able to make those type hints go away or become more
or less strict. They should be consistent across environments and
contexts.
But that's exactly what you've been pushing (catching & ignoring
E_RECOVERABLE_ERROR), with two differences:
- You'd like it to default to the strict behavior instead of the lax,
PHP-like behavior - That behavior will be inconsistent with casting; Those 'similar, but
different' are the most annoying kinds of inconsistencies IMHO...
I do believe that the vast majority of people would want '32 ' and "42\n"
to silently convert to 32/42, and will generally not care much about
'32abc' converting to 32 either for the sake of consistency.
Zeev
Zeev Suraski wrote (on 14/07/2014):
I do believe that the vast majority of people would want '32 ' and "42\n"
to silently convert to 32/42, and will generally not care much about
'32abc' converting to 32 either for the sake of consistency.
And passing 'hello' to a function type hinted as int? Will people really
expect that to become a 0, with a mild warning they may not even have
enabled?
-----Original Message-----
From: Rowan Collins [mailto:rowan.collins@gmail.com]
Sent: Monday, July 14, 2014 7:44 PM
To: Zeev Suraski; Andrea Faulds
Cc: internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)Zeev Suraski wrote (on 14/07/2014):
I do believe that the vast majority of people would want '32 ' and
"42\n"
to silently convert to 32/42, and will generally not care much about
'32abc' converting to 32 either for the sake of consistency.And passing 'hello' to a function type hinted as int? Will people really
expect
that to become a 0, with a mild warning they may not even have enabled?
I'd say absolutely yes, if they're PHP developers that's exactly what they'd
expect. After all, if you use 'hello' today in any integer context in PHP,
explicit or implicit, that's exactly how it will behavior across the
language.
Zeev
Zeev Suraski wrote (on 14/07/2014):
I'd say absolutely yes, if they're PHP developers that's exactly what they'd
expect. After all, if you use 'hello' today in any integer context in PHP,
explicit or implicit, that's exactly how it will behavior across the
language.
And yet if you use it as a parameter to a type hinted function, it will
produce an error.
You can be consistent with casts, or consistent with existing type
hints, but not both.
If the current type hints were only for objects, I would be OK with
that, but I really don't get why an array cast is so different from an
int cast.
If the current type hints were only for objects, I would be OK with that, but I really don't get why an array cast is so different from an int cast.
I’m don’t think the result of casting to array is meaningful or lossless for anything
--
Andrea Faulds
http://ajf.me/
-----Original Message-----
From: Rowan Collins [mailto:rowan.collins@gmail.com]
Sent: Monday, July 14, 2014 8:24 PM
To: internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)Zeev Suraski wrote (on 14/07/2014):
I'd say absolutely yes, if they're PHP developers that's exactly what
they'd expect. After all, if you use 'hello' today in any integer
context in PHP, explicit or implicit, that's exactly how it will
behavior across the language.And yet if you use it as a parameter to a type hinted function, it will
produce
an error.
Type hints were first and foremost introduced for object oriented safety, as
a part of the major OO model shift Andi and I pushed for in PHP 5.0. What
you may be alluding to - type hints for arrays and objects - were added at
later time and introduced that small inconsistency you're talking about.
Still, type juggling for scalars has been the fundamental nature of PHP
since the get go; Type jugging for arrays/objects was always more of an
edge case and perhaps even a misfeature.
You can be consistent with casts, or consistent with existing type hints,
but not
both.
Type looseness defines PHP. Type hints do not.
Zeev
Type hints were first and foremost introduced for object oriented safety, as
a part of the major OO model shift Andi and I pushed for in PHP 5.0. What
you may be alluding to - type hints for arrays and objects - were added at
later time and introduced that small inconsistency you're talking about.
Still, type juggling for scalars has been the fundamental nature of PHP
since the get go; Type jugging for arrays/objects was always more of an
edge case and perhaps even a misfeature.
I’m not sure we actually do “juggle” arrays and objects much, do we? You can cast to them, sure, because PHP as a rule allows you to cast anything to anything explicitly (bar resources), but I can’t, for example, do a loose comparison between an array and a string.
--
Andrea Faulds
http://ajf.me/
-----Original Message-----
From: Andrea Faulds [mailto:ajf@ajf.me]
Sent: Monday, July 14, 2014 8:59 PM
To: Zeev Suraski
Cc: Rowan Collins; internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)Type hints were first and foremost introduced for object oriented
safety, as a part of the major OO model shift Andi and I pushed for in
PHP 5.0. What you may be alluding to - type hints for arrays and
objects - were added at later time and introduced that small
inconsistency
you're talking about.
Still, type juggling for scalars has been the fundamental nature of
PHP since the get go; Type jugging for arrays/objects was always more
of an edge case and perhaps even a misfeature.I'm not sure we actually do "juggle" arrays and objects much, do we? You
can
cast to them, sure, because PHP as a rule allows you to cast anything to
anything explicitly (bar resources), but I can't, for example, do a
loose
comparison between an array and a string.
Exactly, that's my point. While you can explicitly cast scalars to arrays
and even objects, it's an edge case and arguably a misfeature, and (IIRC)
never happens implicitly. And of course there's no way to turn a scalar
into a specific type of object or a resource.
Zeev
Hi!
cast to them, sure, because PHP as a rule allows you to cast anything to
anything explicitly (bar resources), but I can't, for example, do a
loose
comparison between an array and a string.Exactly, that's my point. While you can explicitly cast scalars to arrays
and even objects, it's an edge case and arguably a misfeature, and (IIRC)
never happens implicitly. And of course there's no way to turn a scalar
into a specific type of object or a resource.
We can take another option, which would be a compromise but still allows
us to preserve the consistency:
We can define casts as being two types - implicit cast and explicit
cast. Implicit cast would be anything where value of one type is used in
a context requiring value of another type, and would be roughly
following what we do now, with the exception of some most weird cases -
like array->string, non-array->array, resource->int/string, etc.
excluded (excluded meaning throwing an error, I am not specifying which
one as it is not important but probably the same kind as if you try to
pass "42" to function expecting SplArray).
Explicit cast would be the one used when you do (type), and this one
would include maximum possible conversion - i.e. in this case we would
permit casting anything to array, casting anything to string, and other
casts that we could give any meaning whatsoever without going completely
bananas. Of course the cases covered by the implicit cast should work
the same with the explicit cast.
We kind of already have it with (object) cast - you can not cast
anything to object implicitly, but can do an explicit cast - I just
propose making this a robust framework instead of one-off case.
With this, parameter types would naturally be a candidate to use
implicit casts when needed, while being consistent with the rest and
while still allowing forced casts in case we just don't care if any loss
occurs.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
Zeev,
And passing 'hello' to a function type hinted as int? Will people really
expect
that to become a 0, with a mild warning they may not even have enabled?I'd say absolutely yes, if they're PHP developers that's exactly what they'd
expect. After all, if you use 'hello' today in any integer context in PHP,
explicit or implicit, that's exactly how it will behavior across the
language.
Compare:
$ php -r 'var_dump(substr("abc", "1"));'
string(2) "bc"
$ php -r 'var_dump(substr("abc", "1sf"));'
PHP Notice: A non well formed numeric value encountered in Command
line code on line 1
string(2) "bc"
$ php -r 'var_dump(substr("abc", "apple"));'
PHP Warning: substr()
expects parameter 2 to be long, string given in
Command line code on line 1
NULL
So it's not really how it behaves across the language (especially
since the common paradigm is not run the function if zpp fails, which
it will when passing "apple" to a function expecting an int).
Zeev Suraski wrote (on 14/07/2014):
-----Original Message-----
From: Rowan Collins [mailto:rowan.collins@gmail.com]
Sent: Monday, July 14, 2014 6:28 PM
To: internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)Derick Rethans wrote (on 14/07/2014):
A compromise by adding more inconsistencies.
The only way of not introducing some inconsistencies (or, to put it
another
way, new features) is to use strict type hints
Actually there's a pretty simple way that's not strict type hints:
- Add type hints using existing syntax, which are casts; Change casts
(both existing and these new ones) to emit a new E_CAST in case of data
loss or 'bogus' conversions.Zeev
That's not consistent with current behaviour. This does not perform a
cast, it performs strict validation:
function foo(array $bar) { /* ... */ }
foo('123');
Also, I already mentioned it:
Option 2 (or 3) could also be implemented by making all lossy casts
emit some kind of notice.
The only consistent behaviour is strict validation, period. If you
want that, use Hack; if you want some other kind of type hint, it has to
introduce something new.
The only consistent behaviour is strict validation, period. If you
want that, use Hack; if you want some other kind of type hint, it
has to introduce something new.
Since we are looking at doing this what good reason is there for not adopting
the syntax & some of the semantics of Hack ?
http://docs.hhvm.com/manual/en/hack.annotations.php
NIH is not a good reason.
NIH = Not Invented Here
--
Alain Williams
Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT Lecturer.
+44 (0) 787 668 0256 http://www.phcomp.co.uk/
Parliament Hill Computers Ltd. Registration Information: http://www.phcomp.co.uk/contact.php
#include <std_disclaimer.h
Since we are looking at doing this what good reason is there for not adopting
the syntax & some of the semantics of Hack ?http://docs.hhvm.com/manual/en/hack.annotations.php
NIH is not a good reason.
NIH = Not Invented Here
We are using hack’s syntax (int, float, bool, string, no integer/double/boolean aliases). We are not using Hack’s semantics for reasons that have been discussed endlessly before in this thread and others, reasons which are not NIH.
--
Andrea Faulds
http://ajf.me/
Zeev,
Actually there's a pretty simple way that's not strict type hints:
- Add type hints using existing syntax, which are casts; Change casts
(both existing and these new ones) to emit a new E_CAST in case of data
loss or 'bogus' conversions.
The issue with this, is that it changes how your calling code will
behave based on global configuration. Not an issue for the application
developer (since they can control the global config), but for a
library developer who makes reusable code, this is going to become a
nightmare to deal with.
Example:
function foo(int $bar) {}
foo("12abc"); // May silently succeed. May raise E_CAST error. May
throw exception. Who knows!
That sounds like it's not a big deal, but it will result in calling
code needing to get extra defensive to be robust:
try {
foo($something);
} catch (\Exception) {
// I have no idea what exception may have been thrown here
}
Or ignoring the error entirely by "forcing" the unknown value to an integer:
foo((int) $something);
Which is exactly what this RFC was designed to avoid. Explicit casts
can be lossy, because it's clear that the programmers intention is for
the loss to occur. So (bool) array(123) is a valid cast, because it's
explicit. But implicitly, it's really not clear if that's what was
intended or not.
IMHO, strict hints are dangerous in the context of PHP because PHP's
types can change in unpredictable ways. A variable that was an integer
can turn into a float through seemingly integer operations. Example:
$a / $b * $b will result in a float unless $b divides $a (even though
for sane values of $a and $b, it will be exactly representable as an
int).
And that also hints towards a benefit of adding a numeric hint as well
(which will accept (and cast to) either an int or a float, exactly how
is_numeric_string() does internally)... Which is something that may
want to be considered for this RFC.
That would again result in (int) casts being used, which would then
hide the real error cases, such as passing "apple" to a function
expecting an integer...
These cast rules differ from the existing cast rules for a very
significant and important reason: they are implicit. If the user wants
to force something, they still have the normal cast mechanism to do
that. These cast rules are designed so that reflexive (lossless) casts
are free ("12" is 12), but lossly casts need intervention by the user
to confirm intent.
The edges are where things get odd. "12abc" is currently accepted by
zpp int types, but raises a notice. That was why the RFC initially
included it as a notice. But I agree with the move to making it an
outright error.
But then you get problem areas like booleans. On one hand, "foo"
doesn't make sense, but on the other $flags & FLAG does. But that
could just as well be a string. So either we let everything satisfy a
boolean (how ZPP already works) or we restrict it to lossless casts,
or we make it strict. None of them are really overly good IMHO, but
it's something that should be discussed...
I already mentioned before that I don't think consistency is a bad thing
(and that's an understatement). Having the syntax differ and have a
separate, similar set of rules/behaviors is a disadvantage, not an
advantage in my book.
Well, there is consistency. For the most part (around 95% of this
RFC), ZPP behaves the same way as this RFC is proposing. And I'd argue
that if this RFC is accepted, ZPP should be modified to behave like
this (for PHP_NEXT). The reason is that the rules for these implicit
casts are actually quite simple, with a few edge cases (which is where
the divergence from zpp happened).
There are several advantages of adding this syntax with the simple casting
behavior:
- It saves a bit of code and improves readability for a very common use
case.- It encourages developers to get the types straight instead of relying
on implicit casts.
Implicit casts are good, when it's not clear what the programmer
intended. And simply passing a variable to a function doesn't indicate
intent as we don't have typed variables. So having implicit casts be
"safer" is a good thing, as there's always an explicit cast if they
need it. And if it's not clear, I'd prefer having the implicit cast
error, and let the programmer use an explicit cast to clarify intent.
My $0.02
Anthony
-----Original Message-----
From: Anthony Ferrara [mailto:ircmaxell@gmail.com]
Sent: Monday, July 14, 2014 7:25 PM
To: Zeev Suraski
Cc: Rowan Collins; internals@lists.php.net
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)Zeev,
Actually there's a pretty simple way that's not strict type hints:
- Add type hints using existing syntax, which are casts; Change
casts (both existing and these new ones) to emit a new E_CAST in case
of data loss or 'bogus' conversions.The issue with this, is that it changes how your calling code will behave
based
on global configuration. Not an issue for the application developer (since
they
can control the global config), but for a library developer who makes
reusable
code, this is going to become a nightmare to deal with.Example:
function foo(int $bar) {} foo("12abc"); // May silently succeed. May raise E_CAST error. May
throw
exception. Who knows!
That's true for E_RECOVERABLE_ERROR
in the exact same way. We're only
arguing the 'default', in both cases the actual behavior will be affected by
global error handlers if they exist.
That sounds like it's not a big deal, but it will result in calling code
needing to
get extra defensive to be robust:try { foo($something); } catch (\Exception) { // I have no idea what exception may have been thrown here }
Or ignoring the error entirely by "forcing" the unknown value to an
integer:foo((int) $something);
Which is exactly what this RFC was designed to avoid.
I fail to see how it avoids it... An app developer using an API that
expects an int, and that has an integer-looking-string coming from the end
user or a file, will simply stick an (int) there to avoid the API from
complaining about extra spaces or even superfluous characters.
And that also hints towards a benefit of adding a numeric hint as well
(which
will accept (and cast to) either an int or a float, exactly how
is_numeric_string() does internally)... Which is something that may want
to be
considered for this RFC.
I definitely agree with this one (it's in
https://wiki.php.net/rfc/typecheckingstrictandweak )
That would again result in (int) casts being used, which would then hide
the
real error cases, such as passing "apple" to a function expecting an
integer...
If you care about it - you can easily spot it by paying attention to
E_CASTs. We're talking about runtime errors either way, if there was a way
to do 'compile time' error checking I'd see the point in going for errors,
but there isn't. And as a special bonus, if we change the casting code to
also emit E_CAST - then we don't just push people to find "apple" -> int
issues in that specific situation, but everywhere where there's a cast.
Zeev
IMHO, strict hints are dangerous in the context of PHP because PHP's
types can change in unpredictable ways. A variable that was an integer
can turn into a float through seemingly integer operations. Example:
$a / $b * $b will result in a float unless $b divides $a (even though
for sane values of $a and $b, it will be exactly representable as an
int).
But if you have:
function foo(int $a) {
...
$a = 3 / 2;
}
What do you expect $a to contain ? I would suggest integer 1.
And that also hints towards a benefit of adding a numeric hint as well
(which will accept (and cast to) either an int or a float, exactly how
is_numeric_string() does internally)... Which is something that may
want to be considered for this RFC.
+1
--
Alain Williams
Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT Lecturer.
+44 (0) 787 668 0256 http://www.phcomp.co.uk/
Parliament Hill Computers Ltd. Registration Information: http://www.phcomp.co.uk/contact.php
#include <std_disclaimer.h
IMHO, strict hints are dangerous in the context of PHP because PHP's
types can change in unpredictable ways. A variable that was an integer
can turn into a float through seemingly integer operations. Example:
$a / $b * $b will result in a float unless $b divides $a (even though
for sane values of $a and $b, it will be exactly representable as an
int).But if you have:
function foo(int $a) { ... $a = 3 / 2; }
What do you expect $a to contain ? I would suggest integer 1.
I would expect the same result as 3.0 / 2.0, as would most every new programmer.
But if you have:
function foo(int $a) {
...
$a = 3 / 2;
}What do you expect $a to contain ? I would suggest integer 1.
I’d expect (and I think most people new to PHP would expect) what 3/2 would be in normal maths, i.e. the fractional value 0.666…. Actually, this makes a good case for return type hinting, as you could ensure you’d get an integer result here. (But that is another matter.)
--
Andrea Faulds
http://ajf.me/
But if you have:
function foo(int $a) {
...
$a = 3 / 2;
}What do you expect $a to contain ? I would suggest integer 1.
I’d expect (and I think most people new to PHP would expect) what 3/2 would be in normal maths, i.e. the fractional value 0.666…. Actually, this makes a good case for return type hinting, as you could ensure you’d get an integer result here. (But that is another matter.)
I trust that you meant 1.5 not 0.666.
I would have expected 1 - since it appears, from the code, that $a should only contain integers.
--
Alain Williams
Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT Lecturer.
+44 (0) 787 668 0256 http://www.phcomp.co.uk/
Parliament Hill Computers Ltd. Registration Information: http://www.phcomp.co.uk/contact.php
#include <std_disclaimer.h
I trust that you meant 1.5 not 0.666.
Er… yes. I somehow misread 3/2 as 2/3.
I would have expected 1 - since it appears, from the code, that $a should only contain integers.
So? PHP doesn’t do integer division. It does what Python 3 does: if two integers cannot divide cleanly, then a float division is done instead. This may not be what C, C++, C#, Java, or some other strictly-typed languages do, but it is what PHP does, and has done for a long time. It’s also what makes the most sense, IMO.
--
Andrea Faulds
http://ajf.me/
But if you have:
function foo(int $a) {
...
$a = 3 / 2;
}What do you expect $a to contain ? I would suggest integer 1.
I would have expected 1 - since it appears, from the code, that $a should
only contain integers.
What about the current type hinting we have, then?
function foo(Bar $a) {
$a = 3 / 2;
}
Perfectly OK. Why would we treat scalars any different?
On Mon, Jul 14, 2014 at 7:19 PM, Kristopher kristopherwilson@gmail.com
wrote:
But if you have:
function foo(int $a) {
...
$a = 3 / 2;
}What do you expect $a to contain ? I would suggest integer 1.
I would have expected 1 - since it appears, from the code, that $a should
only contain integers.
What about the current type hinting we have, then?
function foo(Bar $a) {
$a = 3 / 2;
}Perfectly OK. Why would we treat scalars any different?
this was asked and answered a dozen of times in the past, but let me repeat
once again:
php does support type juggling/coercion for scalar types, but not for
complex types.
introducing "strict" typehints for complex types was safe, as there are no
expectation from the users, if you expect an instance of Foo and you got a
Bar (which isn't a subclass of Foo) then you know that you screwed up.
(personally I think that the adding the support for array to the strict
typehints was a bad idea, but that is out of scope here.)
But people do have expectations about the scalar types in php, and they
used to not care about the exact types of a variable as long as it can be
coerced into the expected type.
If you think it over, probably 80-90%+ of all incoming data we are working
with coming from a source which delivers everything as a string (anything
coming from HTTP is a string, anything coming from the database which isn't
using a binary protocol arrives as string, anything coming from memcached
is a string, redis: same thing).
But php doesn't care, because one of it's distinguished features is that it
can coerce between scalar types.
If we introduce scalar type hints, people will use it, if they will use it,
people have to be aware that they can't pass numeric looking strings into
functions and expect them to work.
It will blow up with a fat E_RECOVERABLE_ERROR.
But this won't hold back the library authors from using it, which means
that the consumers of those libs has to start coding defensively, and make
sure that the variable holding the value 123 is an integer and not a float
or a string, because that will blow up something.
And we can argue whether or not it is a good thing that php has type
juggling, but we have that, and it is not likely to be changed(biggest BC
break ever), so introducing something which completelly negates that won't
likely to get support from the devs.
--
Ferenc Kovács
@Tyr43l - http://tyrael.hu
On Mon, Jul 14, 2014 at 7:19 PM, Kristopher kristopherwilson@gmail.com
wrote:On Mon, Jul 14, 2014 at 1:14 PM, Alain Williams addw@phcomp.co.uk
wrote:But if you have:
function foo(int $a) {
...
$a = 3 / 2;
}What do you expect $a to contain ? I would suggest integer 1.
I would have expected 1 - since it appears, from the code, that $a should
only contain integers.
What about the current type hinting we have, then?
function foo(Bar $a) {
$a = 3 / 2;
}Perfectly OK. Why would we treat scalars any different?
this was asked and answered a dozen of times in the past, but let me
repeat once again:php does support type juggling/coercion for scalar types, but not for
complex types.
introducing "strict" typehints for complex types was safe, as there are no
expectation from the users, if you expect an instance of Foo and you got a
Bar (which isn't a subclass of Foo) then you know that you screwed up.
(personally I think that the adding the support for array to the strict
typehints was a bad idea, but that is out of scope here.)
But people do have expectations about the scalar types in php, and they
used to not care about the exact types of a variable as long as it can be
coerced into the expected type.
If you think it over, probably 80-90%+ of all incoming data we are working
with coming from a source which delivers everything as a string (anything
coming from HTTP is a string, anything coming from the database which isn't
using a binary protocol arrives as string, anything coming from memcached
is a string, redis: same thing).
But php doesn't care, because one of it's distinguished features is that
it can coerce between scalar types.
If we introduce scalar type hints, people will use it, if they will use
it, people have to be aware that they can't pass numeric looking strings
into functions and expect them to work.
It will blow up with a fat E_RECOVERABLE_ERROR.
But this won't hold back the library authors from using it, which means
that the consumers of those libs has to start coding defensively, and make
sure that the variable holding the value 123 is an integer and not a float
or a string, because that will blow up something.
And we can argue whether or not it is a good thing that php has type
juggling, but we have that, and it is not likely to be changed(biggest BC
break ever), so introducing something which completelly negates that won't
likely to get support from the devs.--
Ferenc Kovács
@Tyr43l - http://tyrael.hu
sorry, not neccessary the best place for my reply, I just had to type that
out seeing the dozens of mails from the last couple of days.
--
Ferenc Kovács
@Tyr43l - http://tyrael.hu
Hi!
I would have expected 1 - since it appears, from the code, that $a should only contain integers.
Until the time you changed it. If you write:
function foo(SplFileInfo $a) {
$a = 3 / 2;
}
Would you somehow expect $a to magically conjure SplFileInfo object out
of 3/2?
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
And that also hints towards a benefit of adding a numeric hint as well
(which will accept (and cast to) either an int or a float, exactly how
is_numeric_string() does internally)... Which is something that may
want to be considered for this RFC.
I’ve finally gotten round to doing this (I had to fix most of the mess of segfaults and broken tests first). The RFC now proposes a ‘numeric’ type hint that does what you expect it to, casting to int or float.
The implementation (which is done and tested for this type hint) is straightforward, though there’s a minor issue with casting of objects. As IS_NUMERIC is a fake type, cast_object doesn’t support it, so it’ll try IS_LONG first, unfortunately. Not much we can do about that.
Actually, perhaps it would be possible to try IS_NUMERIC, and if that fails, try IS_LONG, then try IS_DOUBLE. Should I do that?
--
Andrea Faulds
http://ajf.me/
Derick Rethans wrote (on 14/07/2014):
A compromise by adding more inconsistencies.
The only way of not introducing some inconsistencies (or, to put it another
way, new features) is to use strict type hints, which perform no casting, and
error on invalid input, since that's what the existing type hints do, in
particular "array". There's broad consensus that that wouldn't be very
"PHP-ish", and it has been rejected in previous discussions.
I am quite aware of that.
Here are the main variants discussed in this thread:
- add type hints using existing syntax, but which are actually silent casts,
rather than the strict validation performed for existing types
- add type hints using existing syntax, which are casts, but also act
differently from existing casts by emitting some kind of notice
- add cast hints using a new syntax
- add type hints using existing syntax, which use a new "lossless cast", i.e.
perform validation for completely wrong input ('abc' as an int param) but
allow juggling for "reasonable" input ('123' as an int param).Option 2 (or 3) could also be implemented by making all lossy casts emit
some kind of notice.This RFC currently proposes option 4.
Yes. And with that option I have a problem, as nothing else does it like
that now - hence my arguing against "a new set of casting rules". Option
1 is equivalent to my argument that this should be equivalent:
function foo(int $var) {}
function foo($var) { $var = (int) $var; }
and called by f.e.:
foo('123abc');
cheers,
Derick
--
http://derickrethans.nl | http://xdebug.org
Like Xdebug? Consider a donation: http://xdebug.org/donate.php
twitter: @derickr and @xdebug
Posted with an email client that doesn't mangle email: alpine
Hi!
In general, I am not in favour of casting typehints, as it would be a
different behaviour from the hard-check typehints that we already have
for classes and arrays.
It already is. All internal functions behave this way.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
In general, I am not in favour of casting typehints, as it would be
a different behaviour from the hard-check typehints that we already
have for classes and arrays.It already is. All internal functions behave this way.
But casting typehints is a userland feature, not an internal function.
cheers,
Derick
hi Andrea,
Good evening,
PHP’s type hinting system is rather incomplete as it does not support scalars, only arrays, callables and objects. In 2012, Anthony Ferrara created an RFC which proposed type hinting for scalar types (int, float, bool, string and resource) with casting, with behaviour nearly the same as that of zend_parse_parameters. Sadly, he later left PHP internals and withdrew his RFCs.
Since I am very much in favour of scalar type hints, I’ve updated the patch to master and made some minor improvements, and I am re-opening the RFC with the intent to try and get it into PHP 5.7. The patch is mostly there. It needs some more tests and there are some edge cases I need to deal with, but it otherwise works, and I expect I can finish fixing it up very soon.
The RFC is here: https://wiki.php.net/rfc/scalar_type_hinting_with_cast
A pull request is here: https://github.com/php/php-src/pull/717
I’m hoping I can get this into PHP 5.7. I think scalar type hinting would be a valuable addition to PHP’s existing type hinting system.
very nice work, thanks!
Some comments or wishes. I know these points have been discussed
already in the other threads but I still think it is worth posting
that here and (re) consider it.
To me argument types handling should match what we already do for
classes, strict handling. I asked many users at various conferences or
large companies using PHP and this is also what they wish. Indeed I am
not saying that all users wish that (who am I to say that? :) but I
feel like there is a large majority expecting this behavior.
The argument saying that it is not the PHP way is somehow incorrect
here, given that we already do that for classe. The type jungling
makes sense in implementations, as it always was but argument passing
and validation have been a source of pain since very long. I could
imagine one exception with the "numeric" type, which could accept
anything and got converted to integer/numeric values, like "1235ab" or
other weird things.
Cheers,
Pierre
@pierrejoye | http://www.libgd.org
The argument saying that it is not the PHP way is somehow incorrect
here, given that we already do that for classe. The type jungling
makes sense in implementations, as it always was but argument
passing
and validation have been a source of pain since very long. I could
imagine one exception with the "numeric" type, which could accept
anything and got converted to integer/numeric values, like "1235ab" or
other weird things.
Personal opinion of a nonvoter, just for the record :)
The fact that roughly everybody in the strict-and-validation camp in the
recent discussions, adds in a different view on "with the exception of",
very very strongly suggests that the strict-and-validation POV is wrong
wrong wrong.
On the one hand, because calling code will become sprinkled with
casts on function calls to coerce the arguments to conform to the strict
interpretation.
And on the other hand, because validation needs, for all practical
purposes, are far more finegrained than any half-a-dozen-type scheme.
So, I'm 100% in the cast camp, i.e. interpret scalar type annotation of
function arguments as syntactic sugar for explicit casts at the beginning
of the function.
best regards
Patrick
The argument saying that it is not the PHP way is somehow incorrect
here, given that we already do that for classe. The type jungling
makes sense in implementations, as it always was but argument passing
and validation have been a source of pain since very long. I could
imagine one exception with the "numeric" type, which could accept
anything and got converted to integer/numeric values, like "1235ab" or
other weird things.
Personal opinion of a nonvoter, just for the record :)
The fact that roughly everybody in the strict-and-validation camp in the
recent discussions, adds in a different view on "with the exception of",
very very strongly suggests that the strict-and-validation POV is wrong
wrong wrong.
I wrote "I could imagine" not "I want or prefer" the numeric one. To me
being strict is what I would like to see.
Hi,
there is, it seems, something missing from both the RFC and the
discussion, as far as I read it. Sorry if it came up before, it was a huge
amount of mails...
How does the proposal affect method compatibility between
subclasses and baseclasses? Will two methods there, differing in the
scalar type annotations of one of their arguments, elicit STRICT
warnings, like object type annotations do?
I'm undecided about what would be the "right thing" in that regard, but I
think it should be clarified.
best regards
Patrick
Hi,
there is, it seems, something missing from both the RFC and the
discussion, as far as I read it. Sorry if it came up before, it was a huge
amount of mails...How does the proposal affect method compatibility between
subclasses and baseclasses? Will two methods there, differing in the
scalar type annotations of one of their arguments, elicit STRICT
warnings, like object type annotations do?
I think it should behave like class arguments do.
Cheers,
Pierre
@pierrejoye | http://www.libgd.org
Hi!
I think it should behave like class arguments do.
That's called strict typing and was discussed many times. Do we really
want another round of repeating the same arguments?
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
Hi!
I think it should behave like class arguments do.
That's called strict typing and was discussed many times. Do we really
want another round of repeating the same arguments?
As I said, yes it was discussed, and yes I think it makes sense to
consider it. I won't discuss or battle that to hell tho', it is only
the way it my humble opinion.
--
Pierre
@pierrejoye | http://www.libgd.org
-----Original Message-----
From: Stas Malyshev [mailto:smalyshev@sugarcrm.com]
Sent: Thursday, July 24, 2014 12:04 PM
To: Pierre Joye
Cc: PHP internals
Subject: Re: [PHP-DEV] [RFC] Scalar Type Hinting With Casts (re-opening)That's called strict typing and was discussed many times. Do we really
want
another round of repeating the same arguments?
We definitely do not..
To elaborate, the notion that we already have strict class types for
classes, so we should have the same thing for scalar makes no sense at all.
Here's why:
- If it was the case, we'd add this right when we added class type hints
(strict class types). - The fact of the matter is that we did not. Why not? Because scalars in
PHP behave in an inherently different way. - As I stated already, 'Dynamic Typing defines PHP, class type hints do
not'. Class type hints were added at a MUCH later stage, as a part of the
major rollout of the new object model of PHP 5. It was actually agreed that
the only way we'd add such type hints is if we weren't going to have them
for scalar types.
What we have on the table right now - casting type hints - can be made to
behave in a way that's consistent with the dynamic typing nature of PHP.
My main concern about the RFC the way it stands right now is that the
current direction involves E_RECOVERABLE_ERROR
instead of E_STRICT
or E_CAST
for data loss. This results in both consistency issues with casting as well
as incompatibility with the dynamic nature of PHP scalars. I know the RFC
author (Andrea) disagrees with me about it, but I think we need to find a
way to put this into a much wider decision. Probably the most practical
thing to do is to put it as a secondary question in the RFC, although those
can be tricky.
Zeev
We definitely do not..
Well, open list, if some like to discuss it, we can. But see below, it
may not be necessary.
To elaborate, the notion that we already have strict class types for
classes, so we should have the same thing for scalar makes no sense at all.
Here's why:
- If it was the case, we'd add this right when we added class type hints
(strict class types).
Just like we'd to add full OO concepts right with 5.0.
- As I stated already, 'Dynamic Typing defines PHP, class type hints do
not'. Class type hints were added at a MUCH later stage, as a part of the
major rollout of the new object model of PHP 5. It was actually agreed that
the only way we'd add such type hints is if we weren't going to have them
for scalar types.What we have on the table right now - casting type hints - can be made to
behave in a way that's consistent with the dynamic typing nature of PHP.
Except for the cases I listed in my 2nd mail, which you certainly did
not read. However, my mistake, I had an outdated version of the RFC
and clearing my local cache shows me the actual one, which matches
100% what I would like to see and wrote in my replies in this thread.
My main concern about the RFC the way it stands right now is that the
current direction involvesE_RECOVERABLE_ERROR
instead ofE_STRICT
or E_CAST
for data loss. This results in both consistency issues with casting as well
as incompatibility with the dynamic nature of PHP scalars. I know the RFC
author (Andrea) disagrees with me about it, but I think we need to find a
way to put this into a much wider decision. Probably the most practical
thing to do is to put it as a secondary question in the RFC, although those
can be tricky.
I do not like these errors either, I would prefer to have the same
than with class arguments, consistent, easy to catch for the
developers. So yes, maybe a 2nd question about how bad arguments
should be handled would be a good thing.
Cheers,
Pierre
@pierrejoye | http://www.libgd.org
My main concern about the RFC the way it stands right now is that the
current direction involvesE_RECOVERABLE_ERROR
instead ofE_STRICT
or E_CAST
for data loss. This results in both consistency issues with casting as well
as incompatibility with the dynamic nature of PHP scalars. I know the RFC
author (Andrea) disagrees with me about it, but I think we need to find a
way to put this into a much wider decision. Probably the most practical
thing to do is to put it as a secondary question in the RFC, although those
can be tricky.Zeev
Hi, all
I looked again at the RFC ..
Can someone please update the description at the section "Conversion Rules"?
This is quoted from the document:
Conversion is allowed only if data-loss does not happen. There are a few exceptions (objects using __toString, strings containing leading numerics, etc). Here's a table of examples.
But if you look at the table, strings containing leading numbers are
not allowed.
And just as a thought: What about objects where the __toString method
returns a string like "42"? Would that also be accepted as an
argument, that just accepts integers? Sounds crazy, but as strings,
only containing numbers, are accepted as integer, we have to take a
decision here and write it down.
Bye
Simon
Conversion is allowed only if data-loss does not happen. There are a few exceptions (objects using __toString, strings containing leading numerics, etc). Here's a table of examples.
But if you look at the table, strings containing leading numbers are
not allowed.
Good catch, fixed.
And just as a thought: What about objects where the __toString method
returns a string like "42"? Would that also be accepted as an
argument, that just accepts integers?
No it wouldn’t, as that’s not what cast_object does, existing conversion functions do, or what the patch does at present.
Andrea Faulds
http://ajf.me/
Hi,
there is, it seems, something missing from both the RFC and the
discussion, as far as I read it. Sorry if it came up before, it was a huge
amount of mails...How does the proposal affect method compatibility between
subclasses and baseclasses? Will two methods there, differing in the
scalar type annotations of one of their arguments, elicit STRICT
warnings, like object type annotations do?I think it should behave like class arguments do.
I should be more precise :)
say:
function i(integer $i)
function f(float $f)
function s(string $s)
$i = 12;
$f = 1.234;
$s = "abcdef";
For integer arguments:
Works:
i($i);
Fails:
i($f);
i($s);
i(new StdClass);
float fails as the argument cannot be an integer without lost of
information. It is a mis-usage of this function argument and the
intend of the caller can only be guessed and can only lead to bugs.
For float:
Works:
f($i);
f($f);
integer is, if I take the class behavior as example, like a float,
same "interface", fully compatible.
Fails:
f($s);
i(new StdClass);
For string, every scalar should work as both float and integer are
easily converted to string, we can compare them to objects with a
__toString method. I could live with strict too here but implicit
string conversion makes sense here. Float precision setting is used
for the decimal precision.
Arrays and objects without __toString fails, obvioulsy.
Cheers,
Pierre
@pierrejoye | http://www.libgd.org
Hi,
there is, it seems, something missing from both the RFC and the
discussion, as far as I read it. Sorry if it came up before, it was a huge
amount of mails...How does the proposal affect method compatibility between
subclasses and baseclasses? Will two methods there, differing in the
scalar type annotations of one of their arguments, elicit STRICT
warnings, like object type annotations do?I think it should behave like class arguments do.
I should be more precise :)
say:
function i(integer $i)
function f(float $f)
function s(string $s)$i = 12;
$f = 1.234;
$s = "abcdef";For integer arguments:
Works:
i($i);Fails:
i($f);
i($s);
i(new StdClass);float fails as the argument cannot be an integer without lost of
information. It is a mis-usage of this function argument and the
intend of the caller can only be guessed and can only lead to bugs.For float:
Works:
f($i);
f($f);
integer is, if I take the class behavior as example, like a float,
same "interface", fully compatible.Fails:
f($s);
i(new StdClass);For string, every scalar should work as both float and integer are
easily converted to string, we can compare them to objects with a
__toString method. I could live with strict too here but implicit
string conversion makes sense here. Float precision setting is used
for the decimal precision.Arrays and objects without __toString fails, obvioulsy.
and to clarify this, after I got some questions/comments on irc etc.:
f.e.
foo(int $a) {
var_dump($a===123);
}
foo(123) >> true
foo("123") >> true
foo("123a")>> error, bad arg
same for float. The cast happens, it would not make sense if not :)
Cheers,
Pierre
@pierrejoye | http://www.libgd.org
How does the proposal affect method compatibility between subclasses and baseclasses? Will two methods there, differing in the scalar type annotations of one of their arguments, elicit STRICT warnings, like object type annotations do?
As implemented, yes.
--
Andrea Faulds
http://ajf.me/
The RFC is here: https://wiki.php.net/rfc/scalar_type_hinting_with_cast
A pull request is here: https://github.com/php/php-src/pull/717
I just updated the patch and RFC to include overflow safety for the integer type hint. This means that the following code is an error:
function foo(int $a) {}
foo(‘8493284029384029384028409304249230894’);
This is actually a level of safety you couldn’t get with any other proposal. If you explicitly cast with (int) it will silently saturate/cap the integer (data is lost), and zend_parse_parameters will silently saturate or truncate (depending on the function).
This is consistent with passing a float. Were I to do the following, it was already an error in the proposal:
function foo(int $a) {}
foo(8493284029384029384028409304249230894.0);
--
Andrea Faulds
http://ajf.me/