this post was submitted on 20 Oct 2023
1 points (100.0% liked)

Lisp

52 readers
3 users here now

founded 1 year ago
MODERATORS
 

The idea that one can change and modify code while it is running sounds great, but I have never really gotten to the point that I understand practically how to do it in a non-trivial circumstance. As a concrete example where I think I should be able to do it, but I can't, is when running one of the examples from the claylib system. I am using slime/emacs and I open claylib/examples/shapes/bouncing-ball.lisp. In slime I use (in-package :claylib/examples/bouncing-ball) and then (main) and I have the bouncing ball demo working fine. What I have tried to do is to change the color of ball from its current +maroon+ to some other color. I have tried editing that part of the function definition in bouncing-ball.lisp and recompiling, but nothing changes. If I kill the running example, recompile the bouncing-ball.lisp and then re-run main I see the new color, so I know that I am specifying a color correctly. Would someone tell me the steps to change the ball color while it is bouncing around to help me get started on this "live" coding method? Of if they think one of the other raylib wrappers would be better for this I can change. I am just using this as a learning tool to give me some visual feedback as I make changes. Thanks.

top 8 comments
sorted by: hot top controversial new old
[–] Shinmera@alien.top 1 points 11 months ago

All that happens when you recompile a function is that a new function object gets created, and the name of the function is updated to point to that new function object.

But the old function is still the one actually running. For your new function to be used, it has to be called, first. What you can usually do then, is to create a secondary function, step, or whatever you want to call it, and have that be called in the main loop. Then, because step will exit and be re-called every update, when you recompile it, the new step will be executed, too.

[–] reddit_clone@alien.top 1 points 11 months ago (1 children)

My understanding is if it is a long running function, and if it is currently running, it is not going to show any new changes. Until it is actually called next time.

[–] brittAnderson@alien.top 1 points 11 months ago
[–] fvf@alien.top 1 points 11 months ago (1 children)

You can't recompile a function as such, running or not. What you can do, is to re-compile some code into a new function, and assign whatever name the old function had to the new function.

Whenever that function-name is called next, the new function will get called. The old function might still exist, either because it was already running while the new function was compiled, or because it as assigned to more names (or otherwise available) except through that function-name from before.

So, again, while you can't recompile some function named X, you can create (i.e. re-compile) a new function and assign it to X. And any function(s) Y that call X will also get "modified" in the sense that they from now on will call the new X instead of the old X (without Y having to be re-compiled in any way).

[–] brittAnderson@alien.top 1 points 11 months ago

Thank you very much. The following is for any future visitor who ends up here with a similar question.

One of my challenges with this example code is that the make-ball function was in a let*. The original example authors were using a move-ball function in their main game loop. So, inspired by your suggestion I wrote a color-ball function with a setf for the color slot of the shape object. Then I wrote an upd-ball function that just called move-ball and then color-ball internally using the ball object created in the let. Then, it all works great. If I adjust the "move-ball" function and recompile the ball speed changes, and if I adjust the "color-ball" function the color changes.

Since you were kind of enough to respond, do you have a recommendation among the raylib wrappers (or the sdl or allegro wrappers or others, including yours) that you recommend as being particularly beginner friendly and also encouraging of good habits for someone learning some simple graphics manipulation with CL?

[–] shelvick@alien.top 1 points 11 months ago (1 children)

Hi, Claylib maintainer here! The other commenters have already answered your general question -- write a separate function that's called from your main loop and then recompile that. I believe your confusion stemmed from the fact that most of the examples are written for conciseness rather than live coding. I had meant to add some more examples specifically for live coding but never really got around to it. As you may have figured out by now, the initial values are typically defined in scenes and then changed later via whatever custom functions you might add.

[–] brittAnderson@alien.top 1 points 11 months ago

Thank you for you library. It would be great to have a tutorial about how to get started that includes some of this. I know you are busy working on the library, and that is what I hope you spend your time, but I will keep good notes on my experience and maybe I can contribute some sort of tutorial blog post or something. Cheers,

[–] paulfdietz@alien.top 1 points 11 months ago

How to recompile bits of a running function as you want is actually an interesting research problem. It comes up when you have optimized code, then change declarations that the optimizations depend on. For example, you might inline the access to a slot in an object, then dynamically change the layout of the object.

This is properly something the Lisp implementation should handle. Robert Strandh had an interesting approach to this for SICL that he described in a recent ELS.

http://metamodular.com/SICL/call-site-optimization.pdf