rune icon indicating copy to clipboard operation
rune copied to clipboard

How to handle closed over variables in functions

Open CeleritasCelery opened this issue 1 year ago • 0 comments

To this point, all values associated with a global function were marked read-only. They are shared between threads so mutation would not be safe. However when working on bootstrapping cl-generic I ran into an issue where the function is actually a closure that closes over the value of the method-cache variable. When a generic function is dispatched, the value is first looked for in the cache, and if not found it is added. However this causes a problem with our assumption that function data is not mutated.

possible solutions

  1. Make function thread local. This would make the issue go away, but would also mean that we have to copy every function that a thread needs to that thread. That will be a lot copying that we don't normally need (the vast majority of functions can be treated as immutable). It also means that function lookup will be more expensive because we can't use a stable address but instead need to do a hash lookup for each symbol.

  2. Make LispHashTable thread safe. We could wrap it in an Arc and therefore make is safe to access from multiple threads. However this would make code harder to reason about because we could have hash-table mutated under the hood and we get spooky "action at a distance". It will also probably make hash table access slower. This also would do nothing to help if some other data type was used that is not a hashtable.

  3. Make closure values thread local. We could treat data inside the function as immutable, but closed over variables are handled just like normal variables (thread local and copied on read to other threads). The key for lookup would be a tuple (function-name variable-name). For the global function we would have some sort of marker value (can't be any existing value) to indicate it needs to be looked up. for generic functions, this means that the first time we call one we have to copy the entire method-cache to the thread (even though we only care about that one method). Also if a function is bytecompiled we don't have a way of determining which constants are closed over values and which are "normal".

CeleritasCelery avatar Feb 02 '24 18:02 CeleritasCelery