Re: [RFC] Scalar Type Hints
| From: | Marco Pivetta | 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/