I found that book a little disappointing. Some other books focus on macros and metaprogramming techniques that are unique to LISP (say Graham's "On LISP"), but despite all the differences between CLOS and Python all I could see was "look, I can draw a line between this function in the metaobject protocol and that function in the Python implementation of objects and get something very close to an isomorphism".
"Meta objects" are significant in many areas of programming where you embed objects from system A inside system B (as opposed to translate native A objects into native B objects). This ranges from "script a Java object in Python" to systems like COM and CORBA as well as UML, MOF, object-relational and object-MOF mappers, etc. Alternative "meta object" systems can expand the capabilities of a single object system.
I'm not sure if anything really good has been written about that topic, I think people aren't so interested in "objects in general" today but alternately we have had 30+ years experience with real-life object systems that can be consolidated.
I think the problem with explaining the MOP is that it really only pays off with systems that are big enough and complicated enough that you really can't use them as examples in a book. You can provide contrived examples but then some readers just nitpick on how contrived they are.
I feel compelled to note that I was cribbing my observation from a similar one made by Guy Steele, who ran into similar trouble finding a non-trivial example to justify the necessity of tail calls in an object oriented language [1]:
> (someone's criticism): The objection to TCO that you're trying to answer is that it's rarely helpful in the real world. So you have to find real-world examples to refute that. An impractically-slow set isn't a real-world example.
> (GLS response): I wish I could fit a real-world example onto a blog page. The best I can do is to exhibit a "toy" example that illustrates the basic idea.
I mean, the systems described in the TAotMOP, and CLOS, are early implementations of multiple dispatch, which is the core paradigm of the Julia language.
Julia doesn't go quite as far as implementing a MOP. It doesn't allow for the arbitrary modification of the semantics of evaluation in the language itself, but I'll bet it'd be pretty easy to write a MOP on top of the base language.
I think the ideas in the MOP are exactly those that you've identified in the first sentence. You can draw lines that allow you compare the object implementations of particular programming languages. This isn't so useful when you're just working in a single language, but in something like CL or Scheme (or Racket more specifically) where a major design strategy is to design a DSL that suits your problem, having a MOP really lets you tailor that DSL to the problem in ways you might have a hard time doing otherwise.
For example, I once wrote a library for a computing in particular area of mathematics, but I also wanted to see some symbolic equations. I just changed the basic evaluation semantics of my numeric operators to operate on symbols as well as numbers and to run some simplification logic and boom. I had a rough view of the equations that were actually being used to compute that I could use to debug or tidy up and write down.
> For example, I once wrote a library for a computing in particular area of mathematics, but I also wanted to see some symbolic equations. I just changed the basic evaluation semantics of my numeric operators to operate on symbols as well as numbers and to run some simplification logic and boom.
This is very much something I find fascinating (and a reason I’m quite excited by Julia). Can you point me to any examples where you feel this has been tastefully done? (yours or otherwise)
Well I did it in Scheme, but there's no reason it wouldn't have worked in Julia. If you're interested in this, the relatively recent Software Design for Flexibility by Chris Hanson and GJS [1] has a pretty good couple of chapters on creating a generic procedure system (and a lot of other really cool things). Edit: In fact, it has an example doing just this example: symbolic alternative evaluation. Where they get the closed form solution from a simple differential equation solver without changing any code in the solver.
Now that I think about it, this idea is pretty much how automatic differentiation works in Julia. (Really everything in Julia.) You can look at the libraries Flux.jl and Zygote.jl. There are probably more now, I've been out of the Julia ecosystem for about a year or so.
> look, I can draw a line between this function in the metaobject protocol and that function in the Python implementation of objects and get something very close to an isomorphism
The book (1991) and the CLOS MOP (1987/88) itself are now quite old and other languages had (Smalltalk) and have (Python) something similar.
"Meta objects" are significant in many areas of programming where you embed objects from system A inside system B (as opposed to translate native A objects into native B objects). This ranges from "script a Java object in Python" to systems like COM and CORBA as well as UML, MOF, object-relational and object-MOF mappers, etc. Alternative "meta object" systems can expand the capabilities of a single object system.
I'm not sure if anything really good has been written about that topic, I think people aren't so interested in "objects in general" today but alternately we have had 30+ years experience with real-life object systems that can be consolidated.