Stas, On Sun, Feb 22, 2015 at 6:47 PM, Stanislav Malyshev <smalys...@gmail.com> wrote: > Hi! > >> You can tell because you know the function foo expects an integer. So >> you can infer that $x will have to have the type integer due to the >> future requirement. Which means the expression "$something / 2" must >> also be an integer. We know that's not the case, so we can raise an >> error here. > > OK, so your claim is that the compiler with strict typing can detect > some situations which the dynamic one can not and reject some of the > code. Without going too much into details, I agree with this, this is an > obvious difference between strict and dynamic. However, this is not a
Alright, we're getting somewhere. > performance advantage, obviously - since you are comparing running code > with non-running one - your model just accepts less code. Obviously, > this works if non-accepted code was wrong - and doesn't work if it was > not. But we talked about running code, I thought. It is still a performance advantage, because since we know the types are stable at compile time, we can generate far more optimized code (no variant types, native function calls, etc). And yes, it accepts less code. It refuses to accept code that is not type stable. More on that in a second: >> At that point the developer has the choice to explicitly cast or put >> in a floor() or one of a number of options. > > That's exactly what I claim would be the defect of the strict model - > people would start putting excessive casts ensuring there would be cases > where information is lost. For example, assume we knew $something is even: > > function bar(int $something): int { > assert($something %2 == 0); > $x = $something / 2; > return foo($x); > } > > Now everything is fine (ignoring the typing for a second), right? We're > dealing with integers, /2 always divides evenly, all is great. Now we > introduce strictness, so we'd need to say something like: > > function bar(int $something): int { > assert($something %2 == 0); > $x = $something / 2; > return foo((int)$x); > } > > Now assume somebody messed up on the routine code reformatting merge and > the code somehow ended up like: > > function bar(int $something): int { > $x = $something / 2; > return foo((int)$x); > } > > Do you see what the problem is? Now we lost the check for $something > being even, but we would never know about it since type system forced us > to insert (int) (which we didn't need) and thus disabled the controls > for the bug of $something not being even (which we did need). Actually, in this case, the int cast does tell us something. It says that the result (truncation) is explicitly wanted. Not to the compiler (tho that happens), but to the developer. With coercive typing as proposed in Ze'ev's RFC, that would need to happen anyway. In both proposals that would generate a runtime error. The difference is, with strict types, we can detect the error ahead of time and warn about it. > But more important question is - with (int) the coercive model can use > this information too, so what's the difference from strict model on that > code? There seems to be none. In this precise example there is none, because division is not type stable (it depends on the values of its arguments). Let's take a different example function foo(float $something): int { return $something + 0.5; } With coercive types, you can't tell ahead of time if that will error or not. With static types, you can. >> Without strict typing this code is always stable, but you still need >> to generate full type assertions in a compiled version of foo() and >> use ZVALs for $x, hence reducing the effect of the optimization >> significantly. > > Wait, you said "this code is invalid" so no code will be generated. Did > you mean code after introducing (int)? Then strict has no advantage > anymore as we can derive the info from (int) anyway. > Otherwise, I can't see how you can avoid generating typechecks in foo() > unless the only place it can ever be called from is bar() - but I don't > see how you can ensure that in PHP, and if you could, I don't see why > weak model could not make the same conclusions on the same code. No, I was talking about trying to do the same trick (using native function calls) with coercive types. > So far the only "advantage" I've seen seems to be that your compiler > would reject code that looks suspicious to it and thus force the > programmer to coerce the variables into the types manually - by (int) or > floor() - something that the coercive model would do for you > automatically. Once coerced, the same code would have the same type info Actually, no. Coercive as proposed by Ze'ev would cause 8.5 to error if passed to an int type hint. So you'd need the cast there as well. Either that, or error at runtime as well. Hence, in both cases casts would be required. One could tell you ahead of time where you forgot a cast, the other would wait until runtime (when the edge-case was hit). > (and thus same potential optimizations) in both models. I don't think it > is a gain in general, and I don't think forcing people to modify their > code qualifies as "JIT performance gain". Sure it does. If their code is not type-stable, even simply telling them that can give advantages both in performance and in correctness. Their code is buggy today. All the static type system does is show it to them ahead of time, rather than relying on test failures or bugs to show it. And to be fair I haven't really been talking generic JIT, but generic AOT (which can include local-JIT compilation). Anthony -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php