#Smalltalk and other #ImageBased #ComputerLanguages have a reputation for making software developed in them hard to upgrade. As far as I know, this has never been satisfactorily solved.

#Erlang, on the other hand, lets you upgrade modules "live", though they need to be made for it.

The persistent #LPMud implementation #DGD had hot code reloading built in: IIRC if you upgraded a class there was a command you could call to upgrade each instance of that class to use the new code.

I think the #DGD approach is probably pretty close to the "right way" to handle upgrade in a persistent system. While #DGD used external files, there's no reason that "modules" or "classes" couldn't be built into the language/environment (which should be the same), along with versioning that can be atomic at various levels of the hierarchy to handle interdependencies.
With such a system, modules or classes would always be specified along with their version (and possibly even a hash) when instantiating them or deserializing state. There would be an explicit upgrade operation for getting from a serialized state from an older version to a newer version. This could involve following a path through upgrade functions in the new version, or instantiating older versions assuming they're not blocked due to security vulnerabilities or bad bugs.
@seanl #CL #commonlisp lets you update live code also.
@Nixfreak The live update is the easy part. It's updating state and dealing with multiple versions running at the same time that's hard.
@Nixfreak A Python messaging server we used at Linden Lab had live update too, but it was just replacing the module, so it relied on the module's either being stateless or explicitly dealing with any leftover state from the old module.

@Nixfreak In #Erlang, the thing you're live-updating is often the module underlying a process, so updating the state is mandatory. Upgrade is implemented by the built-in behaviors IIRC, so you couldn't just live-upgrade *any* process.

In #lpmud you'd be upgrading classes, which are in many ways like Erlang processes, but IIRC you don't deal with state as explicitly and there was no concept of version, so you'd better only jump one version at a time.

@seanl In #Gemstone #Smalltalk, you can load new code to the running service and then migrate class instances (in transaction, of course) with no problem.
@petr_fischer What's the API look like on the class side for upgrading instance state? Do you implement a method that gets passed the old instance and has access to its internals or something?
@seanl Every object can have instance side method migrateFrom: oldObject... you can migrate inst vars (model changes) in this method. Classes has "runtime" versions. Old class versions can coexist with new class versions, you can only migrate the instances you want Everything is flexible.