Hacker Newsnew | past | comments | ask | show | jobs | submit | frollogaston's commentslogin

Yeah, I'll use LLMs to write all application code, but not so sure about libraries. Especially more foundational ones.


What to you are the foundational ones? Perhaps CL has them already, or if it's actually a C lib that every other lang uses, CL can use that too. If not, the feedback would at least give people ideas.

From the parent's security standpoint I'm more sympathetic, there's been a lot fewer eyes on CL code, there's no central place to keep track of discovered security issues, and perhaps more vigilance is required against untrusted input compared to other languages. At the same time, every time I've exposed a CL-powered website I've noticed various attempts at e.g. wordpress endpoint discovery and I sleep soundly knowing a wordpress deployment is something I'll never have to worry about or take extra precautions against. Every time I hear about a supply chain attack I also am happy about the choice of CL. (Though in truth it's not to say that such attacks aren't possible, but for various reasons, one of them rather quite embarrassing to the overall ecosystem, pulling a big one off is going to be more difficult.)


Like asn1, relational DB drivers, Redis, protobuf, XML/YAML/JSON parsing, web client/server, and SDKs for stuff like AWS. Not saying Common Lisp lacks well-maintained versions of those, cause I don't know, just that those are the foundational things I wouldn't want LLM-coded.


Also anything that does image/video processing or cryptography. Both are susceptible to severe security vulnerabilities the average programmer wouldn't think about, e.g. https://heif-heist.com


Thanks for the list. (And Common Lisp does have those things.)


I mean, everything in this comment could equally apply to something like Go's net/http and database/sql, or Elixir's Phoenix/LiveView/Ecto?


IF you're running a debug build. I guess Common Lisp can do this in prod?


I mean, so can JavaScript then? Why would I want a debugging window to open up for a customer in production? I remember when Windows used to try to open a debugger when certain programs crashed on me as if I knew what the heck any of that was supposed to mean.


No debugging window opens up for anybody by default^^ The web server (ex: Hunchentoot) will crash the request's thread and print the backtrace by default. Change a server's variable and print the backtrace in the browser (= dev mode), change another variable and get the interactive debugger (= dev mode++). All this without stopping/restarting the server. Or just restart it if you want.


Was assuming it was a backend. I still don't understand the advantage though. It'd help to have an example.


Thing is with .NET you can debug a release build, and even do remote debugging... So it's all a weird claim to me. Definitely someone who only uses Common Lisp and maybe a language with a less impressive debugging background wrote this article.

To be fair, I love Lisp, I dont do a lot with it, though I'm mostly a fan of Racket which is the most modern one outside of maybe Clojure.


Yeah, you don't want a lisp debugging window in production. The absence of stack unwinding does enable editing behavior with wrappers. You could have different error handling without changing any code downstream, and I guess an LLM could theoretically change that depending on the bug it's responding to.

But I'm not positive the juice is worth the squeeze, and this article was unconvincing. I mean if you want macros and terse code and a bigger ecosystem, wouldn't Clojure make more sense?


Just finished typing up an example as you wrote this. Rather than duplicate it, here's the link:

https://news.ycombinator.com/item?id=49974251


I imagine production backend with LLM connected using debug interface and patching the code continuously on any exception encounter.

(not a CL expert here)


Erm, sounds niche. Like you can normally do all that minus resuming the program in other languages. If this is a webserver, it should be fine to restart it for an update, it's not like I'm going to catch some user's failed request and patch it before it times out.


Good luck debugging all that minified JS code without a map file. It can be done, but will be very painful.


  Also, in most languages an error will crash your program. So if you’re writing code with an LLM it will have to read your crash logs to make some changes and run your program again. In Common Lisp your program won’t crash, it’ll stop and open a debugger with the whole stack and all the variables. You can just point your LLM at the debugger, and it’ll make its fix and resume the program.
What does this look like in a real example system that you're maintaining? I can't imagine you'd always be able to resume like that if it's something like a webserver.


Test driven developmet practitioners in Smalltalk used to (still do?) write the test before writing the implementation, run the test, and, when the "method not implemented" error shows up in the debugger, type the implementation and continue the execution. Common Lisp can do that too.

So, in practice, it might look like you hit any kind of runtime failure, and then the LLM writes some code to fix it, and the user's request completes successfully with no errors.


Not the author, but unless the server was running in a short-lived ephemeral container (in which case the management system probably killed the container and started a new one), the CL process would still be around in a paused state, waiting for you to connect to it and tell it how to resume.

https://comp-348.github.io/lisp-debugging.html has an example of what it looks like. A toy example, to be sure, but the basics of a real example would still look the same. You're given a choice of several options, very reminiscent of the "Abort, Retry, Ignore?" choice that used to be oh-so-familiar in the days of DOS. Except this one is more useful, because it offers ways to specify how to resume. E.g., the toy project is halting on a `(print X)` call where the value of X is not defined. And the choices are:

0. Continue. (Retry using X).

In the toy example, this would fail, because nothing else has defined X. But in real code, the name might have been undefined because the data needed to define it hadn't arrived yet, from the database or the filesystem. In which case retrying the statement might work the second time.

1. Use-value. (Use specified value).

This one prompts you to enter a value for the undefined variable, and continues, but it does not modify the value of X in the program. The next time the program tries to use X, it will halt again with another "unbound variable" error.

2. Store-value. (Set specified value and use it).

This one, just like Use-value, will prompt you to enter a value to use... but then it will set X to that value and continue running the program. Next time the program tries to read the value of X, it will have one, and the program won't halt.

3. Abort. (Exit debugger, returning to top level).

This is what you would choose if there's no good way to fix the error, and you just have to quit the program and restart. Though note that choosing this option isn't going to exit the program you're debugging, just take you out of the debugger. You'll still need to kill-and-restart it some other way... or come back an hour later when the value is finally available, and then choose options 1 or 2.

Hopefully that gives you a taste for what the CL debugger is like to use in practice.


This looks like a good debugger, but it's similar to ones I've used in other languages. What's special about this one? I thought the idea was you use the debugger in prod, but now I don't think that's what the article meant.


Yes, you use the debugger in prod. I've read many articles by Common Lisp users talking about how great that feature is: they can quickly get production back up and running, then go to the code and implement the same fix they just did on live prod.

And it's not editing files on the server, it's actually reaching into the running code and tweaking its values.

That, I think, is the difference here. In many languages, the debugger can pause on the exception and let you inspect the code. But in every other language I've used, once you edit the code to fix the bug, you can't resume from where the debugger paused. You have to recompile the code and resume from the top. In CL, you can resume from exactly the state you were in when the debugger paused, only this time with the correct data in place. (Or even with a code fix having been applied, live, to the code).


First , that’s absolutely not how you run a CL server in production. If you had a debugger installed in production, which you shouldn’t, it wouldn just pause there and time out the sockets. What you could do is attach your client to the Lisp system with swank and then make your image changes, later to be synchronized with the actual code in the repo.

Second, other languages can also do that, Java for example has facilities to recompile functions and then rewind the stack to run the function again from the beginning of it. Dart also does that even better and people use that extensively in Flutter with hot reloading. I do that in a debugger during tests though, never seen it done in prod.


You can do this in many other interpreted languages like Python interpreter when running with --pdb flag will do the same. I imagine CL does this by default when running code in interpreted mode and omits the behaviour for compiled (production) binaries.


In CL, this works with compiled code.


In Python, can you fix the buggy function, re-compile it, and resume execution from the stack you want? I don't think so. That's common practice in CL, useful both during development and in production if necessary. In Python, you edit the file, your webserver restarts and reloads everything. In CL, the change is in. Nothing is restarted. The function was compiled and the next call will use it.

Python REPL and CL's are very different!

In CL: you can install new dependencies from the REPL. You can change a class definition, the existing objects will take the changes at the next invocation. You can control how this happens, etc. TLDR; CL is built around live programs. Buuut we can also do it the dumb (and safe) way following the industry's best practices.


While this can be useful in extreme situations, such as a production system that can't be taken offline even momentarily, it has always felt like a footgun to me: a way to make critical changes that are recorded nowhere and flow through no change process. Lisps are full of these really powerful features that should be used sparingly, but are held up as reasons to use it. I wrote a fair amount of CL a couple decades ago, but always felt that "pause, inspect, stop, edit, start" was safer than "pause, inspect, edit, restart". Some corollary of Kernighan's Law, there.


You can use the features as little and as safely as you want:

> can be useful in extreme situations

it's already useful in development, it's one of those things that shorten the dev loop and make development in CL a breeze. For production, you choose. Connect to the live image to inspect the state without modifying anything or debug while it's live.

> recorded nowhere

you can connect to a running program and have the source under VCS. The thing to do isn't to copy-paste new function definitions in the live image's REPL, but to connect to the image, make changes to the source files, and re-compile them (a C-c C-c in Slime) (sending changes to the running program).

> safer

yep, some things are safer. Advanced features are useful even for simple things (introspection, etc).


But every language lets you do this in development. Doing it in prod and hot reloading is Common Lisp's special feature.


re: “”In Python, can you fix the buggy function, re-compile it, and resume execution from the stack you want?””

Yes. I code Python in Emacs with the ancient Python support for running a REPL, loading buffers, editing a function and just hot reloading the modified function, etc.

I am an old man, and I like old man tools :-)


mmh but the rest of my examples, you can't do them in Python (:


Yeah but what happens to your server then? The connection it was handling times out I guess, then is the rest of it frozen or what?


no, the app isn't frozen (thinking about the Hunchentoot web server).

Also of course the default is to not get the debugger but let the server thread crash and print the backtrace. With a user setting, you can choose to get the debugger, and have this request wait (the connection may time out, which isn't an issue during development). Another setting is to print the backtrace in the browser (= dev mode).


I mean, that entirely depends on the server design. Is it running one connection per process? One connection per thread? Presumably you've designed the server in a way that one slow connection doesn't block other connections from being handled fast, which means that this one connection whose handler went into the debugger is just now a really, really slow connection taking minutes (or hours!) to handle, but the other connections are running just fine.

Now, if your entire server is taken down because one connection threw an exception, that's bad design. But pretty much no major language works that way. All of them allow you to set things up so that an exception handling connection A won't affect connection B. And if you've done that in Common Lisp, then connection A halting and waiting for the debugger won't affect connection B either.


Maybe beside the point, but I'd hope it's neither connection per process or per thread. Modern webservers tend to rely on either an event loop or greenthreading. Looks like such a thing exists in Common Lisp, not sure how the debugger would interact with it though.

Anyway it sounds like this isn't really the target use case for the debugger since restarting a webserver is supposed to be easy. Maybe there's a different use case in mind?


I feel like even if the distances are equal, it's faster to walk a bike up a steep grade and bike the rest flat than it is to bike up a moderate grade the whole way. This topic has probably been discussed somewhere else.


People can generally only output their max power for short durations. The output level they can sustain is generally much lower. I bet you could try to model higher limits for short distances, but what those should be could vary greatly depending on personal fitness.


I think that too favors walking the bike up the incline. Anyone able-bodied should be able to do it, some faster than others, but biking up an SF incline is more hit or miss, especially when considering different bikes.

My reasoning for the bike-hike being faster is that legs are designed for it. Legs are only inefficient on flatter ground because you have no equivalent of high gear (like extendible legs), so all that torque is going to waste.


Uhh, excuse me? Legs are inefficient on flatter ground because they don't have wheels.

Legs have to start, go up, go down, stop.

Wheels go brrrrr.


That's some of it too, but in a way legs aren't all that different from wheels in how they work. Most of it is the gearing. Like there's a gear on every mountain bike that will make your feet go down at the same intervals as walking. That sucks on flat terrain. Legs are also not perfectly designed to push pedals, especially for people who don't bike often.


I believe the "wheels on the bus go round and round" :-)


BRouter models this as inertia, I believe.


But hike a bike is no fun, especially if trying not to sweat


Yeah the multi-unicode-char grapheme clusters are basically only for emojis once they started adding stuff like every ethnicity/gender combo of 4-person family. And that one historical Korean script.


Those clusters are reusing technology that was needed for actual languages. Combining characters in general are used all over.


I greatly prefer plaintext in most cases where Markdown ends up being used. WYSIWYG is more useful than formatting in these cases. Most of the formatting makes it harder to read anyway. Some say you can ignore MD and treat it like plaintext... not so when you use a newline.

Oh and now you could have LLMs write the Markdown, but chances are no human reads that, or even if you do, the formatting is going to be insane. I have to keep telling Claude to give me a .txt instead of .md when asking for a context dump. Maybe .md is popular for agent readmes because they optimize around its headings.


I’m building https://marble.md around this tradeoff: keep the Markdown file, but show the formatting while you write. You can also edit together in the browser. Does that address what bothers you about Markdown?

lol seriously, this is a solved problem


People should really know how to delete sims, but there's a ton of obscure Xcode nonsense that in the "old days" people would blindly trust Stackoverflow answers or even blogs to fix. If Xcode is a tractor, it's the old thing you whack with a wrench and say "come on Bessie" to make it temporarily work again, not something most devs really understand.


This is how I always did it. Why would the alternative involve going into safe mode? Pretty sure I've manually deleted those files before too.


We need macOS 28 Snow Golden Gate


Consider applying for YC's Winter 2027 batch! Applications are open till November 2.

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

Search: