Re: [RFC] Scalar Type Hints

From: Date: Fri, 02 Jan 2015 09:16:17 +0000
Subject: Re: [RFC] Scalar Type Hints
References: 1 2 3 4 5  Groups: php.internals 
Request: Send a blank email to internals+get-80086@lists.php.net to get a copy of this message
On 2 January 2015 at 01:01, Stanislav Malyshev <smalyshev@gmail.com> wrote: > Hi! > > > The problem is that the current proposed hints/casts are deviating from > the > > type-hints that we are used to, therefore this particular feature should > > Let's check the manual we're used to. > http://php.net/manual/en/function.substr.php > > string substr ( string $string , int $start [, int $length ] ) > > What "string" and "int" mean there? How they work? What we're > "deviating" from? 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. This is what you currently do in a real-world scenario (due to the lack of hints for internal types): class Shipment { public function __construct(ProductId $productId, $amount) { if (! is_int($amount)) { throw new InvalidArgumentException(sprintf('Provided $amount must be integer, %s given', gettype($amount))); } $this->productId = $productId; $this->amount = $amount; } } No allowance of weird values passed in: why would my software ever pass an invalid $amount to my constructor? That's where I'd put a hard-failing assertion instead. This is what I'd like it to be: class Shipment { public function __construct(ProductId $productId, int $amount) { $this->productId = $productId; $this->amount = $amount; } } Following code MUST cause a hard failure: new Shipment($bananasId, '1 of a whole lot'); 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: class Shipment { public function __construct(ProductId $productId, (int) $amount) { $this->productId = $productId; $this->amount = $amount; } } This makes the difference **much more clear**, as that (int) is not a constraint, it's a different, broader concept. I'd rather have the new behavior suggested by Andrea with a syntax that makes this subtle yet gigantic difference explicit. 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): function sum((float) $a, (float) $b) { } From an implementation perspective, it should just be a parser change. @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. Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/

« previous php.internals (#80086) next »