On 2 January 2015 at 14:00, Andrea Faulds <a...@ajf.me> wrote: > Hi Marco, > > > On 2 Jan 2015, at 09:16, Marco Pivetta <ocram...@gmail.com> 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/