freenode/#lisp - IRC Chatlog
Search
18:22:15
amerlyq
In my workflow I have both (init-A) and (deinit-A) together in file. I edit them symmetrically when needed and reload. But if event loop in another thread already called previous version of (init-A), then after ending event processing it will call new (deinit-A), which is wrong.
18:24:15
Bike
if i understand amerlyq's problem correctly, it's that deinit-a is being redefined AFTER init-a is called but BEFORE deinit-a is called, and the new deinit-a is inappropriate for undoing the consequences of init-a.
18:25:03
Bike
yes. i think this requires more synchronization than an implementation could provide without some input.
18:25:58
phoe
I know that Erlang has this sort of modularity in place, it supports live-reloading module by module, and a module contains multiple functions at the same time
18:26:56
amerlyq
I was able to found where I read mention about "multiple environment model" https://www.reddit.com/r/Common_Lisp/comments/9q6bum/how_does_common_lisp_implement_hot_code_reloading/
18:27:18
amerlyq
>> Each stack frame has its own environment frame, which allows you to "go back in time" and evaluate code in the context of a particular stack frame
18:27:57
phoe
eval-in-frame likely refers to dynamic context rather than an old version of the dynamic environment
18:28:06
phoe
eval-in-frame likely refers to dynamic context rather than an old version of the global environment
18:29:08
Bike
"It seems that in some way the LISP compiler updates also the call stack. " i don't think this is actually true.
18:30:22
phoe
but it requires the calling code to be prepared for such redefinitions, and still doesn't have any synchronization so is prone to race conditions
18:34:24
Bike
i don't understand how you could accomplish both allowing threads to see redefinitions from other threads, and making sure they see all redefinitions in a module at once, with preemptive multitasking?
18:37:34
amerlyq
if we combine init and deinit under single class, will instance use old or new deinit?
18:38:04
Bike
that is not how methods are organized in lisp. functions exist in themselves, they are not part of or under any class.
18:39:01
Bike
now, if you had like, (init object) and (deinit object), the choice of what method to call is delayed until the actual call, so if you redefined deinit it could work.
18:39:26
amerlyq
So, instances call methods too by name, and not by pointer (in which case instance would have still old ptr)
18:41:45
amerlyq
then, what is general workflow to mitigate such problems in your development? Do you really must reinit whole image when you with to replace some init-deinit pair?
18:42:39
Bike
I don't think I have ever run into this particular problem. If I did, I would probably stop the loop and redefine things, yes. If I really wanted to keep the process going I'd probably do something like what phoe wrote, maybe hidden by macros.
18:47:56
amerlyq
Bike: What about global state stored outside of loop? What if it still contains instances of old classes you changed? Will you try to transfer state somehow (assuming it was long to load/evaluate) or will ditch it too?
18:48:53
Bike
instances of classes that are redefined actually do get lazily updated to match the new definition.
18:50:23
OlCe
amerlyq: If you want to keep init-A and deinit-A in sync, a simpler way is to redefine the caller of them. It it's an event loop, then you should arrange for a way out of the loop after the caller's redefinition, and call again the caller.
18:51:03
OlCe
amerlyq: If not, you're going to have to hack the new version of deinit-A so that it runs the old code only if init-A has been called, which you may not be able to determine without a new version of init-A anyway.
18:51:26
amerlyq
Bike: Hm. Lazy update... (defclass Pt (x y)) -> (defclass Pt (a b)). After dropping x,y -- who will init values a,b , if their init was before the loop -- and therefore never called again?
18:52:29
amerlyq
OlCe: even if you redefine caller -- you still must redefine inidividual init/deinit -- and will still get inconsistency. Otherwise -- you must inline them for your approach to work
18:52:54
Bike
amerlyq: instances are updated at latest the next time you try to access one of their slots. so, if you then tried to access the A slot of a point, it would be updated, which means the value of the x slot would be dropped and the value of the A slot would be initialized from the initforms, and then the read of the a slot would complete and return that initialized value.
18:54:11
OlCe
amerlyq: Not necessarily, if your redefine the caller, you can substitute the calls to init-A' and deinit-A'.
18:56:19
amerlyq
Bike: and so, "A" slot will contain "default value" instead of expected values from "init" accompanying the "Pt" class. In demo of particles it will look like abrupt jump of all points to the (0,0) in the moment of reload.
18:57:08
OlCe
This way you just change the bindings to call the new versions of init-A and deinit-A in the new version only.
18:57:20
Bike
amerlyq: the instance updater doesn't know anything about your "init" function, no. You can however actually customize the updater to call your init method or whatever.
18:59:53
amerlyq
OlCe: thanks for the idea, batch-renaming functions by adding incremental sfx will allow somewhat atomic dirty replacement (still GC is crying).
19:00:29
amerlyq
dynvars and funcall looks like the way -- not "generic", but at least for some functions which I replace the most often.
19:02:00
amerlyq
Bike: I read above as "don't rely on lazy init and better manually reinitialize everything, however long it takes"
19:08:28
amerlyq
again example with particles simulation -- generally you expect to have some initial distribution -- so you have generator which creates batch of points with specific (x,y) based on its parameters. If you wrap this generator to generate single i-th point and provide it to lazy init -- you will "hardcode" generator parameters
19:09:37
Bike
Maybe I wasn't clear. The updater can look at the instance pre-update. You could for example assign A to have the old X value and B to have the old Y value.
19:09:52
Bike
But you were phrasing things in terms of an (init) call so I thought that was what you wanted.
19:13:20
Alfr
amerlyq, you could make your init-a return a corresponding deinit-a which the user of init-a shall call later.
19:13:34
amerlyq
Slightly convoluted example (I know): changing Pt(x,y) -> Pt(a,b) may signify you worked with geometric plane and wish to try working with phase plane (s,v) now (and still keep all previous program state). In this case there is no direct conversion (x,y) -> (a,b) and you must get new (a,b) values somewhere. Still let's stop, I know I must simply create PPt class instead :)
19:15:41
Bike
i kind of want to know how this is supposed to work. i mean if there's no correspondence between the old and new points, what does "updating" even mean?
19:16:51
Bike
I guess you could do something like call a function that returns both an initializer and deinitializer, then calls the initializer, then does whatever work, then calls the deinitializer. and then wrap it in a macro so you just write (with-a ... do work ...)
19:28:44
amerlyq
Bike: I had a mess of example, sorry. Emphasis was, that when you -add- new field -- it's often dependent on smth outside instance, so you can't lazy-init to generate proper value for that field
19:29:21
Bike
sure. in that case you'd probably have to do something more global, yeah. which i guess would involve pausing.
20:38:00
phoe
What sorts of fixes, corrections, revisions, additions, tricks, recipes, informations, would you like to see in the second edition of Common Lisp Recipes?
20:39:33
Xach
i preordered Common Lisp Recipes in 2015. between my preorder and the actual release, i moved to a new place. the book was delivered to my old house. the new owners kept it! i have never read it!
20:41:52
mfiano
A recipe for getting set up with a proper environment so we can direct people insisting on MS Notepad without SLIME/Sly over to it.
20:42:37
phoe
I will certainly want to have a whole initial section dedicated to emacs, vim, sublime, atom, and vscode along with their respective Lisp environments
20:44:10
_death
I couldn't bear to finish CLR.. every page had footnotes, which are not useful when reading front to back, and my compulsion forces me to read them.. too painful
1:09:02
Gnuxie[m]
Rust cannot be made lispy, mostly its investors are not interested in interactivity, but this isn't what you want to hear
1:10:56
Gnuxie[m]
That's Ignoring everything that makes rust rust stands against what makes lisp lisp
1:20:22
theemacsshibe
So, what kind of "built-in variable" would make Rust any more like Lisp exactly?
4:50:02
fiddlerwoaroof
(asdf:initialize-configuration (:source-registry :inherit-configuration (:tree "/path/to/directory/"))) works too
5:06:05
no-defun-allowed
One solution is to do (funcall (find-symbol "NAME" "PACKAGE") ...) but I'd rather ask why you need to do that.
5:06:41
no-defun-allowed
Can you load the other files required beforehand, or at least the file defining the package?
5:07:11
dbotton
So I want to give a way for someone to load and run a tutorial file in my quicklisp project without needed to known where it is installed
5:08:33
no-defun-allowed
One approach is to define another ASDF system for the tutorial, which depends-on your actual system, and have the user load that.
5:08:56
no-defun-allowed
So, (asdf:defsystem #:clog-user :depends-on (#:clog) ...) then the user types (ql:quickload :clog-user)