Hacker News new | past | comments | ask | show | jobs | submit login

Well, the funny thing is that for base Common Lisp, it's less dynamic than you think.

The functions and symbols in the core packages (e.g. COMMON-LISP package) are considered fixed and immutable. For example, out of the box, the compiler can assume that things like '+' aren't going to be redefined behind its back. It's assumptions like that can lead to very efficient code. But, at the same time, the core lisp language is actually not very dynamic, its more like your typical, compiled language in that sense.

In contrast to say, Scheme, which has no presumptions. Out of the box, naive Scheme compilers can not make such assumptions. So, if you have something like:

    (set! a (+ x (- y (+ z w))))
The compiler actually has to look up (dispatch) '+' twice! Did '-' change the definition of '+'? Maybe...you don't know. So you can't (again naively) inline anything (not even counting the issues with numeric tower and types of the variables). So, what would ideally be a couple of simple machine instructions turns in to a huge endeavor.



It is true that in Scheme you can shadow built-ins if you want, but a compiler would have to be extremely naive, perhaps lacking support for macros entirely, to not recognize primitive `+` from a user defined `+`. One of the very first transformations applied to the user program would be alpha conversion, where all user defined variables are replaced with program-unique names. At that point, the compiler would be absolutely sure that `+` is the primitive addition operator and compile it directly as an add primcall.


I believe it is legal to actually reassign the global builtins, not just shadow them. Proving that a program doesn't do this is difficult to impossible, and I think some schemes give you an option to tell the compiler you won't do it. Chez Scheme has a section in their manual recommending pulling top level declarations into lets that it can analyze locally in order to optimize them.


Scheme always felt less dynamic than Common Lisp to me, with less repl-messing capability.

Both Scheme and CL let's you completely shadow any symbol in a given compilation unit, however.


If Common Lisp allowed additional methods to be added to + (if they were generic functions, and if the new methods did not override the standard ones) without changing the existing methods, it would be possible to be just as efficient. That's because one could just dispatch as now and instead of erroring if nothing applied, instead check the new methods.


for those wanting generic +, equality and comparison in CL, there's a nice library: https://alex-gutev.github.io/generic-cl/


What would be nice is a way of having that generic +, but making it as efficient as builtin + on the standard numeric types. CL implementations do not currently have that capability (except perhaps if they make builtin + rather slow).


I'm guessing there are very few people out there that think of programs as that dynamic? Especially considering that the message you are quoting started from python, how does it compare there?

I'm also curious to know why I would want something that was so dynamic that + could be redefined on me.


One that comes immediately to mind is that you might want + to handle vectors as well as scalars. Something like:

    (define scalar-sum +)

    (define (+ . arguments)
        (if (vectors? 'arguments)
            (vector-sum 'arguments)
            (apply scalar-sum arguments)))


    vectors? and vector-sum not shown for clarity.

Edit: or maybe you want any sum in excess of (say) $5,000 to alert a manager.

    (define old-plus +)
    (define (+ . args)
      (let ((value (apply old-plus args)))
        (if (> value 5000)
            (begin
              (alert-manager)
              value)
            value)))
The nice thing here is that this Just Works anywhere + appears in the code. You don't need to put the conditional and the call to alert-manager everywhere you're calculating a sum. Of course, in a real implementation you'd want to pass stuff to alert-manager like what module you're in, the transaction number, etc.


Fair, I should have tried to use my imagination there. Basically operator overloading? I forgot that generic functions are different beasts, and I've rarely had need for this, myself.


> For example, out of the box, the compiler can assume that things like '+' aren't going to be redefined behind its back.

Because it is undefined behavior to do so.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: