libera/#commonlisp - IRC Chatlog
Search
10:19:21
beach
gilberth: Maybe you said this already, but do you have plans to include more stuff into the Nova Spec? Like MOP stuff?
13:01:21
dnhester26
does anyone here use package-inferred-system to avoid having to specify every file in .asd?
13:01:34
dnhester26
I have a question about the docs: https://asdf.common-lisp.dev/asdf/The-package_002dinferred_002dsystem-extension.html
13:02:08
dnhester26
it uses :use-reexport in the all.lisp examples. Wouldn't it make more sense to use :import-from to avoid collusions?
13:02:48
beach
Some people do, but I don't. I forget exactly why. Is it that each file must be in its own package?
13:04:54
beach
I just remember that there was some ridiculous (to me) limitation that I couldn't accept.
13:07:20
yitzi
The idea of putting an entire package in one file is absurd. As is the idea that there is a one-to-one correspondance between packages and systems. Its just a terrible idea, imho.
13:08:59
pfdietz
I've used p-i-s. Sticking everything in a single file is a downside. It would be nice if there were a way to have the best of both worlds. Maybe associate packages with directories, not files?
13:09:05
yitzi
Yeah, I don't even like Lisp files that more then a couple hundred lines long. That is what separate files and hierarchical files systems are for.
14:28:50
dnhester26
yitzi: can you please explain why not use a package per file? why is it absurd? Sorry if it seems dumb, I'm just coming from a java python background where every file pretty much is it's own package. lisp packages have nothing to do with that because they are ways of bringing symbols together, but java to the extreme every file is pretty much just a class, and you import based on the directory path to get the class. it's pretty stra
14:28:50
dnhester26
ightforward and removes the need to write a build file like .asd, which is what's bothering me a lot
14:29:29
dnhester26
How can I sensibly build .asd files? I would like a simple tutorial. I was going through https://github.com/robert-strandh/Cluffer/blob/master/cluffer.asd
14:29:31
paulapatience
Does LDB treat integers in two's complement notation? E.g., is (ldb (byte 8 0) -1) guaranteed to be #xFF?
14:29:40
dnhester26
so each folder has it's own package: https://github.com/robert-strandh/Cluffer/blob/master/Base/cluffer-base.asd
14:29:59
paulapatience
Section 12.1.1.3.1 says the logical operations do, but makes no mention of it in 12.1.1.3.2 for byte operations.
14:30:11
dnhester26
asdf just finds it because it's a .asd file even though it's not on the same directory it doesn't matter, it just traverses searching so I don't have to worry about it. Correct?
14:34:08
yitzi
dnhester26: Putting a single package into a single file is only appropriate if the package is very small in terms of the lines of code. For anything else more than ~500 lines of code it can be confusing (at least to me) to have it all in the same file. Instead break it up into logical groups of functionalitity for each file. common-lisp is a single package, can you can imagine the entire code-case of a CL implementation being in a single file?
14:34:11
dnhester26
beach: here https://github.com/robert-strandh/Cluffer/blob/master/Base/cluffer-base.asd you load packages.lisp first, and here https://github.com/robert-strandh/Cluffer/blob/master/Base/packages.lisp you export the symbols that are not yet defined. I think doing that in sbcl for me gave me warnings (is that correct?) is that normal programming style? will it not lead to an error?
14:35:37
dnhester26
yizti: what is the meaning of a package beyond a grouping of symbols? when I think of a package I think of a group of symbols that provide certain functionality, but according to that each file you are describing should be in it's own package. Why keep them all in one package?
14:40:01
yitzi
I think having larger packages versus lots of smaller ones is pretty subjective. I just try to group them by the logical functionality groups that help me visualize the problem.
14:42:46
beach
dnhester26: When you :EXPORT something, you give it a string designator, so that will create the symbol in the package you are defining, or export an existing symbol otherwise available in the package.
14:43:53
beach
dnhester26: You can think of the package as the unit of encapsulation. It says what symbols are available to client code.
14:44:55
beach
dnhester26: But most of the time, the definitions named by those symbols, like functions, classes, types, etc., represent a lot of code, and it makes sense to put them in separate files.
14:45:55
beach
dnhester26: For example, you might want one file with definitions of generic functions without associated methods, and another file with class definitions, and a perhaps several files with method definitions for the generic functions.
14:47:50
beach
dnhester26: In other words, the Common Lisp package system plays the "encapsulation" role of classes in most object-oriented languages, whereas Common Lisp classes play the role of the "representation" role of the classes in those languages.
14:48:37
beach
dnhester26: It is a dumb idea to have both encapsulation and representation represented by the same language element. That's probably why code in traditional object-oriented languages get very complex.
14:49:34
dnhester26
is there a way around having to define the .asd build files with serial or depends-on? In a lot of other languages, the build is just implied by the way the code is written without having to explicitly state it
14:50:16
dnhester26
why is it a dumb idea? because encapsulation is not for all other classes, just the ones outside of that particular functionality?
14:52:42
beach
In Common Lisp, you typically have several classes defined in a single package, because all those classes are logically part of the same "module".
14:52:56
dnhester26
I get errors all the time from defining circular dependencies or forgetting to add the line and I just find the whole managing of a massive file of dependencies a pain. But I can see that I may have been structuring my code in the wrong way, I just don't see any explanation on the correct way. I'm reading your cluffer to try to understand how. Making a system per folder seems more sensible and I guess forces that all those files be
14:52:56
dnhester26
either completely independent of another folder, or if dependent, the other folder cannot depend on it...
14:53:52
beach
dnhester26: Yes, the way I organize my code is that a directory contains the code of one "module" and that "module" is defined by an ASDF system definition and a package definition.
14:54:39
dnhester26
flexibility in terms of what? having another class within the same module access the first classes slots yet at the same time not export the slot accessors from the package so that classes outside the package should not access it as a first measure?
14:55:33
beach
So in my code, the dependencies are either between modules, as stated in the ASDF system definition, or between files in a module, which I usually turn into a :SERIAL T dependency for simplicity.
14:56:27
yitzi
dnhester26: You don't have to put the asd in the same directory. Its just my preference, but I put all of the asd files in the root directory and use `:pathname` to map to subdirectories. I like this because I can look in the root directory and see all the systems that are defined. https://github.com/s-expressionists/Inravina/blob/1d4439fe3cf982a6a2a542b4a17abc985a61d4ee/inravina-extrinsic.asd#L11
14:56:27
dnhester26
so module is really a whole working component of a project. In a web app with a model view controller type design, it doesn't make sense then to have those 3 folders mvc, it would be more like a module for authentication with a folder for it and it's mvc files inside that folder, and then each part of the code that can be broken up would get it's own module. right?
14:56:49
beach
dnhester26: Classes in Common Lisp are very lightweight. It is common to define a bunch of "mixin" classes, for instance, and they often play not important role to client code.
14:59:13
dnhester26
thanks, I'm just trying to understand how to structure my code, break up the 40 files in the asd file I have into multiple systems so that it's easier to manage. it's just a model view controller, it's not particular to web apps, desktop apps and anything that wants to separate concerns for displaying data (views), doing business logic (controllers), and data representation (models) has it..
15:00:52
dnhester26
ok, thanks, this was instructive. I wish there was a tutorial or explanation at length of this somewhere. Even if it's an opinionated tutorial, it's better than no tutorial. it's just that the approach is so different from say java python and other languages I've programmed in, that I find it hard to guess the concepts
15:01:30
beach
Yes, it is different because the Common Lisp object system is very different from that of most languages.
15:01:59
dnhester26
beach: a module for each model you mean the whole class, logic for processing that data in the class instances, and the code for displaying it, all in one package and system. Is that what you meant?
15:02:56
beach
And I don't know why you talk about "class" here. The module contains what we call a "protocol definition", which is a generalization of an interface.
15:03:04
dnhester26
This difference between encapsulation and representation, once you mentioned it in regard to the packages, I understood what you meant, but without thinking about it, I was not aware. I should really read the Keene book you recommended. It's the tradeoff of trying to be productive and code vs taking the time to read that is hard
15:03:49
dnhester26
beach: I've no idea what this means in our context: "The module contains what we call a "protocol definition", which is a generalization of an interface."
15:04:22
beach
So a protocol contains classes, functions, types, method combinations, variables, etc. that client code can use in a coherent way.
15:06:09
beach
The documentation of a protocol explains the relationship between those elements, like how to create instances of the classes, what class instances can be passed to what functions, what objects those functions return, etc.
15:06:44
beach
It also explains what kind of subclasses client code can create and what methods it must then supply.
15:09:33
beach
dnhester26: I have an idea. Eclector is a program that implements the Common Lisp READ function. It is highly configurable. It is also well documented. Perhaps you could look at the documentation to get an idea of the concept of a protocol.
15:10:22
dnhester26
yitzi: trying to make sense of https://github.com/s-expressionists/Inravina/blob/1d4439fe3cf982a6a2a542b4a17abc985a61d4ee/code/extrinsic/packages.lisp you are exporting a bunch of symbols, only a few were shadowed and very few defined in print.lisp. Does that mean you are then just exporting a bunch of common-lisp symbols you are "use"ing?
15:13:04
dnhester26
beach: thanks, I will take a look. I was reading cluffer for an idea of how to structure the code. eclector shows how the code comes together in a protocol. Is this way of using a common lisp way of using it or is it your personal definition?
15:14:43
beach
dnhester26: Oh, another important document is the CLIM II specification. That's how I learned about how to use CLOS and CLOS protocols.
15:15:42
yitzi
dnhester26: I was only using that as an example of `:pathname`. That is system is implementing part of the CL spec inside a host implementation so it is a bit unusual in the export list. The actual functions are created by a macro, so its not immediately obvious on first glance.
15:17:22
beach
dnhester26: Speaking about dependencies, I don't see a general way of inferring the dependencies between the components (files) of an ASDF system.
15:17:29
scymtym
dnhester26: eclector mostly shows my preferred style. for example, the ASDF system definitions are in the project root directory. but beach, yitzi and i all use one directory per module and often but not always one file per aspect within such directories like "conditions.lisp", "generic-functions.lisp", "classes.lisp"
15:18:22
beach
scymtym: I was pointing to Eclector mainly for the documentation, but that's a good point.
15:20:41
yitzi
I second that. Part of understanding how a system functions is building a mental map of where that functionallity is located and good names like scymtym suggested are really key to that for me.
15:24:40
dnhester26
beach: yuo learned from reading the specification or from coding in the project?
15:26:22
dnhester26
yitzi: yeah, ok, I was just reading it to understand what the defpackage was doing in general. That was a different file from the one you sent me. thanks
15:31:18
dnhester26
scymtym beach: ok thanks, so read both the docs of eclector the the code to understand what a protocol is and how to break up the code in modules. CLOS and CLOS Protocol: read the CLIM II specification for the docs or the code?
15:32:52
dnhester26
so there is no way in common lisp unless we modify somehow how we program to avoid writing a build file?
15:33:55
scymtym
dnhester26: the CLIM II specification doesn't have any code besides examples. i just describes how a CLIM implementation is supposed to work and be used. the described functionality is broken down into named protocols like here: http://bauhh.dyndns.org:8000/clim-spec/8.html#_294
15:52:12
beach
In particular, I learned from it that slots are implementation details and that classes are defined by a name, the initargs, and the functions that can take its instances as arguments.
15:53:35
beach
That way, whether some datum is stored in a slot or computed, is of no importance to client code, and the module can change between the two without informing the client.
15:54:05
beach
An "implementation detail" is something that is private to a module and not part of the protocol.
15:55:46
beach
So, for example, if you have a class PERSON, you may have two functions DATE-OF-BIRTH and AGE, but you have no business knowing whether one of them is computed, nor which one in that case.
15:56:08
dnhester26
oh wow, even public fields in say another language, here in CL we are saying there's really no such thing? it's only relevant to export a function from a class for accessing and setting the slots
15:57:22
dnhester26
interesting. i guess in java the practice was to make getters and setters instead of public fields, which seemed to accomplish the same thing, but it basically allows for changing the internal representation of the data as long as the public function interfaces stay the same, so here too
15:59:43
beach
For example, if a PERSON has an ADDRESS, you might have a function named ADDRESS that takes a PERSON object, and a function named (SETF ADDRESS) that updates the address. The latter would be used with SETF like: (SETF (ADDRESS JANE) <new-address>)
16:00:23
beach
And since packages are all about symbols, both those functions can be used by client code if the symbol ADDRESS is exported.
16:01:12
beach
But whether the address is stored in a slot of the PERSON object or in a hash table, or somewhere else, is irrelevant to client code.
16:02:12
aeth
yes, set-foo is (SETF FOO), get-foo is FOO, and the API is ideally the same except the SETF function (it doesn't have to be a function, though, since you can define your own in one of 3 ways) just takes in one extra argument, but the syntax of calling a SETF function puts that later
16:03:12
beach
And I have the impression that get-foo and set-foo are used only to access fields, in which case it is again blatantly obvious what is stored in a field and what is not.
16:04:30
aeth
Since there's no separate dot notation, either, the syntax is entirely uniform and (foo bar) and (setf (foo bar) 42) could be anything.
16:04:47
reb
Regarding the uniform access principle page wikipedia page. It's sad there's no Eiffel example. With Eiffel foo.bar can either mean "access the bar field of object foo" or "call the bar method of object foo", which allows refactoring fields into zero-parameter methods and vice versa.
16:04:56
aeth
You can even obscure the constructor with MAKE-FOO in which case it's not clear to the user any implementation details at all
16:05:55
beach
reb: But Common Lisp is even better, because slot accessors are just functions that can be mapped over stuff like lists.
16:06:41
beach
reb: That's why initial attempts at Common Lisp object systems were rejected, because they had a different syntax for slot access.
16:09:19
aeth
Seems to be an issue with the Wikipedia article that it's missing Eiffel and CLOS examples.
17:02:43
dnhester26
beach: aeth: thanks for your explanations. sorry for the late reply, I had to jump to a meeting
18:49:52
yottabyte
in my function I see an underline in emacs saying undefined variable and undefined function in my package, but they're not, indeed the function works as expected. it seems like it's just lost or not keeping track of things correctly. has anyone experienced this before?
19:05:35
pfdietz
Something like design by contract should be achievable with method combination. For example, preconditions/postconditions/invariants in :around methods.
19:07:56
aeth
preconditions can be enforced entirely by the type system if you force type checking (which sadly needs to be done via the MOP) because e.g. SATISFIES types
19:10:17
aeth
that gets rid of 90% of the :before or :around methods you'd want, for constructors and accessors