FAQ

On 2 January 2015 at 14:00, Andrea Faulds wrote:

Hi Marco,
On 2 Jan 2015, at 09:16, Marco Pivetta wrote:


I'm not sure why everyone is still taking the PHP manual as a good
reference about how to write software: PHP internal functions are one of
the main reason why this language is under-appreciated.
The manual is pulling the concepts of `int`, `string` and so on out of
thin air, whereas the correct syntax in those cases is
`int|string|Stringable`, with explicit explanation of what those strings
should look like.

I don’t see why the manual is wrong. Yes, in a strictly-typed language
which allows no conversion of arguments, foobar(int $foo) wouldn’t have the
behaviour PHP exhibits. Yet PHP is not a strictly-typed language, and
weakly-typed parameters are hardly a novel concept. The language that PHP
is implemented in, C, also has this. And yet, C does not have this:
void foobar(char|unsigned char|short|unsigned short|int|unsigned
int|long|unsigned long|long long|unsigned long
long|float|double|_Bool|void* foo)

Why? Because in C, implicit conversions between parameter types are
permitted. PHP has the same thing for its internal/extension functions. The
manual isn’t wrong.
The manual is wrong since it specifies a strict hint for something that is
`mixed`. It is still useful tho, since it's telling us "it accepts"
integer-ish values there. It's purely for documentation purposes though, it
is by far dictating the actual implementation.

This is constraining. Constraining has nothing to do with validation and
casting: mixing the concepts of type-juggling, validation and constraining
is a huge mess (which I don't like, but it's better than having nothing),
and it would better be off using a syntax like:

Argument types do not necessarily exist purely to error on invalid input.
They also exist for documentation purposes and, in languages like C,
implicit conversion.
No, argument types exist to prevent mistakes: they prevent invalid values
to cross validation boundaries of the application. Documentation purposes
are purely secondary, we already have phpdoc for that.

public function __construct(ProductId $productId, (int) $amount)

This makes the difference **much more clear**, as that `(int)` is not a
constraint, it's a different, broader concept.

I don’t think the cast-like syntax is a particularly good idea. It’s
inconsistent with our manual conventions (then again, many other things
are).

Again with the manual (*sigh*): the manual comes AFTER the code has been
written.

It’s misleading, as well: we don’t do an explicit cast. If it was an
explicit cast, literally any value would be accepted.

Agree on that, then give it a different name and/or syntax, but it's not a
constraint then.

But that’s not the case at all, the weakly-typed parameters that extension
functions have do not accept any value. Instead, they accept the desired
type, and a limited range of convertible values of other scalar types.
~int ~float and ~string are fine as well here IMO, if you think that (int)
(float) and (string) are misleading.

Additionally, the BC break concern of strict type-hinting and classes
named `String`, `Int` and `Bool` (and similars) is delayed until we get
strict type-hints, as the syntax is currently not allowed by the language
and doesn't present any BC issues (http://3v4l.org/3Fqdh):

I’d rather not delay it. We probably should have reserved syntax for
scalar hints ages ago.
It was just a plus for getting it done to move over to actual type
specifications :-) Introducing a BC break always increases the likeliness
of a change being accepted by a huge lot.

@Andrea: as for the "strict" and "non-strict" PHP suggestion you had
before, please don't do that. Take following example:
function repeat(int $amount, (string) $value) {
$acc = '';
$i = 0;

while ($i < $amount) {
$i += 1;
$acc .= $value;
}

return $acc;
}

As you can see, mixing implicit cast and strict constraining behaviors
is perfectly fine in this case, so please don't include contextual
switches: that would be even worse IMO.

I don’t understand why that particular example makes sense. Since it’s
producing a string value, surely $value should always be a string?

The difference is that $amount must always be an integer (not integer-ish)
value, whereas $value must be a stringable value, and the cast would happen
at call-time, not at every loop (very relevant for instances of classes
implementing `__toString()`, as the call happens only once).

I really don’t like the idea of mixing strong- and weakly-typed
parameters. We should be consistent. Otherwise, we are imposing too high a
mental burden on programmers, who will now need to remember which
parameters are strongly-typed and which parameters are weakly-typed.
I think the example I just gave you is very consistent, explicit and easy
to understand. Additionally, I don't see any particular mental burden
except for having to know that $value will be cast to a string if it isn't.

If there is any mental burden, it's mainly introduced by the proposed RFC,
whereas strict checking would remove any doubts about what $value can be.

Marco Pivetta

http://twitter.com/Ocramius

http://ocramius.github.com/

Search Discussions

Discussion Posts

Previous

Follow ups

Related Discussions

People

Translate

site design / logo © 2019 Grokbase