libera/#commonlisp - IRC Chatlog
Search
21:56:45
jcowan
I came up with an idea for a non-portable extension of CL. It may be doable with the MOP, but I never learned the MOP. It looks like this: (define-type-class name type-specifier). The instances of such a class are all the objects which belong to the specified type. Otherwise they work like built-in types (or perhaps I should say they are built-in types: no slots and no constructors. However, parent types are possible, in
22:00:07
hayley
(beach: For what it is worth, I would believe that the URL was an honest mistake on mfiano's behalf. Usually you don't see server URLs on Matrix, so it is hard to spot bad servers. And there are some of _that_ kind of person present in Lisp rooms; I know cause I had to get rid of some of them.)
22:01:10
Gnuxie
( there's some of those people lurking in this channel for sure for what it is worth )
22:03:23
hayley
What does rewriting the parent types achieve that inheritance doesn't achieve? Is it that classes defined with define-type-class don't inherit any slots or anything like that?
22:06:30
slyrus
any vellum and/or teddy users around? Other data-frame like libraries I should consider?
22:09:46
hayley
Right, I think it would be quite possible with the MOP. You could just rig COMPUTE-SLOTS to return the empty list.
22:11:34
hayley
If it was possible, I was going to use it for network proxying once, as I can handle everything else lazily.
22:13:18
jcowan
Anyway, I think the better approach is to say that where the type specifier of the class being defined is t_c and the type specifier of each superclass is t_s, then for each superclass, subtypep(t_s, t_c) returns T T.
22:14:49
hayley
That arrangement reminds me of stealth mixins, though you would reuse one mixin for multiple classes.
22:45:29
stylewarning
Are there any JSON libraries that let you customize the structure that gets built?
22:46:16
stylewarning
Everything I’m seeing let’s you do small customizations (like make an alist or plist, or use lisp booleans or symbols or …), but I’m not seeing anything that allows me to instruct the parser what exactly I want it to build
22:54:30
random-nick
stylewarning: going through the libraries on cliki, this looks like it lets you take parse events https://github.com/rotatef/json-streams
0:45:28
moon-child
on x86, why does cmucl generate code that pops the return address manually and jumps to it, instead of using the native RET instruction?
0:47:29
hayley
I've never used CMUCL, so I don't have the disassembly on it. But one thing which came up when discussing the calling convention of SICL was that you also have to pop more of the stack before returning.
0:52:20
moon-child
It's a shame; I understand there is a dedicated return predictor, which is being bypassed in favour of a (much harder to predict) indirect jump. I wonder how setting up the return stack manually at the call site would compare
0:52:27
hayley
The choice here was to put another location on the cold end of the stack, which we copy the return address to. While I guess jumping makes more sense, meddling with the stack to get RET to work makes some predictor work.
0:55:11
moon-child
https://twitter.com/ktemkin/status/1375835935061942274 I think this technique is faster than regular threading, which would indicate the return predictor can work without a corresponding call
0:56:54
moon-child
anyway 'A Last-In-First-Out buffer, called the return stack buffer, remembers the return address every time a call instruction is executed, and it uses this for predicting where the corresponding return will go.'
0:58:22
moon-child
hmm, if you do something like this: push L1; push arg; push arg; call func; L1: then you will have a redundant entry on the stack, but the return predictor will work correctly
3:04:11
beach
moon-child: What we do is leave a space right near the frame pointer, so we do push <arg1>, push <arg2>... call. Then we pop the return address and put it first in the frame. So then, to return, we first deallocate the arguments and then RET.
5:43:20
rain3
beach: is it a good idea to separate "add-mixin" out of define-stealth-mixin ? https://termbin.com/2o62 Sometimes I need to add to victim classes mixins which are already defined so I need this add-mixin
5:55:48
contrapunctus
I don't know anything about OOP in other languages, and all I know of OOP is basic CLOS. Is there anything I might read to understand what mixins are, and how they're created and used in CLOS?
5:56:33
beach
contrapunctus: Technically, they are just ordinary classes. What qualifies them as mixins is just conventional use.
5:57:39
beach
contrapunctus: They are not intended to be directly instantiated, and instead are used as superclasses to "normal" classes in order to capture common things between several "normal" classes.
5:58:26
beach
contrapunctus: Example: (defclass name-mixin () ((%name :initarg :name :reader name))) could be used as a superclass for both a PERSON class and an ORGANIZATION class.
5:58:43
mfiano
How does stealth-mixin differ from my solution? https://gist.github.com/mfiano/af1a31d1a4767834b96d39f425ee75e9
6:00:14
beach
mfiano: This is Monday and Monday mornings are chaotic around here. I'll have a look later, unless someone else gets there first.
6:00:46
beach
mfiano: But we had a paper published in the Australian Conference on Software Engineering on it some two decades ago.
6:02:05
moon-child
http://clhs.lisp.se/Body/m_pshnew.htm the first example here mutates literal data!
6:07:18
Alfr
It's only undefined, so some implementation might simply behave as shown in that example.
6:07:59
rain3
moon-child: see this example, for DESCRIBE-ing circular objects https://termbin.com/cabo add-mixin allows one to add an existing mixin that has behaviour defined through defmethod . It is different from using a #:dummy class which has no behavior
6:11:22
moon-child
mfiano: notably 'so that we retain the flexibility needed to update these sections even at the last minute without fear of needing a formal vote to change those parts of the document'. Given that, I think they are not intended to be unauthoritative
6:11:28
rain3
moon-child: how do you define methods specialized on objects of a class named #:dummy ?
6:12:16
moon-child
rain3: I meant that, instead of writing '(stealth-mixin:add-mixin 'safely-describe-mixin 'c1)', you can write (stealth-mixin:define-stealth-mixin #:dummy safely-describe-mixin c1)
6:14:49
rain3
okay got your point. btw add-mixin can be written as a function rather than as a macro
6:15:01
mfiano
moon-child: That quote is regarding front and back matter only. Examples only pertain to the rest of the section.
6:31:14
mfiano
#'MIX is the main interaction. It takes as arguments a standard instance and a standard-class type.
6:31:45
mfiano
It constructs a new anonymous class with the class of the instance and the class denoted by the type argument as superclasses
6:33:21
spiaggia
STEALTH-MIXIN adds a superclass to an existing class, so that client code can, say, add its own slots to a library class that wasn't designed for it.
6:35:45
mfiano
Yeah, same here. It's unfortunate because some slots with initargs may be implementation details not intended for make-instance to be used.
6:36:44
mfiano
Well all slots should be implementation details in my opinion...and I guess to make initargs "private" they'd need to be interned into the library package
6:37:29
spiaggia
I think it is fine if the client which defines the mixin use symbols in its own package only.
6:37:41
mfiano
The reason why I don't use this pattern much though, is due to something you hinted at above
6:38:46
mfiano
SBCL will emit a style warning if slots have the same symbol name but different package. I really don't want to wrap defclass in my own macro to muffle that, as most of the time the user will be defining their own mixin classes
6:40:19
mfiano
I have no idea. It's probably my biggest complaint about SBCL, as small of problem it is, it has a large effect on my codes.
6:40:27
spiaggia
I mean, to avoid the style warning, client code must know the implementation details of the library, which is contrary to the idea of modularity.
6:41:10
spiaggia
I would much rather have a style warning when a DEFMETHOD is used without a DEFGENERIC for the same function.
6:48:25
saturn2
newbies tend to assume exporting the class name from a package also exports all the slot names
6:49:46
mfiano
spiaggia: Why don't I remember seeing you here before in all the years I've been paying attention? Did you change your nick?
7:00:14
hayley
I think spiaggia uses spiaggia when he is strand(h)ed from the computer logged into beach all the time.
7:02:18
hayley
Put all blame on defunkydrummer, because he once called spiggia Robert Strandh"ed at the beach".
7:15:23
mfiano
I raised the topic (again) in #sbcl. If this behavior affects anyone else, I kindly ask you to voice your opinion.
7:17:53
spiaggia
I am accumulating evidence that the package system was used a lot less in the past, but I have seen no reason why that would be the case.
7:18:25
spiaggia
The naming convention for slot accessors in a bit older code is also evidence in that direction.
7:19:30
spiaggia
CLIM uses that convention, like SHEET-PARENT, and CLIM also has only two package defined by the specification, CLIM and CLIM-INTERNALS.
7:20:10
spiaggia
If I were to write the CLIM specification today, I would probably define many more packages; maybe one for each "module".
7:20:41
mfiano
I frown when I see the class prefix on accessor names instead of utilizing packages, at least for non-legacy code.
7:21:11
spiaggia
Yes, and it looks silly when inheritance is deep, like (SHEET-PARENT PANE) in CLIM.
7:22:46
Cymew
Hasn't Graham or someone else vocal described the CL package system as "somewhat weak" or words to that effect?
7:26:06
beach
If what you want is a module system, then it is weak. But if you use it for what it is, it is great. I think the two concepts are orthogonal.
7:29:23
Cymew
Personally I think the word "orthogonal" is overused, but otherwise my experience mirror yours.
7:31:22
beach
moon-child: A thing that can encapsulate sets of entities such as classes, functions, types, etc. As opposed to just map names to entities as the package system does.
7:32:42
hayley
beach: Silly question, have you read "Modules as Objects in Newspeak" <https://bracha.org/newspeak-modules.pdf>?
7:33:51
beach
moon-child: I am not sure I can formulate the argument immediately, since modules are so fundamental in programming.
7:34:00
hayley
In the code examples there is a "platform" object which is eerily similar to a first-class global environment, in my opinion. But this object is an explicit argument used when instantiating a "library" class, and not an implicit "argument" like the FCGE.
7:34:54
beach
moon-child: Let me give you an example instead: People often complain that you can't have two versions of the same library loaded into the same image, which is problematic because some client might want one version, and a different client a different version.
7:35:27
beach
moon-child: A module system would put one client and one version of the library in one module, and the other client with the other version of the library in a different module.
7:35:38
mfiano
beach: For what it's worth, I am familiar with modules, but I am curious to hear your thoughts as they relate to the missing Lisp piece (outside of FCGI)
7:36:13
hayley
The other difference is that a library in Newspeak is a class, where as a library in Common Lisp with first-class global environments is an effect on a first-class global environment, and the library is only reified if you use a fresh environment for each library.
7:37:22
mfiano
beach: How does that address the primary issue; colliding package names in the global environment.
7:38:03
beach
First-class global environments? Well, since they allow multiple global environments, that's how.
7:38:28
hayley
The solution is to give either client its own environment, where each environment has access to the desired version of the module.
7:39:37
mfiano
So you mean that I can refer to either package #:foo (in module A) or #:foo (in module B) in client code (or even both if that is your cup of tea)?
7:40:40
hayley
(I had to think this through as one day Gnuxie showed me the Newspeak paper, said modules-as-objects looked neater, and it took a while for me to figure what my gut told me when it said FCGEs could be made more ore less equivalent.)
7:40:41
beach
Right, each first-class global environment has its own mapping from strings to packages.
7:41:55
mfiano
That is much more useful that I originally thought about fcgi. I wonder what client code looks like for interacting with different gi's from user code
7:42:59
beach
mfiano: It would be used only fairly infrequently. I am not thinking of any fine-grain use of this feature.
7:43:56
beach
In fact, I invented it (jcowan says I "reinvented" it) to solve the bootstrapping problem, which requires me to execute SICL code in a host Common Lisp system, and to prepare for CLOSOS so that different users have different environments.
7:44:37
mfiano
beach: I am thinking as it relates to a "dependency manager" (as to not overload "package" from other languages), that supports versioned dependencies, where the transitive graph could include many of versions of the same library.
7:44:44
hayley
Another useful ability would be to share packages between environments, so that it is still possible to have another module which is a client of both of the forementioned modules.
7:45:28
mfiano
the client code here is the code that loads systems. the invidual systems can't be modified to refer to some particular gi
7:45:42
beach
moon-child: But all attempts I could find required a hash-table lookup for each function call.
7:46:04
hayley
In 20 years, we will surely have someone saying that you should explicitly prefix global environments somehow, rather than implicitly :use-ing environments :)
7:46:38
moon-child
beach: javascript 'requires' a hash-table lookup for every slot access. Obviously there are fast javascript implementations. I see your point, though
7:47:20
mfiano
beach: Yes I understand that. The issue is loading multiple versions of the same library, perhaps with the same package-name, into an image. The fact they came from a dependency graph is kind of irrelevant
7:47:28
hayley
Still, if you load each module into a fresh global environment, you more or less have module "objects".
7:47:38
mfiano
The point I'm trying to make, is the code being loaded is not aware of any environment
7:50:05
mfiano
This problem is why I gave up on my "quicklisp alternative" some years ago, and why CLPM opted to not recursively resolve manifest files.
7:51:32
beach
Also, I see first-class global environments as a safety issue. For SICL, I want to put all the code for the compiler in a separate first-class global environment, and then just import COMPILE, COMPILE-FILE, and EVAL to the default global environment.
7:52:23
beach
Then it would take an environment switch to alter the code generator, and presumably that switch is password protected, so that loading any arbitrary code can not easily alter the code generator.
7:52:23
hayley
Well, there may be a few things which appear to "break" if you go through environments in specific ways.
7:53:28
hayley
For example, a symbol from another environment might or might not have a function binding in the current environment, even if it was bound in the environment from whence it came. So using such a symbol as a function designator might not be a good idea.
7:55:12
hayley
But this kind of situation would probably only occur in my very absurd plan to use first class global environments as part of a Newspeak-esque module system, while still using modules written in normal Common Lisp.
7:59:17
beach
hayley: That would not happen in Clostrum environments. Code is "tied" to an environment when it is loaded, so references to named global functions are resolved then.
8:01:24
hayley
Right, but I don't think tying would affect something like having (defun f (symbol) (funcall symbol)) evaluated in one environment, and having (defun g () 'welcome-stranger) (defun h () (f 'g)) evaluated in another environment which a function binding for F.
8:02:13
beach
moon-child: There are certain aspects that we haven't worked out yet. For instance, I am not sure whether (SYMBOL-PACKAGE <SYMBOL>) could return a different package in different environments.
8:03:18
mfiano
beach: the style warning was intended to catch a hard-to-debug programmer-error situation: where they intended to extend a slot, but because of a package snafu ended up "silently" creating a new slot instead.
8:03:40
mfiano
The solution they want to take is to only emit it if the slot in question is exported, and thus not an implementation detail.
8:03:53
beach
hayley: Right, an example like that would go through FDEFINITION which will result in a hash-table lookup.
8:04:24
moon-child
it occurs to me that symbols not being closed over their environments is consistent. If you redefine a package, symbols which were already interned into it will continue to be
8:06:02
beach
moon-child: Like I said, I haven't imagined all possible scenarios. I think that more experience will be required to iron out the details.
8:07:00
beach
What I think I do know is that I don't want any "module prefix", so that one could say <module>.<function-name> or something like that.
8:07:09
moon-child
however functions _are_ closed over their environments. If symbols were too, then SYMBOL-PACKAGE would always have to return the same package regardless of which environment it were evaluated in
8:07:40
pve
I'm trying to understand these first class global environments. Would it be possible to implement them (meaningfully) as a library that could be loaded into any CL implementation?
8:08:14
beach
moon-child: Right. I am just explaining why I am unable to think very fast, so I don't have an answer to all potential issues.
8:08:34
moon-child
err, sorry, in 'symbols not being closed over their environments is consistent', 'environments' should have been 'packages'
8:10:03
beach
pve: Well, Clostrum is a library that implements first-class global environments, and we certainly use it during SICL bootstrapping to isolate the host environment from multiple SICL environments, but executing code relative to an environment currently takes a factor 4 or so performance hit compared to host code.
8:12:25
beach
pve: Essentially, every reference to a global function, variable, etc. in source code must be replaced by a load-time access to a particular first-class global environments in order to find "cells" containing the entity being referred to.
8:12:35
mfiano
Ok good, the stealth-mixins paper is rather short. I don't have time for too much attention today :)
8:12:52
beach
pve: And the way we do it now is to turn source code to a Cleavir AST, and then turn that to host code for compilation by the host compiler.
8:13:26
beach
pve: Probably, that process could be optimized a bit, but I have seen no reason for it, since it is plenty fast as it is for SICL bootstrapping.
8:15:07
pve
beach: Ok, I see. And is there any amount of package trickery (renaming packages etc) that could be done to "simulate" FCGEs (or a module system)?
8:16:01
beach
pve: Probably. That's what SBCL does for bootstrapping. I just found that unappealing which is why I didn't want it.
8:17:22
mfiano
Just noticed I said FCGI twice and GI twice instead of FCGE and GE. You know it's a Monday :/
8:18:05
moon-child
mfiano: oh!--I was trying to figure out what the present discussion had to do with fastcgi :)
8:18:31
hayley
beach: Yeah, and so if someone wrote a module which actually relied on passing around symbols as function designators, they would find that the program looks for the FDEFINITION in the "wrong" environment.
8:18:39
beach
So a typical SICL "module" (now "module" means ASDF system definition plus package definition) has a package definition that :USEs only the CL package, and every component starts with (cl:in-package <module-name>), like (cl:in-package #:sicl-array) for instance.
8:19:51
beach
hayley: I don't think so, because FDEFINITION would be in a particular environment and it would look for functions in that environment.
8:20:42
beach
hayley: So code doing (FDEFINITION 'FOO) would be loaded into some environment E, and FDEFINTION would be resolved to the one in E and functions returned would be those in E.
8:20:43
mfiano
moon-child: Yeah, that is why I probably made that connection...I am not completely with it yet today.
8:21:40
hayley
I would expect FDEFINITION to look for the function in the former environment (which we evaluated the (defun f ...) form in), and so it would be unable to find the function named G in the latter environment.
8:23:32
beach
hayley: In your example, it would be the G in the environment that FUNCALL is taken from.
8:23:39
mfiano
beach: Not everyone uses Emacs, or a client with abbreviations. Some people prefer the typewriter experience :) I for one, despise Emacs, and only use it is a barely sufficient means to interact with CL.
8:25:17
hayley
On the other hand, expecting FDEFINITION to work across environments would require some sort of ambient authority (probably by unnecessarily sharing bindings for H between environments somehow?) so I'm theoretically fine with that. I'm, however, less fine about how normal Common Lisp code might expect such code to work.
8:26:31
rain3
I only recently have started using emacs without 'evil-mode' . I had been under the impression that it is not possible, because vi was my first editor and my psyche shaped after it
8:27:47
mfiano
rain3: I took the opposing path, because years of non-evil Emacs use has hurt my fingers.
8:27:47
beach
Here is my opinion: First-class global environments solve a real problem for bootstrapping, and also likely for a multi-user Common Lisp system. But there are details that need to be figured out. Either way, it will work better than without them. My brain is too small to figure things out a priori, so it is fine for others to try that, but I am not going to be much help at this point.
8:29:03
rain3
abbreviations and hot keys are so useful that they should be available even across clients= the operating system/a background service should deal with them
8:29:16
hayley
I agree. Really I'm only doing stupid thought experiments and wondering why they run into stupid problems.
8:29:52
mfiano
contrapunctus: Plenty of reasons, such as its terminal mode not supporting truecolour unlike vim, or font-locking being unbearably slow compared to Vim on old hardware/large buffers. Mostly though, I just prefer the UNIX philosophy, so shoot me
8:31:13
beach
rain3: I get very angry every time I use (say) bash, and don't have the spell checker or the abbrev processor.
8:31:29
contrapunctus
rain3: I've recently used this program called kmonad to do some crazy (/s) things like having Space act like Ctrl when held down, and Shift to insert () when tapped. Might be pretty good to avoid the Emacs pinky, too.
8:31:51
akater[m]
I'm only interested in Lisp because it makes environments like Emacs possible. (Or rather, I'm only interested in programming because of that.)
8:32:39
beach
akater[m]: Yes, it seems clear from your utterances that you are not particularly interested in Common Lisp as such.
8:33:40
hayley
Does "only" qualify that you don't have any other reasons to be interested in Lisp, or that the reason is unique to Lisp?
8:34:32
contrapunctus
mfiano: I do feel a little dissatisfied with Emacs in that it does not have much in the way of means of composition for users. Perhaps keyboard macros, at most.
8:34:48
hayley
I would joke and say "I'm only interested in Lisp because it makes environments better than Emacs possible", but the same could be achieved in Smalltalk, and it is not the only reason that I like Common Lisp.
8:35:17
lisp123
I was thinking today, Elisp is basically an 'embedded language' in Common Lisp, that's my new company line on the two - Elisp is for the most parts well designed for customising text editors
8:35:22
contrapunctus
mfiano: Interop between Emacs packages happens by conscious design, not automatically through the design of the environment.
8:35:34
mfiano
contrapunctus: My opinions are mine and just that, opinions. Please don't take this as the start of a holy war. I accept that I have to use it, and I get by with things like evil-mode, even though it is barely acceptable to me.
8:35:40
rain3
I have made my own tool with common lisp that can program any additional usb keyboard . It doesn't support abbreviations yet or key combinations , but I can program any single key to do execute arbitrary common lisp code (including code that simulates text typing and pressing key combinations ,since that was the primary purpose of this program)
8:35:45
beach
hayley: Well, your phrase means "I am only INTERESTED in Lisp...", as opposed to also being (say) INVOLVED in it.
8:36:52
contrapunctus
mfiano: you shared you dissatisfactions with Emacs, I'm sharing my dissatisfactions with Emacs...where's the "holy war"? 🤷️