gilch / hissp

It's Python with a Lissp.
https://gitter.im/hissp-lang/community
Apache License 2.0
364 stars 9 forks source link

defonce defs twice? #236

Closed gilch closed 11 months ago

gilch commented 1 year ago

Or rather, the definition happens once (per module instantiated), but the side effects can happen twice: once on compilation, and again on first import. This is because the compiler doesn't cache the modules it creates. It wasn't really noticeable until I tried doing some REPL-driven tkinter, when I noticed that a recompile made a new window pop up, even when guarded by a defonce.

Furthermore, every recompilation will trigger the side effects again, even when they're guarded by a defonce. This is because the compiler doesn't read the cache either. Maybe it should. Caching is why imports don't.

When I wrote the compiler to begin with, I didn't have a defonce macro. I was also thinking about workflows where the compiler was run in a different session than the import (maybe even on a different version of Python). I still want to support that, but I also want to support the REPL-driven workflows where a defonce would matter, and the current behavior doesn't seem right for that.

reload used to be a builtin, but subtleties around globals sometimes not getting deleted made it too confusing for beginners, so it got moved. Clojure has similar problems, but the faster feedback loops are valuable enough to make the REPL-driven style worth learning. Making the compiler use the cache would have similar issues.

I'm tempted to put in a kwarg to keep the old behavior, but it's probably not necessary. One can always delete the module from the cache, but one also has to know that's possible.

The desired caching behavior makes me wonder if the compiler should be an import hook. I still kind of think it shouldn't. Sometimes the source isn't from a file. Even when it is, we still want to produce .py files, and macros mean the programmer needs to be able to control when compilation happens.