S-expressions are a nice gimmick, but it’s not the fundamental reason why some Lisps support dynamic patching of code at runtime. Indeed you can easily imagine Lisp written in M-expressions and still support that. Or you can imagine other dynamic languages with reflection gaining this capability with a bit of will, like… check notes… Python.
S-expressions make the user interface to code generation, a component to hot-reloading, more facile. It's not a triviality or gimmick in this context.
We can see from OP that it's actually quite annoying to specify code in a non-S-expression language (or really any language lacking a meta-syntax), usually requiring either
- stuffing and interpolating strings
- building ASTs with API functions provided by the implementation in a tiresome or verbose manner
But you're right that there are more aspects to hot-reloading than just the syntax and data structure.
Common Lisp gets away with it because it actually defines the semantics of redefinition of functions and classes. For instance, the standard says what will happen to all existing FOO object instances in memory if I change
to and even lets the programmer customize the behavior of such a redefinition.Few if any languages go through the trouble of actually defining these semantics, especially in the context of a compiled language (like Common Lisp), making all but the simplest instances of reloading code well defined.