If g returns an x and f takes an x, I can do f(g()) without knowing anything else about type x. Even type inference will choose an x that makes g compatible with f, or complain if there isn't any. So the system is still modular at the source level, which is important because it keeps the project comprehensible. What you don't have is binary-level modularity, but that's just an efficiency hack that dates back to when computers were almost too slow to run compilers. Now it should only matter to people who obfuscate by refusing to ship source (or source-equivalent intermediate files, which at least one Ada and one C++ implementation used to handle separate compilation of polymorphic code) and living with the lack of whole-program optimization.