>stored program definitions in the same form that the programmer entered them in
>allowing the definitions to be recalled at runtime and redefined
>Some Lisps compile everything entered into them; you cannot edit a defun because it has been turned into machine language.
Ability to recall and redefine definitions at runtime, even when the language is compiled is orthogonal to homoiconicity. Ruby can do this (interpreted). Clojure too (compiled). To do so, they don't store the program as text, they store source locations (file://...:line:col) and read the files from the disk (or jar). In fact any programming language that does source-mapping and has eval() is inches away from being able to do this. This was the case for Ruby and was made possible by the pry REPL library [1]. And then there are tools like javassist [2] that allow you to edit compiled code to some extent using a limited form of the language.
Note that in the case of lisps, this is entirely orthogonal to macros (the source is passed as arguments to macros in the form of an AST/list rather than a pointer into a file), which is where homoiconicity shines. Storing code in the same format it is written in (strings) doesn't alleviate the headache of processing it when you want to do meta programming.
Additionally, macros allow you to do structured meta programming: macros are guaranteed to only impact code they enclose. Compare this with redefinitions that are visible to the whole code base. This is like global vs local variables: macros don't redefine code, they transform it.
>allowing the definitions to be recalled at runtime and redefined
>Some Lisps compile everything entered into them; you cannot edit a defun because it has been turned into machine language.
Ability to recall and redefine definitions at runtime, even when the language is compiled is orthogonal to homoiconicity. Ruby can do this (interpreted). Clojure too (compiled). To do so, they don't store the program as text, they store source locations (file://...:line:col) and read the files from the disk (or jar). In fact any programming language that does source-mapping and has eval() is inches away from being able to do this. This was the case for Ruby and was made possible by the pry REPL library [1]. And then there are tools like javassist [2] that allow you to edit compiled code to some extent using a limited form of the language.
Note that in the case of lisps, this is entirely orthogonal to macros (the source is passed as arguments to macros in the form of an AST/list rather than a pointer into a file), which is where homoiconicity shines. Storing code in the same format it is written in (strings) doesn't alleviate the headache of processing it when you want to do meta programming.
Additionally, macros allow you to do structured meta programming: macros are guaranteed to only impact code they enclose. Compare this with redefinitions that are visible to the whole code base. This is like global vs local variables: macros don't redefine code, they transform it.
[1] https://github.com/pry/pry#edit-methods
[2] https://www.javassist.org/tutorial/tutorial2.html#before