Hello internals,
I'd like to propose an enhancement to curl_setopt()
http://php.net/manual/en/function.curl-setopt.php which is used to
configure a given curl session. The second argument of this function
defines which option to set and the third argument provides the
corresponding value to use.
Because each option expects the value to be a specific type, it makes sense
to enforce these types in strict type checking mode. I'd therefore like to
propose that we introduce strict type enforcement inside curl_setopt()
when
"declare(strict_types=1);" is being used.
The full details of the proposal, including the proposed patch, can be
found here: https://wiki.php.net/rfc/curl_setopt_strict_types
Huge thanks to Sara Golemon for the idea and creating the patch!
Cheers,
Colin O'Dell
colinodell@gmail.com
I'd like to propose an enhancement to
curl_setopt()
http://php.net/manual/en/function.curl-setopt.php which is used to
configure a given curl session. The second argument of this function
defines which option to set and the third argument provides the
corresponding value to use.Because each option expects the value to be a specific type, it makes sense
to enforce these types in strict type checking mode. I'd therefore like to
propose that we introduce strict type enforcement insidecurl_setopt()
when
"declare(strict_types=1);" is being used.The full details of the proposal, including the proposed patch, can be
found here: https://wiki.php.net/rfc/curl_setopt_strict_types
A note on the current state of the PR: Colin's RFC is based on the
first commit in that PR, but after more thought and some feedback from
NikiC, I piled a refactor on top of it which quite notably changes the
weak-mode handling. See
https://github.com/php/php-src/pull/2495#issuecomment-296383366
So some decisions to make yet regarding precisely how we'd land the
final commit, but I hope we can all agree the intent stated in the RFC
is pretty sound: Improve type checking in curl_setopt()
without
screwing over the majority of existing users.
-Sara
Hi!
Because each option expects the value to be a specific type, it makes sense
to enforce these types in strict type checking mode. I'd therefore like to
propose that we introduce strict type enforcement insidecurl_setopt()
when
"declare(strict_types=1);" is being used.
While it may make sense to check types per-option, that's not exactly
what scalar types are supposed to do - this is not argument typing, this
is internal function business logic, and I am not sure confusing the two
is really that good an idea.
--
Stas Malyshev
smalyshev@gmail.com
Hi!
Because each option expects the value to be a specific type, it makes sense
to enforce these types in strict type checking mode. I'd therefore like to
propose that we introduce strict type enforcement insidecurl_setopt()
when
"declare(strict_types=1);" is being used.While it may make sense to check types per-option, that's not exactly
what scalar types are supposed to do - this is not argument typing, this
is internal function business logic, and I am not sure confusing the two
is really that good an idea.
I completely agree with Stanislav at this point. curl_setopt
can and
probably should validate the types of the various options, it may even
throw a TypeError
, but it most certainly should not depend on the
strict_types
declaration.
--
Richard "Fleshgrinder" Fussenegger
Hi!
Because each option expects the value to be a specific type, it makes sense
to enforce these types in strict type checking mode. I'd therefore like to
propose that we introduce strict type enforcement insidecurl_setopt()
when
"declare(strict_types=1);" is being used.While it may make sense to check types per-option, that's not exactly
what scalar types are supposed to do - this is not argument typing, this
is internal function business logic, and I am not sure confusing the two
is really that good an idea.I completely agree with Stanislav at this point.
curl_setopt
can and
probably should validate the types of the various options, it may even
throw aTypeError
, but it most certainly should not depend on the
strict_types
declaration.
I disagree. From the user's perspective it is argument typing. The
internal implementation detail of that argument type being dependent
on another arg's value is just a detail.
-Sara
Hi!
I disagree. From the user's perspective it is argument typing. The
Not really. Argument typing is when arguments have types. curl_setopt
arguments do not have known types, they have business logic inside that
says if argument X is equal to this, then argument Y must be of that
type. It's very different from what strict_types does.
internal implementation detail of that argument type being dependent
on another arg's value is just a detail.
It's not "just a detail", it's the whole point of it. The value argument
does not have a know type, it is typed only when you know the exact
value of another argument (and sometimes not even then - e.g.
CURLOPT_POSTFIELDS
accepts both strings and arrays). We don't have "type
that is defined by another type" in the type system, it's clearly
business logic. Which I have no problem with, but it shouldn't be part
of type system then.
Stas Malyshev
smalyshev@gmail.com
it's clearly
business logic. Which I have no problem with, but it shouldn't be part
of type system then.
We're certainly arguing semantics at this point. Let's agree that
type enforcement is a good thing (which you seemed to say in your
first response) and move on to how that's implemented.
Why shouldn't we allow the same call-time decision making around
strict/weak enforcement to apply to "business logic" type enforcement
as it does to argument types? Surely consistency is a good thing as
well?
-Sara
25.04.2017 01:56 "Sara Golemon" pollita@php.net napisał(a):
On Mon, Apr 24, 2017 at 4:09 PM, Stanislav Malyshev smalyshev@gmail.com
wrote:it's clearly
business logic. Which I have no problem with, but it shouldn't be part
of type system then.We're certainly arguing semantics at this point. Let's agree that
type enforcement is a good thing (which you seemed to say in your
first response) and move on to how that's implemented.
I agree with Stanislav. IMHO argument types are valueable when are
reflective by reflection and curl_setopt has no valuable info by reflection
and will never be. Curl implementation also uses resources cURL handle is
used. Maybe it's time to refactor and provide objects with option setters
with argument types?
Why shouldn't we allow the same call-time decision making around
strict/weak enforcement to apply to "business logic" type enforcement
as it does to argument types? Surely consistency is a good thing as
well?-Sara
On Mon, Apr 24, 2017 at 9:00 PM, Michał Brzuchalski
michal.brzuchalski@gmail.com wrote:
I agree with Stanislav. IMHO argument types are valueable when are
reflective by reflection and curl_setopt has no valuable info by reflection
and will never be. Curl implementation also uses resources cURL handle is
used.
Literally zero internal functions have argument type reflection
(beyond class and array types). curl_setopt()
is not and would not be
any different in this regard.
Maybe it's time to refactor and provide objects with option setters
with argument types?
I do agree there. I've got a WiP "cURLi" extention in my homedir that
I've been poking at since ZendCon 2016. I suppose if we don't put
type checking in curl_setopt()
then that'll just push users who care
about type safety towards cURLi. :D
-Sara
Maybe it's time to refactor and provide objects with option setters
with argument types?I do agree there. I've got a WiP "cURLi" extention in my homedir that
I've been poking at since ZendCon 2016. I suppose if we don't put
type checking incurl_setopt()
then that'll just push users who care
about type safety towards cURLi. :D
Oh, lordy, yes please! The curl API is absolutely horrible, and just crying out for a more sane wrapper to be built into the language, rather than everyone writing their own messy classes.
Please can we also set some sane defaults (e.g. CURLOPT_RETURNTRANSFER) and a small amount of extra logic (e.g. capturing return headers) so that using it doesn't require a dozen lines of boilerplate to be useful?
Thanks,
--
Rowan Collins
[IMSoP]
On Mon, Apr 24, 2017 at 9:00 PM, Michał Brzuchalski
michal.brzuchalski@gmail.com wrote:I agree with Stanislav. IMHO argument types are valueable when are
reflective by reflection and curl_setopt has no valuable info by reflection
and will never be. Curl implementation also uses resources cURL handle is
used.Literally zero internal functions have argument type reflection
(beyond class and array types).curl_setopt()
is not and would not be
any different in this regard.Maybe it's time to refactor and provide objects with option setters
with argument types?I do agree there. I've got a WiP "cURLi" extention in my homedir that
I've been poking at since ZendCon 2016. I suppose if we don't put
type checking incurl_setopt()
then that'll just push users who care
about type safety towards cURLi. :D-Sara
Way to go. This RFC is just wrong, and not simply about semantics.
--
Richard "Fleshgrinder" Fussenegger
Hi Michał,
Michał Brzuchalski wrote:
IMHO argument types are valueable when are
reflective by reflection and curl_setopt has no valuable info by reflection
and will never be.
Neither do the vast majority of internal functions with parameter type
checking.
--
Andrea Faulds
https://ajf.me/
Hi,
Hello internals,
I'd like to propose an enhancement to
curl_setopt()
http://php.net/manual/en/function.curl-setopt.php which is used to
configure a given curl session. The second argument of this function
defines which option to set and the third argument provides the
corresponding value to use.Because each option expects the value to be a specific type, it makes sense
to enforce these types in strict type checking mode. I'd therefore like to
propose that we introduce strict type enforcement insidecurl_setopt()
when
"declare(strict_types=1);" is being used.
I'm sorry to say but I think this /approach/ is a horrible idea :(
To me the intention of strict types is clearly on the functions publicly
visible contract, i.e. it's reflectable parameters and not some business
logic hidden inside a function.
regards,
- Markus
To me the intention of strict types is clearly on the functions publicly
visible contract, i.e. it's reflectable parameters and not some business
logic hidden inside a function.
So you feel that declare(strict_types=1); should never apply to
internal functions?
-Sara
On Fri, Apr 28, 2017 at 9:34 AM, Markus Fischer markus@fischer.name
wrote:To me the intention of strict types is clearly on the functions
publicly
visible contract, i.e. it's reflectable parameters and not some
business
logic hidden inside a function.So you feel that declare(strict_types=1); should never apply to
internal functions?
I don't see that assertion implied in any of the objections on this thread. The objection is that type checking currently only occurs at function boundaries: their signatures are matched against provided parameters, and their return declarations against returned values. The entire feature is equivalent to the compiler injecting either casts (weak mode) or assertions (strict mode) at the beginning and end of function definitions, and nowhere else.
This RFC introduces a check at a different point in the function: after the parameters have been examined, based not on the signature of the function, but an internal set of rules.
Notably, this is not a type of check that could be made in a userland function - or, rather, it would have to be made unconditionally, since the strict_types setting is explicitly invisible to the callee.
So, while I agree that checking the argument types for curl_setopt()
is highly desirable, I am sympathetic to the argument that strict_types should not alter those checks.
That leaves us with either checking the types unconditionally (a significantly breaking change) or introducing a new, type-safe, API. That could mean a small but awkward set of type overloads (setBool, setInt, etc), or a large set of named setters (setReturnTransfer, setHeaders, etc) which could use normal parameter hinting to interact with strict_types.
As I mentioned, I think the entire PHP curl API is unnecessarily complicated to use, and the overloading of parameter types in curl_setopt actually contributes to this rather than simplifying anything.
Regards,
--
Rowan Collins
[IMSoP]
On Fri, Apr 28, 2017 at 9:34 AM, Markus Fischer markus@fischer.name
wrote:To me the intention of strict types is clearly on the functions
publicly
visible contract, i.e. it's reflectable parameters and not some
business
logic hidden inside a function.So you feel that declare(strict_types=1); should never apply to
internal functions?I don't see that assertion implied in any of the objections on this thread.
It's implied by the statement of yours that I quoted. "To me the
intention of strict types is clearly on the functions publicly visible
contract, i.e. it's reflectable parameters and not some business logic
hidden inside a function."
Internal functions do not have reflectable type hints (apart from
array and object), ergo by your criteria you feel that strict types
does not apply. Your words.
The objection is that type checking currently only occurs at function boundaries:
their signatures are matched against provided parameters, and their return
declarations against returned values. The entire feature is equivalent to the
compiler injecting either casts (weak mode) or assertions (strict mode) at the
beginning and end of function definitions, and nowhere else.
But that isn't how strict type enforcement works in internal
functions. I realize I'm being pedantic here, but since the objection
is on semantics grounds, I feel I must apply the same standards of
semantics to the counter argument.
The state of the PR at the moment is to apply function-entrance
criteria to arguments, the only thing which makes it (somewhat)
special is the degree of deferment from the C function entry till the
types are checked. I say "somewhat", because it is not unique in this
regard, many internal functions apply varying signatures based on
initial argument and/or number of arguments. See pg_*() functions for
my favorite example of this, though there are several examples in
standard as well.
This RFC introduces a check at a different point in the function:
after the parameters have been examined, based not on the
signature of the function, but an internal set of rules.
Repeat; See above, this is not unique.
Notably, this is not a type of check that could be made in a userland function -
or, rather, it would have to be made unconditionally, since the strict_types setting
is explicitly invisible to the callee.
Agreed, but userland and internal functions are not created equal and
this behavior is still not without precedent.
So, while I agree that checking the argument types for
curl_setopt()
is highly desirable,
I am sympathetic to the argument that strict_types should not alter those checks.
We disagree.
That leaves us with either checking the types unconditionally (a significantly breaking change)
or introducing a new, type-safe, API.
It also leaves us with the third option of what is presented by the
PR. You do not have absolute veto.
That could mean a small but awkward set of type overloads
(setBool, setInt, etc), or a large set of named setters
(setReturnTransfer, setHeaders, etc) which could use
normal parameter hinting to interact with strict_types.
Eww. Eww. And eew.
I reject the idea of making a worse API for the sake of an artificial
purity standard which has long since been violated elsewhere.
As I mentioned, I think the entire PHP curl API is unnecessarily complicated
to use, and the overloading of parameter types in curl_setopt actually
contributes to this rather than simplifying anything.
I agree that the overloading of the curl_setopt()
function is the
cause of a problem. I just disagree that allowing opt-in validation
of those types fails to solve it.
-Sara
On Fri, Apr 28, 2017 at 2:29 PM, Rowan Collins
rowan.collins@gmail.com wrote:On Fri, Apr 28, 2017 at 9:34 AM, Markus Fischer markus@fischer.name
wrote:To me the intention of strict types is clearly on the functions
publicly
visible contract, i.e. it's reflectable parameters and not some
business
logic hidden inside a function.So you feel that declare(strict_types=1); should never apply to
internal functions?I don't see that assertion implied in any of the objections on this
thread.It's implied by the statement of yours that I quoted. "To me the
intention of strict types is clearly on the functions publicly visible
contract, i.e. it's reflectable parameters and not some business logic
hidden inside a function."Internal functions do not have reflectable type hints (apart from
array and object), ergo by your criteria you feel that strict types
does not apply. Your words.
Just to clarify, I jumped into the thread to put my explanation of what I think people were objecting to. It is not my words you are quoting there, they don't speak for me, and I don't speak for them. My apologies for the confusion.
Personally, I don't think the literal fact of reflection not being available is all that relevant either way. It's certainly not the objection I was raising.
The objection is that type checking currently only occurs at function
boundaries:
I say "somewhat", because it is not unique in this
regard, many internal functions apply varying signatures based on
initial argument and/or number of arguments. See pg_*() functions for
my favorite example of this, though there are several examples in
standard as well.
Then I stand corrected. I was unaware that there were already internal functions which performed checking that couldn't be done the same way in userland; specifically, that checked more than basic signatures, but only under strict_types mode. Nor did I spot those examples in this thread, so it's possible that other people are also unaware of that precedent. But again, to be clear, it may just be me.
So, while I agree that checking the argument types for
curl_setopt()
is highly desirable,
I am sympathetic to the argument that strict_types should not alter
those checks.We disagree.
Fair enough.
That leaves us with either checking the types unconditionally (a
significantly breaking change)
or introducing a new, type-safe, API.It also leaves us with the third option of what is presented by the
PR. You do not have absolute veto.
I never claimed to have any sort of veto, I don't even have formal voting rights, I just have an opinion. What I meant was "it leaves two options which I would back right now, based on the reservations I just explained". Other people can back whatever options they like, including the fourth option of "no change", or ideas neither us have thought of.
That could mean a small but awkward set of type overloads
(setBool, setInt, etc), or a large set of named setters
(setReturnTransfer, setHeaders, etc) which could use
normal parameter hinting to interact with strict_types.Eww. Eww. And eew.
I reject the idea of making a worse API for the sake of an artificial
purity standard which has long since been violated elsewhere.
Personally, I think if we were designing from scratch, having a setHeaders method which took an array (and an associative one at that) would seem a better API than a weird polymorphic function with a manual page a mile long.
Regards,
--
Rowan Collins
[IMSoP]
I reject the idea of making a worse API for the sake of an artificial
purity standard which has long since been violated elsewhere.Personally, I think if we were designing from scratch, having a
setHeaders method which took an array (and an associative
one at that) would seem a better API than a weird polymorphic
function with a manual page a mile long.
We can agree on this, and others in this thread have said as much as
well. I've also mentioned that I've been poking at a new curl binding
since last November. Funnily enough, it's a mix of a
monolithic/polymorphic setOpt() method and where appropriate,
setSomeSpecificThing() methods.
When I get it to a stable point I'll toss it on github.
-Sara
On Fri, Apr 28, 2017 at 6:05 PM, Rowan Collins
rowan.collins@gmail.com wrote:I reject the idea of making a worse API for the sake of an artificial
purity standard which has long since been violated elsewhere.Personally, I think if we were designing from scratch, having a
setHeaders method which took an array (and an associative
one at that) would seem a better API than a weird polymorphic
function with a manual page a mile long.We can agree on this, and others in this thread have said as much as
well. I've also mentioned that I've been poking at a new curl binding
since last November. Funnily enough, it's a mix of a
monolithic/polymorphic setOpt() method and where appropriate,
setSomeSpecificThing() methods.
That mix sounds very reasonable. Does it still make you go "eww" to suggest that those settings that don't deserve their own method, and take a boolean argument rather than a string or int, could have a different method, such as setFlag? Because that's really all I was suggesting: a more visible distinction that said "this method always takes a boolean", rather than "this method must be given a boolean if given this, that, or the other".
Meanwhile, I'll repeat that if there really is precedent for functions validating their arguments based on both strict_types mode and the value of some other parameter, then my concern (mostly) evaporates, and I suspect others' might also. I just checked through the thread and RFC, and can't see these examples being named, so I would very much appreciate a specific example.
Perhaps the precedents seem obvious to you, and that's why this whole conversation is frustrating you? It definitely feels like there is some miscommunication, because you seem surprised that people have any concerns at all.
Regards,
Rowan Collins
[IMSoP]
That mix sounds very reasonable. Does it still make you go "eww" to suggest
that those settings that don't deserve their own method, and take a boolean
argument rather than a string or int, could have a different method, such as
setFlag? Because that's really all I was suggesting: a more visible
distinction that said "this method always takes a boolean", rather than
"this method must be given a boolean if given this, that, or the other".
It certainly seems unnecessary. setBool(), setInt(), setOffset(),
setString(), versus setOption() is imposing a design detail on the
consumer that shouldn't be relevant to them. In fact, in weak mode,
it becomes especially irrelevant to know the difference between an int
and a bool setting. Specifying type in the method name is essentially
imposing a cognitive form of strict mode on those who don't want it.
Meanwhile, I'll repeat that if there really is precedent for functions
validating their arguments based on both strict_types mode and the value of
some other parameter, then my concern (mostly) evaporates, and I suspect
others' might also. I just checked through the thread and RFC, and can't see
these examples being named, so I would very much appreciate a specific
example.
Not on both strict mode and the value of another parameter, there's
very little application of strict mode throughout the codebase because
strict mode is new. What there are precedents of, and what I was
responding to in your earlier email, was the idea that an arguments
type can vary based on the type and/or number of other arguments.
This precedent exists in the pg_*() methods as I already pointed you
at, and a quick grep shows stream_context_set_option()
, and a
particularly fascinating "signature" in intlcal_set()
.
Perhaps the precedents seem obvious to you, and that's why this whole
conversation is frustrating you? It definitely feels like there is some
miscommunication, because you seem surprised that people have any concerns
at all.
I'm not surprised that there are concerns, I'm just shocked that the
concerns are so poorly founded. Arguments I've heard so far fall into
two categories.
-
If the parameter isn't reflectable, then it shouldn't be subject to
enforcement.
This argument holds no water because internal functions can only
reflect array or object type hints, yet we enforce other types
routinely. -
Type enforcement should not depend on the declare(strict_types=1); directive.
This argument is ridiculous on the face of it, since that's precisely
what that declare() directive was designed for. The fact that the
type being enforced is dependent on another arg's value is an
irrelevant implementation detail. Think about the user's experience
here. Bob wants to call curl_setopt($ch, CURLOPT_RETURNTRANSFER,
$value); Bob expects $value to be validated and used as a boolean.
If Bob has strict_types set, he expects an exception if $value isn't a
bool, if it's not set, he expects the value to be quietly converted
(if possible within type affinity).
-Sara
Not on both strict mode and the value of another parameter, there's
very little application of strict mode throughout the codebase because
strict mode is new. What there are precedents of, and what I was
responding to in your earlier email, was the idea that an arguments
type can vary based on the type and/or number of other arguments.
This precedent exists in the pg_*() methods as I already pointed you
at, and a quick grep showsstream_context_set_option()
, and a
particularly fascinating "signature" inintlcal_set()
.
There is nothing wrong about having business rules inside that check
types based on another argument. The problem we are pointing out is
about those business rules making use strict types.
I'm not surprised that there are concerns, I'm just shocked that the
concerns are so poorly founded. Arguments I've heard so far fall into
two categories.
If the parameter isn't reflectable, then it shouldn't be subject to
enforcement.
This argument holds no water because internal functions can only
reflect array or object type hints, yet we enforce other types
routinely.Type enforcement should not depend on the declare(strict_types=1); directive.
This argument is ridiculous on the face of it, since that's precisely
what that declare() directive was designed for. The fact that the
type being enforced is dependent on another arg's value is an
irrelevant implementation detail. Think about the user's experience
here. Bob wants to call curl_setopt($ch, CURLOPT_RETURNTRANSFER,
$value); Bob expects $value to be validated and used as a boolean.
If Bob has strict_types set, he expects an exception if $value isn't a
bool, if it's not set, he expects the value to be quietly converted
(if possible within type affinity).-Sara
Let me be Bob, and my assumption would be completely different. I expect
that internals behave the same as userland implementations. I know that
this is not the case in every circumstance, but those where this
assumption does not hold true are meant to cover very special edge
cases, like GMP. I consider many others as being ugly hacks.
I expect strict types to affect the arguments I pass to a routine, not
more, not less. The fact that internals are not reflective is sad, we
most probably should do something about that. Regardless, this
expectation and/or assumption holds true.
In other words, I consult the docs and if the signature states an
expected type for a parameter of a routine, I expect strict types to
validate that for me, not more, not less. The docs of curl_setopt
states mixed
for $value
and that is what I expect.
This does not mean that it is not allowed to throw an exception if the
value is of another type, but it must not use strict types to determine
its mode. Simply because I cannot do the same in userland.
--
Richard "Fleshgrinder" Fussenegger
Let me be Bob, and my assumption would be completely different. I expect
that internals behave the same as userland implementations. I know that
this is not the case in every circumstance, but those where this
assumption does not hold true are meant to cover very special edge
cases, like GMP. I consider many others as being ugly hacks.
Your example of GMP can't be simply dismissed as "a special edge
case", it's precisely true that internals does not always follow the
same rules as userspace and often it breaks those rules for very good
reason.
I expect strict types to affect the arguments I pass to a routine, not
more, not less.
Agreed. And that's what this proposal suggests. If I took at your
word here, I would expect you to support this RFC.
In other words, I consult the docs and if the signature states an
expected type for a parameter of a routine, I expect strict types to
validate that for me, not more, not less. The docs ofcurl_setopt
statesmixed
for$value
and that is what I expect.
Again, you're weakening your own position. The PHP manual page for
curl_setopt()
GOES ON to state the per-option types which should be
passed for $value. I expect strict types to validate that for me, not
more, not less. The fact that you fail to read past the first line of
the manual page doesn't invalidate the function's total signature.
This does not mean that it is not allowed to throw an exception if the
value is of another type, but it must not use strict types to determine
its mode. Simply because I cannot do the same in userland.
Again, false. The fact* that something can not be done in userland
does not preclude doing it in internals. You mentioned one such case
at the start of your reply and there are plenty others.
-Sara
- Pedantically: This is not even true. Using backtraces and some
simple hacks, it's quite possible to determine the caller's
strict_types setting from userspace. But that's going off on a
tangent...
Your example of GMP can't be simply dismissed as "a special edge
case", it's precisely true that internals does not always follow the
same rules as userspace and often it breaks those rules for very good
reason.
I only said that I do not consider GMP being a dirty hack. I still think
that it is very wrong that we cannot achieve the same in userland.
Operator overloading is something I would love to see.
Again, you're weakening your own position. The PHP manual page for
curl_setopt()
GOES ON to state the per-option types which should be
passed for $value. I expect strict types to validate that for me, not
more, not less. The fact that you fail to read past the first line of
the manual page doesn't invalidate the function's total signature.
No, this is about the logic inside the function and not it's signature.
Part of the signature is everything before the opening brace. Of course
there are still some short-comings here which I hope will be resolved in
the future, e.g. union types, exceptions, generics; for those we are
required to rely on documentation, for now.
I for one am totally in favor of having dedicated methods for all
options on an option class. It makes it straight forward to discover the
possibilities that are available. The implementation is also simple with
the aid of macros. Doing that would mean that the types of the arguments
are part of the signature. Heck, the array arguments could be variadic
and thus type safe.
Again, false. The fact* that something can not be done in userland
does not preclude doing it in internals. You mentioned one such case
at the start of your reply and there are plenty others.
Of course we can do it, the question is, if we should do it. It makes
the language unpredictable at times, and that is a bad thing.
- Pedantically: This is not even true. Using backtraces and some
simple hacks, it's quite possible to determine the caller's
strict_types setting from userspace. But that's going off on a
tangent...
More dirty hacks?
I understand that we disagree, but do not try to tell me how I think
about how things should work. Your assumptions/expectations about these
things are built around the idea that strict types is a flag that
changes PHP's behavior. My idea of strict types is built around the idea
that it makes PHP behave they way other sane type safe languages work
(the word sane limits the amount of languages to compare to, Java is
definitely not part of that because of null references, but Kotlin,
Ceylon, Rust, would definitely be candidates).
--
Richard "Fleshgrinder" Fussenegger
Your example of GMP can't be simply dismissed as "a special edge
case", it's precisely true that internals does not always follow the
same rules as userspace and often it breaks those rules for very good
reason.
I think the adage applies here that you should first acknowledge rules before you break them. GMP is a special case; it is one of very few instances, if not the only instance, of overloading arithmetic operators, and IIRC that was the subject of a whole RFC. It was agreed that the use case justifies the special behaviour.
In this case, we should acknowledge that userland cannot (delta dirty backtrace hack) change behaviour based on strict types inside the body of the function, and in most cases neither sold internal functions. We can then decide if this use case merits breaking that rule or not.
Regards,
--
Rowan Collins
[IMSoP]
In this case, we should acknowledge that userland cannot
(delta dirty backtrace hack) change behaviour based on
strict types inside the body of the function, and in most
cases neither sold internal functions. We can then decide
if this use case merits breaking that rule or not.
That's a conversation I can agree needs to be had. My position should
be pretty obvious wrt curl_setopt()
, but I would actually state that
I'd go further by saying we should allow userland functions to know
if they were called strictly or not, and the reason is: Union Types.
Union Types (and intersection types and several other complex
variants) have been argued against (reasonably, I would say) on the
merit that the syntax gets ugly quite quickly and anyway, userspace
and implement the equivalent of arbitrarily complex types in the
opening body of their functions.
What such workarounds can't do, is know how much to freak out when
called incorrectly. If, as an author of a function, I want to
respect weak mode, I don't have that option currently (barring said
backtrack hacks).
I realize this is getting off-topic by venturing into a whole separate
RFC discussion, but as you point out it's a salient one when it comes
to deciding how much intelligence curl_setopt()
should apply.
Then again, I think operator overloading belongs in userspace as well,
so there's no accounting for taste.
-Sara
The fact that internals are not reflective is sad, we
most probably should do something about that.
As of PHP 7.0.0 there is ZEND_ARG_TYPE_INFO[1] which is not yet used,
though, presumably due to BC concerns.
[1]
https://php-lxr.adamharvey.name/source/xref/PHP-7.0/Zend/zend_API.h#107
--
Christoph M. Becker
Hi,
- If the parameter isn't reflectable, then it shouldn't be subject to
enforcement.
This argument holds no water because internal functions can only
reflect array or object type hints, yet we enforce other types
routinely.
I selected unfortunate words and wanted to mention reflection as an
example (in retrospect a bad and confusing one), but would I really
meant was the "user readable / visible" contract of the function
definition, as in: "you look at it and know what to expect what it accepts".
I've read through the thread and see your arguments but, to me, the fact
that this is "nested hidden" in the data structure passed to the
function still doesn't want me to have this dependent on the strict
types. I feel that strict types is misused here.
regards,
- Markus