It's because when you have higher-order functions (functions that can take other functions as parameters, or return other functions) then having the type after the variable makes your type declarations read left to right instead of in a weird spiral.
Consider this example from an excellent blog about why golang went this route:
int (*fp)(int (*ff)(int x, int y), int b)
It's pretty difficult to tell what's a return type and what's an argument, and you need parentheses to disambiguate a lot of that. It's a major reason why people avoid function pointers like the plague in C. With the type at the end, that ambiguity is removed without parentheses.
As amon pointed out, recent C-family languages do this more like:
std::function<int(std::function<int(int x, int y)> ff, int b)> fp
Yes, the ambiguity is removed here as well, but it was for the C example too. We have just chosen a different set of delimiters (the std::function<>) to disambiguate. We still have a special syntax for declaring function pointers that's outside of the regular type declaration syntax. We no longer read in a spiral, which is a vast improvement, but we haven't even added generics into the mix and we already have a pretty long and busy type signature.
Compare with the postfix type signature for a function declaration:
def f(ff: (Int, Int) => Int, b: Int): Int
This reads very cleanly, from left to right. I can scan down the left side of the page and easily find my function names. It's easy to parse, because you already have a declaration, you just add an optional
: type signature at the end. Declaring a variable holding a reference to this function is nearly identical:
val fp: (ff: (Int, Int) => Int, Int) => Int = f
// although usually because of type inference you can just write:
val fp = f
We are also using a colon here as a delimiter to resolve the ambiguity, but the delimiter on the other side was already there, either the comma or the closing paren or whatever token, so it is much less obtrusive. This is simply not possible with type-first. You have to surround the function declaration, one way or another.
When you use higher-order functions all the time, every bit of added readability helps. That's why languages that intend to idiomatically support higher-order functions at some point use type-last syntax from the beginning.