freenode/#lisp - IRC Chatlog
Search
18:12:21
pfdietz2
I read this paper on mutation testing at Google. I was surprised to see one of the 7 languages involved was Common Lisp. https://ai.google/research/pubs/pub46584
22:26:09
whartung
I dunno if he’s hacking anything right now, but he apparently drifted over to Python a long time ago.
23:45:14
drduck
Can anyone speak on if there are any differences in the hot reload capabilities SLIME provides lisp compared to that of which an IDE provides java?
23:55:01
whartung
I don’t know exactly what slime does, but we know what CL can do. Basically the REPL, “LOAD”, and “COMPILE”. All of those impact the environment in subtle, different ways (which I can’t detail, only knowing that there’s differences.)
23:55:53
whartung
and the symbol table is simply one aspect of the global environment, but an important one.
23:56:19
whartung
the SYMBOLS remain (unless they’re specifically unintern’ed), but what they reference changes.
23:58:15
whartung
no, since (normally), Lisp continues do dereference stuff through symbols (when they have global scope), then you have dynamic changes to a running system. This can clearly be adjusted trhough efficiency hints and stuff like that, but at the high level, if you have (defun x () (print “hello world”)), and something calls (x), if you later do (defun x () (print “goodbye world”)), that existing reference x will now say “goodbye” instead of “hello
23:59:22
whartung
So, that’s what SLIME does, is it “simply” updates the global environment, and then the chips fall where they may.
0:00:04
whartung
I recall, long ago, with Franz lisp, running multi-threaded, having a routine that was just running (x) in a loop, and seeing it go from “hello” to “goodbye” when I re-defun’d x. “Hazah!”
0:00:25
whartung
(And here we splash in more disclaimers abou thte global environment and threading and yada yada)
0:01:13
whartung
But we also know, that this is more of the first class concept in the system and the language. It’s “supposed” to do this. Even to the point the CLOS has a protocol for changing class instances in flight.
0:01:51
whartung
when you add slot new-slot to an CLOS class, you can write code to properly update that for existing instances of that class. Pretty snazzy.
0:02:28
whartung
You first have to appreciate that with Java, we like to think all about classes, and think clases are king and such.
0:04:59
whartung
If you try to, say, reload a JSP in a web container, that’s a diffrent problem. That creates a new class from the JSP, and swaps out the old one that’s mapped by the URL of the JSP. So, when you hit test.jsp, it just loads the new class, not the old one.
0:06:04
whartung
That’s much more of a hack. It why the reloads aren’t always successful. It’s one thing to reload the class of, say, a web controller. Something that has, you know, one instance. Big deal.
0:06:33
whartung
It’s another to reload the class of, say, a JPA Entity, like Employee, that you happen to have 10,000 instances cached.
0:08:25
drduck
So full feature dynamic reloading in lisp is by design and it's a hack -- also sometimes only partially works -- in java?
0:08:40
whartung
Java can’t “update” instances. it can’t add slots to old classes. And, depending on how the class was redefined, your cached objects may well no longer be of the “same class”. If the new class has a different class loader, then when “new code” tries to cast “new Employee” from a instance of “old employee” that’s in the cache (and Java ALWAYS casts under the hood), it’ll fail. “CLass Cast Exception”, because Employee is no lon
0:09:02
whartung
It’s much more of a first class concept (with all the warts and caveats) in Lisp than it is in Java.
0:09:08
drduck
I wish I could comprehend a little better what that actually means in a freshman-esque case study.
0:09:32
whartung
It means that redefining dynamic elements in a runtime system is not always simple.
0:10:19
whartung
Lisp, out of the box, is dynamic at the price of performance. Lisp can be made “faster” through declarations that limit the flexibily.
0:10:48
whartung
For example, the CL package is specifically defined by the standard to really not have the dynamicity of other Lisp code.
0:11:13
whartung
Consider the “+” function, nobody on the planet wants to invoke a function call for +. It’s just crazy.
0:11:42
whartung
so, (+ 1 1) isn’t really a function call when it’s been compiled. Redefining “+” isn’t going to work like redefining X would, right?
0:12:02
whartung
but that’s why the CL package is specifically exempted, so the compiler can do reasonable stuff.
0:13:01
whartung
Runtime systems make a lot of assumptions, Java assumes that’s its really in a pretty static environment. The CLassLoader is the barrier that helps boundary the dynamic behavior.
0:13:44
whartung
when you load a web app, Tomcat will create a new ClassLoader, and THAT loads in your web app and it’s classes and stuff.
0:14:18
whartung
When you undeploy the webapp, the classloader gets destroyed, and that’s the link in the chain that keeps your app in memory. With that gone, the GC marches through and kills everything
0:15:06
whartung
but out of the box, Java doesn’t really like the underlying structure of its classes to change. The ClassLoader give Java a lot of dynamic behavior.
0:15:25
whartung
But changing class structure in flight is not one of them. Rather, they want you to toss away the old, and brin gin the new
0:15:42
whartung
but there goes not just your class, but the 10,000 cached Employee instances as well.
0:16:34
drduck
what happenes to the 10,000 cached Employee instances in common lisp in this scenario?
0:16:49
whartung
but that’s also because most of the use cases are folks updating application logic, changing a web controller, or some other “mostly” stateless bit of code.
0:19:26
whartung
you can see that when the structure was changed, the NEW print routine for q was unhappy
0:24:13
whartung
so, here, we see that CLOS is actually telling us that it’s not updating the instances in this case
0:24:36
whartung
but notice the different message when we try to access ‘d between when we redefined the classes
0:25:05
whartung
I’d have to dig a bit to find an example that uses the clos redefinition protocol — see if that works
0:30:22
whartung
now, for the CLOS implementaion in CLISP, in theory the structure is supposed to updated when the class is redefined, apparently by default CLISP doesn’t support that.
0:30:45
whartung
but the fundamental point is that the two environments live with two different base assumptions.
0:31:18
whartung
Java is a static world, and while it can easily handle loading new classes, it’s not really set up to allow them to change, especially structurally.
0:31:48
whartung
when an IDE reloads classes, it’s doing a magic trick that may well not always work. It sometimes works.
0:32:41
Bike
the semantics are that when you redefine a class, instances of that class are updated (i.e. turned into instances of the new class) some point prior to you accessing one of their slots. and the update process is a generic function you can customize.
0:32:41
whartung
Personally, I don’t use it in Java. I don’t trust it, and I’d rather have things take longer, and work consistently, than things be faster and be inconsistent. I hate going after some strange bug that “goes away” when the image is restarted.
0:34:59
whartung
no, it doesn’t that’s the point. If you have some Singleton out there reference a class that’s reloaded…who knows what happens.
0:36:10
whartung
And, sorry, at this point I have to do my own magic trick and disappear. Hope this was helpful.
0:36:31
whartung
In summary, the reloading mostly works in Java, just don’t be surprised if it bites you at times.
0:37:21
whartung
if you’re chaning just logic, it’s much better than if you’re changing structure in java
1:40:25
skidd0
how do you (use-package) or its equiv to load a package (to-do) along with all sub-packages (to-do.lists)
1:45:35
skidd0
so is there a way i can use a single (use-package) for all the many packages in my system?
1:46:43
Bike
but, you could have one package that exports everything interesting from multiple packages.
2:02:35
mfiano
Is there any undefined behavior with regard to using WITH-SLOTS with a structure-object?
2:21:28
beach
I know of no Common Lisp implementation that supports that. It would be fairly tricky, given the semantics of Common Lisp. I will be able to do some of that stuff with first-class global environments, but there are other things that are tricky, like modifying the readtable, etc.
2:22:48
beach
skidd0: Once a package is loaded, exported symbols are available. You just have to use an explicit package prefix. Lately, I have come to the conclusion that it's a bad idea to USE to many packages.
2:22:49
beach
Not only do you commit yourself to future modifications of those packages, but it also becomes harder to read the code, since you don't know from which package a symbol is used.
2:35:37
aeth
Bike: In case you missed it, I did manage to get my metaclass to work. The method you said to redefine was too elaborate so I wrapped it with :around. The issue is that SBCL hardcoded the initargs for effective-slot-definition-class even though it doesn't for direct-slot-definition-class. So I have to make everything my direct-slot-with-checked-type and handle the case of a null checked-type.
2:36:26
aeth
Bike: https://github.com/sbcl/sbcl/blob/c5db3dca77303b6f0601601e064c0a3b05deb4a8/src/pcl/std-class.lisp#L1210-L1214
2:36:44
aeth
It calls compute-effective-slot-definition-initargs which provides the initargs to effective-slot-definition-class. It uses the standard initargs.
2:36:56
aeth
So checked-type was always nil when I was checking for it in effective-slot-definition-class
2:38:01
aeth
What I went with is this, though: https://gitlab.com/zombie-raptor/zombie-raptor/blob/6f0360991ee3f27f4a918397d98a6713dd1211ca/util/util.lisp#L447-495
2:38:04
Bike
but i've never bothered with an effective-slot-definition-class method that didn't just always return the same class, it's true
2:39:27
aeth
On the other hand, since I have an assert there I could probably turn it into a general system, not just with guaranteed type checking. (It's a shame that :type isn't guarnateed to be checked)
2:39:38
beach
mfiano: WITH-SLOTS expands to SLOT-VALUE, and the page on SLOT-VALUE says: Note in particular that the behavior for conditions and structures is not specified.
2:41:07
aeth
mfiano: Afaik, with-accessors can be assumed to be safer and more efficient with CLOS objects, and it works on just about anything with the simple accessor form (not just CLOS objects and structs, even accessors like car and cdr).
2:43:18
aeth
Personally, I USE CL and my own packages, and try to USE nothing else with rare exceptions. I use import-from, but it's not perfect for some things. e.g. Apparently if you forget to import a class, it doesn't fail when you inherit from that non-existent class.
2:45:03
beach
skidd0: But you will do yourself a favor if you use explicit package prefixes. When you come back to your code in the future, you will have forgotten from which package a symbol comes if you can't see the package prefix.
2:45:46
beach
skidd0: And even if you have exceptionally good memory, the people who want to use your code and maintain it will have no clue where those symbols come from.
2:46:15
matzy_
i have a noob-ish question. for cl-cffi-gtk (gtk bindings for cl) where do you put the folder that you can load it with the command (asdf:load-system :cl-cffi-gtk)?
2:47:05
matzy_
everyone says to use that command to instll it, but i dont see where you can even point it to the dir. should i put it in my quicklip folder? i thought that was bad for manually installed packages
2:47:35
beach
skidd0: I am reminded of the quotation from Charles Simonyi on page 9 of this document: https://www.cs.umd.edu/~nau/cmsc421/norvig-lisp-style.pdf
2:49:16
beach
mfiano: And notice that there is no definition of "CLOS object" in the Common Lisp HyperSpec. The only reasonable interpretation of such a term would be "any Common Lisp object" (since every Common Lisp object is an instance of a class) which makes it meaningless.
2:52:25
beach
skidd0: Nowadays when I look at some code that I wrote a few years back, I deeply regret having overused USE, because I have no clue where those symbols are coming from, so maintaining that code is a nightmare. I usually start such maintenance by removing the USEes and inserting package prefixes. But even that exercise is VERY DIFFICULT.
3:10:12
beach
skidd0: No you don't have to. Others can use the double package prefix. But exporting is a signal that it is meant for client code to use.
3:12:18
skidd0
so if i had a TASK-LIST with a TASKS slot (that had a :accessor tasks), i export :tasks?
3:12:27
beach
skidd0: A protocol is a collection of types (usually classes) and functions (usually generic functions) that is all the client code needs in order to use your module.
3:12:37
mfiano
You may even have multiple accessors per slot, and only a selection of them exported for users.
3:13:17
skidd0
beach: the protocol basically a collection of higher leverl interfaces to the lower level code
3:14:02
beach
skidd0: Yes, a module (not a Common Lisp term) consists of a protocol (or interface) and its implementation.
3:14:36
beach
skidd0: Because you might want the client to be able to define an auxiliary method on one but not on the other.
3:15:07
beach
skidd0: The small part is the protocol and the big part is the implementation. So you don't want to reveal the implementation in your protocol.
3:15:36
mfiano
What I typically do, is I define a reader which is exported, and an accessor symbol with a % prefix which is used internally. That way, users know the slot is read-only, and I can pre-populate it myself through the internal API
3:15:55
beach
So you don't export those. Only accessors, and only those accessors that make sense as independent functions, without any reference to slots.
3:17:14
mfiano
Multiple accessors per slot starts to make sense when you think of the package system as a protocol for your users
3:17:20
beach
skidd0: Now for the technical details of :EXPORT in DEFPACKAGE. The :EXPORT and :SHADOW options of DEFCLASS take what is known as "string designators".
3:18:26
beach
skidd0: A string designator can be a string, a character (denoting a singleton string) or A SYMBOL.
3:18:33
mfiano
Also note, that the HyperSpec defines "accessor" to be any of reader, writer, or accessor, which might make what I said a bit confusing otherwise
3:19:00
beach
skidd0: The thing is that in Common Lisp, symbol names are usually typed in lower case and then turned into upper case by the reader.
3:20:07
beach
skidd0: One possibility is to use symbols from the KEYWORD package, so like :export :my-accessor.
3:21:06
beach
skidd0: When the reader sees a : at the beginning of a token, it creates a symbol in the KEYWORD package, yes.
3:26:10
beach
skidd0: Try (symbol-package ':hello) (symbol-package 'hello) (symbol-package '#:hello)
3:26:35
beach
skidd0: No, it is not anonymous. Anonymous means "has no name" and every symbol has a name.
3:30:26
skidd0
beach: not same symbol becuase, among maybe other things, the symbol-package is different?
3:30:30
beach
mfiano: There is nothing in the Common Lisp HyperSpec that says a symbol has a symbol-function slot.
3:30:57
mfiano
fair enough. Point being, symbols are objects, much like everything else in Common Lisp.
3:34:33
beach
skidd0: What mfiano says. It is the syntax #:... that makes the reader create a fresh symbol.
3:44:41
mfiano
matzy_: Probably not. GTK is a beast, and there isn't really anything "simple" about it, or really any GUI programming. Shinmera has created quite a few tools around Qt because of the fact, even though Qt's API is only slightly better.
3:46:46
mfiano
i would use something more native to CL, like McCLIM. Or I would use something hosted, like SDL2 with OpenGL, or a web frontend if it fits the problem.
3:48:10
matzy_
Really I just want to make a gui app for my personal use. Ive been wanting to learn cl for a long time, and i finally have a worthwhile personal project to do with whatever language i want
3:49:09
matzy_
i use linux though, and havent had to bring in qt yet (run a tiling wm instead of DE)
3:50:08
beach
matzy_: I would personally avoid learning Common Lisp by writing a GUI application because GUI applications are hard.
3:51:29
beach
matzy_: Debugging becomes a nightmare. You will have segmentation faults and other messy stuff that is typical in less safe languages.
3:51:43
mfiano
Start by learning Common Lisp. Not just using Common Lisp as a stepping stone to foreign libraries. You're bound to fall and get dirty
3:52:14
beach
matzy_: Plus, by mixing languages, you put yourself in a situation where you don't have any good debugging tools.
3:54:04
beach
matzy_: Now, McCLIM is a GUI toolkit that is (almost) entirely written in Common Lisp. But to use it, you need to know about generic functions and lots of other things that is not typical to learn in the beginning.
3:54:31
matzy_
it's pretty simple. I use arch + i3, so I just launch apps thrugh stuff like rofi. the problem comes when you cant remember an apps name (like, what was that pdf reader i instaled?). i wanted to build some GUI app organizer you could use to categorize and launch common gui apps. some small utility just for me
3:55:58
mfiano
rofi can do more than just act as a dmenu replacement. It is scriptable, calling out to any binary to do the heavy lifting
3:56:08
matzy_
ive just been looking for something to do in cl for awhile, because im not one to sit through endless tutorials. i like learning by building something
3:56:16
mfiano
So use Common Lisp to do the backend work. then you aren't writing a GUI...you are leveraging what you already use
3:59:51
matzy_
wow...so i could take a list of all sysem apps in cl, filter to get how i want, and then present in a cutom rofi window?
4:01:13
matzy_
this is an awesome idea. and really useful too, a perfec project to learn on. thanks a million for the idea man!