Skip to content

Instantly share code, notes, and snippets.

@ircmaxell
Created July 14, 2014 16:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ircmaxell/7a94d7e3da979dadf5cc to your computer and use it in GitHub Desktop.
Save ircmaxell/7a94d7e3da979dadf5cc to your computer and use it in GitHub Desktop.
internals_reply

Zeev,

Actually there's a pretty simple way that's not strict type hints:

  1. Add type hints using existing syntax, which are casts; Change casts (both existing and these new ones) to emit a new E_CAST in case of data loss or 'bogus' conversions.

The only issue with this, is that it changes how your calling code will behave based on global configuration. Not an issue for the application developer, but for a library developer who makes reusable code, this is going to become a nightmare to deal with.

Example:

function foo(int $bar) {}
foo("12abc"); // May silently succeed. May raise E_CAST error. May throw exception. Who knows!

That sounds like it's not a big deal, but it will result in calling code needing to get extra defensive to be robust:

foo((int) $something);

Which is exactly what this RFC was designed to avoid. Explicit casts can be lossy, because it's clear that the programmers intention is for the loss to occur. So (bool) array(123) is a valid cast, because it's explicit. But implicitly, it's really not clear if that's what was intended or not.

Strict hints are dangerous in the context of PHP because PHP's types can change in unpredictable ways. A variable that was an integer can turn into a float through seemingly integer operations. So if the foo hint above was strict, foo($intVar + 1) could result in an error, due to $intVar+1 possibly becoming a float (example: when adding 1 to PHP_INT_MAX).

That would again result in (int) casts being used, which would then hide the real error cases, such as passing "apple" to a function expecting an integer...

These cast rules differ from the existing cast rules for a very significant and important reason: they are implicit. If the user wants to force something, they still have the normal cast mechanism to do that. These cast rules are designed so that reflexive (lossless) casts are free ("12" is 12), but lossly casts need intervention by the user to confirm intent.

The edges are where things get odd. "12abc" is currently accepted by zpp int types, but raises a notice. That was why the RFC initially included it as a notice. But I agree with the move to making it an outright error.

But then you get problem areas like booleans. On one hand, "foo" doesn't make sense, but on the other $flags & FLAG does. But that could just as well be a string. So either we let everything satisfy a boolean (how ZPP already works) or we restrict it to lossless casts, or we make it strict. None of them are really overly good IMHO, but it's something that should be discussed...

I already mentioned before that I don't think consistency is a bad thing (and that's an understatement). Having the syntax differ and have a separate, similar set of rules/behaviors is a disadvantage, not an advantage in my book.

Well, there is consistency. For the most part (around 95% of this RFC), ZPP behaves the same way as this RFC is proposing. And I'd argue that if this RFC is accepted, ZPP should be modified to behave like this (for PHP_NEXT). The reason is that the rules for these implicit casts are actually quite simple, with a few edge cases (which is where the divergence from zpp happened).

There are several advantages of adding this syntax with the simple casting behavior:

  1. It saves a bit of code and improves readability for a very common use case.
  2. It encourages developers to get the types straight instead of relying on implicit casts.

Implicit casts are good, when it's not clear what the programmer intended. And simply passing a variable to a function doesn't indicate intent as we don't have typed variables. So having implicit casts be "safer" is a good thing, as there's always an explicit cast if they need it. And if it's not clear, I'd prefer having the implicit cast error, and let the programmer use an explicit cast to clarify intent.

My $0.02

Anthony

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment