Okay, well "What about homoiconicity?" you say? Well, I think it's a totally cool sounding word that all hipster programmers need to have ready to pull out, but it isn't a game changer for Lisp. Or I should say, that yes it has kept Lisp in the game, because without it Lisp would be like FORTRAN IV, a language that didn't have enough useful stuff (fixed size arrays of numbers was pretty much all there was to program with in early FORTRAN), but it doesn't make Lisp "better" than more modern languages.
Homoiconicity means that the the abstract syntax of the language can be represented easily in the programming language itself. Just the fact that Python is written in text and can easily represent and manipulate text doesn't count. Because of homoiconicity Lisp can do amazing things to itself, see [1] and [2]. Python programs aren't commonly producing another python program to feed to the python interpreter.
However, Python makes the the AST available as a python construct. Go does something similar. So yes, python and go could support the Metaobject protocol if they wanted to. The important thing observation is that Python and Go programmers don't want to and don't need to. These languages already provide powerful enough abstractions to support 99% of a programmer's needs: object, classes, interfaces, lambdas and so forth.
"Well, yeah, but ithout homoiconicity how do you construct a good DSL?" I presume that you mean how can you implement something like CLOS? Really? I don't want to implement CLOS and I also don't want to write the Boost library for C++. Both are complex exercises in programming to extend the capabilities of the underlying language. Why wallow in macros (again see [2]) or templates (see Boost source)? I understand that C++ templates solve an essential problem that the language has: original compatibility with C and a desire to be able to operate as close to the metal as C. Likewise, Lisp originally lacked even a decent set of control constructs. High powered macros (and call/cc for Scheme) allowed the languages to build there own extensions just as templates have for C++.
Other language just start with a good set of abstractions, control abstractions (like Java's enhanced for loop), data abstractions like interfaces, concurrency abstractions like go's channels.
"Yeah, well like man, how can you anticipate exactly what the program needs?". Well, I've found higher level programming with functional languages and object oriented languages to provide almost all my needs.
"Well, DSLs make programming so obvious. You end up programming so much closer to the problem domain?" Yes, that's true. I find that DSL's and even macros helpful in configuration files, for example in a 3000 line Emacs configuration file. I use John Wiggle's use-package macro extensively to simplify my Emacs init.el file. My problems with macros as a fundamental organizational abstraction for programming-in-the-large are worth a separate post (it has to do with hidden semantics and the difficulty in even informally reasoning about the correctness of programs written using macros).
Homoiconicity means that the the abstract syntax of the language can be represented easily in the programming language itself. Just the fact that Python is written in text and can easily represent and manipulate text doesn't count. Because of homoiconicity Lisp can do amazing things to itself, see [1] and [2]. Python programs aren't commonly producing another python program to feed to the python interpreter.
However, Python makes the the AST available as a python construct. Go does something similar. So yes, python and go could support the Metaobject protocol if they wanted to. The important thing observation is that Python and Go programmers don't want to and don't need to. These languages already provide powerful enough abstractions to support 99% of a programmer's needs: object, classes, interfaces, lambdas and so forth.
"Well, yeah, but ithout homoiconicity how do you construct a good DSL?" I presume that you mean how can you implement something like CLOS? Really? I don't want to implement CLOS and I also don't want to write the Boost library for C++. Both are complex exercises in programming to extend the capabilities of the underlying language. Why wallow in macros (again see [2]) or templates (see Boost source)? I understand that C++ templates solve an essential problem that the language has: original compatibility with C and a desire to be able to operate as close to the metal as C. Likewise, Lisp originally lacked even a decent set of control constructs. High powered macros (and call/cc for Scheme) allowed the languages to build there own extensions just as templates have for C++.
Other language just start with a good set of abstractions, control abstractions (like Java's enhanced for loop), data abstractions like interfaces, concurrency abstractions like go's channels.
"Yeah, well like man, how can you anticipate exactly what the program needs?". Well, I've found higher level programming with functional languages and object oriented languages to provide almost all my needs.
"Well, DSLs make programming so obvious. You end up programming so much closer to the problem domain?" Yes, that's true. I find that DSL's and even macros helpful in configuration files, for example in a 3000 line Emacs configuration file. I use John Wiggle's use-package macro extensively to simplify my Emacs init.el file. My problems with macros as a fundamental organizational abstraction for programming-in-the-large are worth a separate post (it has to do with hidden semantics and the difficulty in even informally reasoning about the correctness of programs written using macros).
[1] https://en.wikipedia.org/wiki/The_Art_of_the_Metaobject_Prot...
[2] http://letoverlambda.com