Yeah, but what happens when the api surface of one of the modules changes? Erlang's dynamic typing, combined with its philosophy of treating crashed processes as normal, means that you can deploy the upgraded module on multiple machines without any kind of rigorous synchronization. If you want to do the same with a statically typed system you have to be able to handle the case of one module not being well typed against another. You might accomplish this by implementing transactional upgrades, but that's likely to cause a hiccup across the whole cluster, or else you could essentially define dynamically typed runtime semantics, which would lose a lot of the value of static typing.
In Cedar, or ETHZ Oberon for that matter, all executables are dynamically loaded and can be either used by other modules or exposed to the user as commands.
Loading a new version means unloading the module and its dependencies.
When it gets re-loaded it has a the new interface available.
Of course, there is the issue to solve any possible compilation errors before the module can be loaded again.
A similar approach can be done in Java and .NET via classloaders and app domains respectively.
I used to think so as well, but not any more. Any non-trivial service needs persistence, so it must checkpoint its state periodically. Also, the service is distributed to prevent a server from being a single point of failure. In this age of lightweight containers and microservices, restarting the program on an upgrade seems to me a perfectly reasonable alternative.
(does one pronounce MLFE as "milfy"?)