How can a static analysis tool keep up with a language that’s being arbitrarily extended at runtime? The prospect is daunting.
I don't really understand that point. In Racket, for example, programs macro-expand down to a very small set of primitives, such as `let-values` and `lambda`. This makes it easier to do analysis, not harder. For example, this is how something like Typed Racket can support every idiom in untyped Racket programs -- because they all expand down to a fairly manageable core set of forms. (Or if you need to analyze something no-so-primtive, you can stop expansion on whatever that is.)
Racket is descended from Scheme. I don't know if CL or Clojure expand down to quite such a small primitive core, but I imagine the story is roughly similar?
Anyway, writing such tools is not what the average programmer would do on a putative large project.
Any large project needs technical and social norms, mentoring, and leadership -- regardless of language. I think the language is the smallest part of it. Perhaps like how in security it's social not technical engineering that usually turns out to be the weakest link.
Furthermore: Lisps tend to prefer staged metaprogramming (eg. macros) over dynamic metaprogramming eg. python's __whatever__, Ruby's method_missing, and JavaScript's obj[foo + bar](). I'd much rather debug static metaprogramming techniques over dynamic ones any day of the week.
The fact is that Clojure/etc is much easier to analyze statically than the popular everything-is-a-dictionary scripting languages. That should be obvious given that the reference implementation is a compiler, not an interpreter. But stuff like Typed Racket and Typed Clojure should eliminate any remaining doubt.
and more importantly macros are expanded at compile time, not runtime, so static analysis is still possible, and this makes that statement a bit wrong.
And to drive your point home, Haskell code "expands" into System F. Macros in lisp do the same kind of transformation (AST rewrites), they just get to skip parsing.
I don't think the author understands that these things happen at different times. Especially because they said "at runtime" when macros expand much before that.
On the contrary, something like Rails is what I'd call extending the language arbitrarily at runtime. So the very lack of macros is what motivates shaky transformations at runtime.
Comments
I don't really understand that point. In Racket, for example, programs macro-expand down to a very small set of primitives, such as `let-values` and `lambda`. This makes it easier to do analysis, not harder. For example, this is how something like Typed Racket can support every idiom in untyped Racket programs -- because they all expand down to a fairly manageable core set of forms. (Or if you need to analyze something no-so-primtive, you can stop expansion on whatever that is.)
Racket is descended from Scheme. I don't know if CL or Clojure expand down to quite such a small primitive core, but I imagine the story is roughly similar?
Anyway, writing such tools is not what the average programmer would do on a putative large project.
Any large project needs technical and social norms, mentoring, and leadership -- regardless of language. I think the language is the smallest part of it. Perhaps like how in security it's social not technical engineering that usually turns out to be the weakest link.
Furthermore: Lisps tend to prefer staged metaprogramming (eg. macros) over dynamic metaprogramming eg. python's __whatever__, Ruby's method_missing, and JavaScript's obj[foo + bar](). I'd much rather debug static metaprogramming techniques over dynamic ones any day of the week.
The fact is that Clojure/etc is much easier to analyze statically than the popular everything-is-a-dictionary scripting languages. That should be obvious given that the reference implementation is a compiler, not an interpreter. But stuff like Typed Racket and Typed Clojure should eliminate any remaining doubt.
and more importantly macros are expanded at compile time, not runtime, so static analysis is still possible, and this makes that statement a bit wrong.
And to drive your point home, Haskell code "expands" into System F. Macros in lisp do the same kind of transformation (AST rewrites), they just get to skip parsing.
I don't think the author understands that these things happen at different times. Especially because they said "at runtime" when macros expand much before that.
On the contrary, something like Rails is what I'd call extending the language arbitrarily at runtime. So the very lack of macros is what motivates shaky transformations at runtime.