Disclaimer: I use the word "type" in the following to refer to types, tags and classes, because I'm feeling lazy ;)

> Return Type Declarations & Scalar Type Hints

This seems a shame.

We can only add type hints to arguments and return types if we're writing arguments and return values, which is unnecessarily verbose. We should really add these types to the functions themselves. For example:

$dbl = function(int $x) : int { return 2 * $x; };
$neg = function(int $x) : int { return -1 * $x; };

We've given types to the inputs and outputs, but the functions themselves still just have the type 'Closure'; there's no indication about what they accept or return. Functions are meant to abstract, but this implementation of type hinting forces us to go and read the implementation!

For example, if we've written the following and we want to add types (where I've put "???"), we need to look at the implementations of $dbl and $neg:

$dblneg = function(??? $x) : ??? { return $dbl($neg($x)); };

We could implement the same functions in a different way:

$mult = function(int $x) : Closure {
return function(int $y) : int use ($x) {
return $x * $y;
};
};
$dbl = $mult(2);
$neg = $mult(-1);

Now if we want to add types to $dblneg, the implementations of $dbl and $neg don't help; we have to dig even further and read the implementation of $mult.

All of this would go away if we could hint the function instead, eg.

$mult = function($x) : Closure(int, Closure(int, int)) {
return function($y) use ($x) : Closure(int, int) {
return $x + $y;
};
};
$dbl = $mult(2);
$neg = $mult(-1);

Here I've used the ": ???" syntax to hint the whole function rather than just its return value, and I've written "Closure(x, y)" to mean a function type from argument type "x" to return type "y". This means if we have a function, like $dbl, we can query its type in the usual way (`typeof $dbl`) and get the argument and return types without having to read any source.

Note that this doesn't require generics/parametric-polymorphism, since all of the types I've used are concrete. However, adding that would be the next logical step ;)

Note that we can trivially extend this scheme to functions with multiple arguments, in all of the various, incompatible ways PHP lets us define them:

function add($x, $y) : Closure(int, int, int) {
return $x + $y;
}

$add = function($x, $y) : Closure(int, int, int) {
return $x + $y;
};

static function add($x, $y) : Closure(int, int, int) {
return $x + $y;
}

public function add($y) : Closure(int, int, int) {
$this + $y;
}

function add($x) : Closure(int, Closure(int, int)) {
return function($y) use ($x) : Closure(int, int) {
return $x + $y;
};
}

function add($args) : Closure(array(int, int), int) {
return $args[0] + $args[1];
}

$add = function($args) : Closure(array(int, int), int) {
return $args[0] + $args[1];
}

static function add($x) : Closure(int, Closure(int, int)) {
return function($y) use ($x) : Closure(int, int) {
return $x + $y;
};
}

function add() : Closure(int, int, int) {
return func_get_args()[0] + func_get_args()[1];
}

function add() : Closure(array(int, int), int) {
return func_get_args()[0][0] + func_get_args()[0][1];
}

// and so on

This seems to me like another case of PHP ignoring decades of programming language research and development and instead just "doing it like <popular language from the 1970s> does it". It's like generators all over again :( (eg. see http://okmij.org/ftp/continuations/generators.html and http://parametricity.net/dropbox/yield.subc.pdf )