freenode/#lisp - IRC Chatlog
Search
8:44:42
schweers
dim: I normally don’t need this information, it is just for debugging purposes after the fact. I want to know if I accidentally used the wrong settings.
8:52:01
splittist
Having read (well, skimmed) the 'proceedings', I wonder if ELS could take a stand for abandoning double-column article format (especially with CL's appropriately-descriptive-identifier-style.
8:52:45
beach
splittist: That would make it more difficult to be associated with the ACM, I would think.
8:54:28
splittist
What a twisted web. And to think some academics give advice on how society should be ordered... (:
9:01:31
splittist
They could pretend they were writing for the Journal of Computing and Cultural Heritage (not too far from the truth); the ACM allows a single column format for that...
9:06:25
pjb
schweers: note that this requires that you reset *gensym-counter* when you compiled the file! ccl seem to have reproducible builds, but I don't know if that's the case with sbcl (often compiler added a time-stamp…)
9:14:40
jackdaniel
reproducible builds are a nice quality but it is not incorrect to have them not being reproducible
9:22:28
schweers
pjb: I’ve successfuly loaded your code into a fresh image. I’m not sure about your example usage. why do you do this? (load (compile-file "~/o"))
10:20:34
refpga
Hi, is cl-graph appropriate for creating an N-ary tree? Are there any better alternatives?
10:27:01
pjb
minion: memo for schweers: I put the code in ~/o.lisp; (load (compile-file "~/o")) is to load it; the following form is to try it on ~/o.dx64fsl or whatever fasl file it is.
10:42:29
fivo
Why does READ continue to return nil if I run (setf *read-suppress* T) (setf *read-suppress* nil)?
10:54:15
Xach
> If the value of *read-suppress* is true, read, read-preserving-whitespace, read-delimited-list, and read-from-string all return a primary value of nil when they complete successfully
10:54:39
Xach
fivo: after that, the R in REPL returns NIL all the time, so the E can't do any more meaningful work.
10:55:53
fivo
ok I have to get used to that the stuff I modifying also concerns the REPL I am playing around with
11:18:31
Xach
fivo: the bare SBCL repl (but not slime) will catch some things and prevent you from making it unusable
11:18:56
Xach
fivo: but not all things. and there may be ways to recover even if you get things somewhat wedged.
11:21:20
pjb
fivo: hence the use of local bindings! (let ((*read-suppress* t)) (read-from-string text))
11:21:54
Xach
for example, you can enter the debugger with C-c C-c and use : to eval (mapcar (lambda (thread) (setf (sb-thread:symbol-value-in-thread '*read-suppress* thread) nil)) (sb-thread:list-all-threads))
11:26:30
selwyn
is it practical or advisable to do image-based development using modern CL implementations? in particular I wonder whether anyone here does this
11:26:58
selwyn
my main fear is borking the image due to some incorrect CFFI call but perhaps there are other drawbacks to the approach
11:30:37
jackdaniel
since your program evolves as you go (i.e you may modify function and compile function which got inlined somewhere), it may be hard to reproduce problems
11:31:33
jackdaniel
or you may use some macro to compile function you use later, then change this macro definition - then your function can't be recompiled, so your program state is not reproducible
12:03:13
pjb
selwyn: I don't think a lot of people do image based development. However, have a look at Image Based Development http://www.informatimago.com/develop/lisp/com/informatimago/small-cl-pgms/ibcl/index.html
12:04:02
pjb
selwyn: the main problem is that we are using posix system that are file based, and we want to keep the sources in files. So all the modifications made in the image have to be saved to files. (and then, commited to git).
12:04:46
pjb
selwyn: however, there's a cl git library. Perhaps you could use to access to the git repositories directly from the lisp image, and pull and push without going thru the posix file system.
12:05:49
pjb
selwyn: some CL implementations let you save an image without killing lisp. In the others, you can usually fork(2) before saving the image, so you can keep working in the parent.
12:06:10
pjb
selwyn: saving the image often will let you fall back to the last snapshot in case of borking.
12:07:42
pjb
selwyn: using image based development usually has the drawback of non-reproductibility. Since we keep mutating the image, we can make it evolve in ways that are not available to batch compiling and loading of systems (eg. thru asdf). Nowadays, being able to reproduce identical build has become an important feature, to ensure the security and validation of binaries.
12:08:26
pjb
But if we worked on image based development tools, I'm sure these problem could be solved.
12:09:33
schweers
I like that we can have both in lisp: build procedures suitable for batch runs, but also load them into an image to work on them interactively. I don’t see a reason to abandon any one of those qualities.
12:09:33
minion
schweers, memo from pjb: I put the code in ~/o.lisp; (load (compile-file "~/o")) is to load it; the following form is to try it on ~/o.dx64fsl or whatever fasl file it is.
12:10:07
schweers
ah, right. pjb: when I tried your code, it just compiled for ages (seems that emacs didn’t like the excessive output), and didn’t print or return anything meaningful :(
12:10:22
pjb
selwyn: or more precisely, ecl doesn't save lisp images. A new lisp image is built each time you initialize ecl (cl_boot).
12:10:50
pjb
schweers: be careful not to put recursive load or compile calls in sources. They were in comments.
12:20:39
schweers
yeah, but it doesn’t seem to print or return anything useful, which seems weird, looking at the code.
12:23:44
pjb
schweers: if it returns NIL, it means that it found no corresponding combination, therefore it means that the build is not reproducible.
12:25:20
Josh_2
Literal worse time for a game jam xD for me my deadlines are the end of this month and the start of next
12:37:15
selwyn
thanks for the replies everyone. did image-based development used to be more popular than it is now?
12:46:23
makomo
jmercouris: the initform is just that, a form ("expression") used to initialize the slot
12:47:27
jackdaniel
or, if you really want to mimic a reader: what you really want is (defmethod name (object) *global-var*)
12:47:32
jmercouris
I'm doing a lot of objective-c lately and the two things are messing with my mind
12:47:54
jackdaniel
or, if you want to do something silly don't initialize the slot and define slot-unbound method which returns *global-var*
12:48:13
jmercouris
Nope, won't do that, already have a solution in mind that doesn't commit war crimes :D
13:00:46
pjb
For example, the Patchwork application was developped in mcl on Macintosh this way. I had a lot of work to unravel the dependencies to be able to write an asd file to compile it separately.
13:01:33
pjb
Smalltalk systems are still heavily image based in general (gst is an exception). Smalltalk includes methods to save the code to files…
13:02:45
pjb
selwyn: so it was common to see in lisp applications both a repl and a command to save a new version of the application (a new image).
13:05:11
pjb
fivo: you can use fork and exec. It's not standard, but you can get them by FFI (or thru a sb-posix or posix package). or you can just use uiop:run-program.
13:05:53
pjb
fivo: eventually, sicl will provide environments allowing us to implement this kind of feature.
13:06:45
dlowe
you want some kind of intermediate step between unread and read into the global environment?
13:06:49
pjb
(let ((list (in-separate-environemnt (read-from-string "(alexandria:flatten '(1 (2 3) 4))")))) …)
13:07:19
pjb
But notice that to implement in-separate-environment, if we use a system with separate address spaces, then we will have to serialize the result and read it in the current image.
13:08:31
pjb
If you use fork/exec, you may also use mmap, and copy the data thru memory, but you still need a serialization (you may use com.informatimago.common-lisp.heap.heap).
13:10:26
fivo
I the end, I want to process lots of lisp files with READ and don't want to quickload all the libraries involved.
13:11:11
pjb
You cannot use CL:READ, but you may use com.informatimago.common-lisp.lisp-reader.reader which let you hook your own tokenizer.
13:12:43
selwyn
pjb: i see. it seems very difficult to me to create image-based tools that scale to larger numbers of users. imagine two users make independent changes to parts of a lisp image. how could one do 'git merge' on images? and worse, how to resolve conflicts?
13:13:33
pjb
selwyn: you wouldn't do it at the image level. You would keep a file system inside the image. You would edit the sources inside the image, and use git to commit and push the modifications.
13:13:57
fivo
But you are saying I only have the options FFI and uiop:run-program if I don't want to keep all the libraries in my image?
13:14:16
pjb
fivo: Once I started a VFS: https://github.com/informatimago/lisp/tree/master/future/vfs
13:14:44
pjb
fivo: it's not finished; it could be completed rapidly, using gray streams (which I didn't want to use at the time).
13:15:52
pjb
selwyn: Once I started a VFS: https://github.com/informatimago/lisp/tree/master/future/vfs
13:15:58
pjb
selwyn: it's not finished; it could be completed rapidly, using gray streams (which I didn't want to use at the time).
13:16:12
grewal
fivo: I don't understand what you're trying to do. If you want to use the libraries, you'll have to have them loaded
13:16:36
Xach
fivo: mainly because it is difficult in some cases to process project source code without loading the project
13:16:49
pjb
grewal: i think he wants to read sources without loading the dependencies. For this, you need to parse foo:bar without interning bar into a package foo.
13:17:08
pjb
So you need a hook in the reader to return an object of your own class when you read foo:bar.
13:17:16
Xach
i run sbcl as a child process and instruct it to load a project, then load my analysis code, which saves its results somewhere.
13:17:58
pjb
In any case, it's limited, because reading lisp sources requires evaluating arbitrary lisp expressions (reader macros, macros, etc).
13:18:30
dlowe
it's theoretically not possible to robustly process source code without loading its dependencies because of evaluation during read-time
13:28:19
selwyn
it is in any case not all of the information contained in a common lisp symbol, besides home package, symbol-function and so on
13:29:46
selwyn
i feel that this approach will run into problems, because common lisp symbols are more than just names. for a start, 'flatten' is not necessarily 'from' alexandria, what matters is that it is exported from alexandria
13:30:22
beach
fivo: What will you do if someone imported the symbol FLATTEN from the package ALEXANDRIA and just wrote (flatten ...)?
13:30:29
selwyn
it's quite possible that a package selwyn will export a symbol selwyn:flatten which is actually the same symbol as alexandria:flatten
13:31:32
selwyn
in which case, only taking the names of the symbols into account would not correctly tell whether the symbols were different or not
13:32:50
fivo
whenever somebody writes (flatten ...) and has uses :alexandria I want to get the information
13:33:30
beach
fivo: That's some pretty sophisticated information to derive without loading the systems.
13:34:33
pjb
This is something that has already been done with my reader. Unfortunately, I don't remember who did it.
13:34:37
fivo
so alexandria is in quicklisp so that is probably easier then the case where the package is no
13:38:38
selwyn
one would have to deal with unloading dependencies of a given quicklisp system in a sensible way that doesn't break the image
13:38:47
pjb
(progn (setf (com.informatimago.common-lisp.lisp-reader.reader:readtable-parse-token com.informatimago.common-lisp.lisp-reader.reader:*readtable*) (function print)) (com.informatimago.common-lisp.lisp-reader.reader:read-from-string "alexandria:foobar")) #| ("ALEXANDRIA:FOOBAR" . #(6 8710 518 6 6 6 4614 6 6 6 8 2566 6 6 6 6 6)) --> nil ; 17 |#
13:41:19
Xach
fivo: that is an interesting project, and my experience on similar (but not the same) things in the past has led me to the approach i described above: start a subprocess, do some work, dump the data, repeat.
13:41:20
selwyn
fivo: if i understand your problem correctly, i would do something along the lines of Xach's approach, to run sbcl as a child process, load the project and collect the results
13:45:46
selwyn
this is roughly what i do to test if libraries work in clasp. i wouldn't want to worry about whether things are properly unloaded (even if i could unload libraries) i would rather have the peace of mind of knowing a library loads into a fresh lisp image
13:51:23
pjb
actually: (progn (setf (com.informatimago.common-lisp.lisp-reader.reader:readtable-parse-token com.informatimago.common-lisp.lisp-reader.reader:*readtable*) (lambda (token) (values t token))) (com.informatimago.common-lisp.lisp-reader.reader:read-from-string "(alexandria:foo 1 2)")) #| --> (("ALEXANDRIA:FOO" . #(6 8710 518 6 6 6 4614 6 6 6 8 2566 6 6)) ("1" . #(6)) ("2" . #(6))) ; 20 |#
13:52:08
pjb
the parse-token function takes a token (cons string attributes), and produces (values t object) or (values :eof) or (values nil (list of objects)).
14:41:14
Xach
I think it would be *great* to have reliable clean unloading of projects! I just don't see how that destination could be reached.
14:42:24
jackdaniel
Xach: in principle ECL could unload fasls which are .so objects underneath. that said devil would probably be in details
14:44:09
Bike
side effects from them would still remain though, right? you'd have to restrict what code you can have in libraries.
14:45:08
jackdaniel
yes. also there are gotchas like: module defines a class, you create an instance of this class
14:48:56
dlowe
if you had a dependency graph, you could require that all dependant modules be unloaded
14:53:34
Xach
I am worried about the thinking traps of "that would be hard to do in Common Lisp so it must not be worthwhile" or "if it were worthwhile to do someone would have done it already"
14:54:25
dlowe
A true rollback could look like moving all objects into the permanent heap and then saving the top of the permanent heap.
14:57:12
Bike
maybe you could just have unloading (assuming no major side effects not covered by def-whatever) mean everything becomes collectable normally, so basically just deleting the packages
14:59:52
beach
I think first-class global environments would be a solution, but we have not packaged them up in a way that they can be used by any implementation or any applications.
15:01:44
dlowe
beach: I was thinking about that, but to get data out of them may involve pulling a lot of other things
15:17:31
pjb
Unloading systems could be achieved if loading systems didn't mutate the global state other than creating new packages.
15:18:06
pjb
and otherwise, undoable mutations. (eg. adding a system object to a list of loaded systems).
15:23:04
selwyn
some common lisp implementations are designed with speed in mind, others with a view to extensions to FFIs in languages like java or c++
15:24:23
selwyn
my question is: has anyone attempted to produce a common lisp implementation which has the aim of being as ansi-compliant as possible as the primary aim above all others
15:25:28
selwyn
(this is not meant as a comment on ansi-compliance of CL implementations around today)
15:42:38
selwyn
beach: i ask because i thought that such an implementation would be of great utility to those who value correct program behaviour higher than execution speed
15:45:05
jackdaniel
otherwise expt would be defined (defun expt (x y) 42), incorrect but insanely fast
15:47:04
selwyn
yeah after i ask i realise that a speed improvement that breaks compliance would probably not be very wise, useful or popular
15:48:13
pfdietz
What you may be asking for is an implementation that strongly rejects programs that have behaviors that aren't specified or defined by the standard. But this would mean you couldn't use pathnames (for example), as they are poorly specified.
15:53:51
sjl_
It could be nice to have a CL implementation that took as many liberties as possible while still adhering to the standard, e.g. where (/= (char-code #\b) (1+ (char-code #\a))
15:54:48
sjl_
Such a HellCL could be useful to run your unit tests, to see if you're relying on anything not-standard-but-happens-to-work-in-most-implementations
15:55:24
Xach
sjl_: I was thinking about the opposite, codifying common practices like that in a test suite or something.
15:58:48
Xach
sjl_: i mean stuff like unicode code points for char-code/code-char, (unsigned-byte 8) arrays reading and writing as you'd expect
16:05:55
sjl_
Oh, so you could run the suite in a new implementation and get advance warning of pitfalls to watch out for?
16:06:07
sjl_
Yeah, that would be useful too. And way less work than making a full implementation of CL.
16:08:33
sjl_
predicates returning random stuff other than t for true cases would be another fun one.
16:12:30
p_l
sjl_: actually, ECL compiled with certain options on one of them *should* fail (= (char-code #
16:14:34
sjl_
but I'm sure there something like (position t (mapcar #'stringp '(a b "c"))) out there in the wild somewhere
16:15:09
sjl_
Josh_2: they return a "generalized boolean", which is either NIL (false) or anything-thats-not-NIL (true)
16:16:26
p_l
at the very least all standard library functions that want predicates accept a generalized boolean
16:18:21
sjl_
(when (eql (stringp a) (stringp b)) (print "a and b are both strings, or both not strings"))
16:21:04
sjl_
or perhaps a slightly-less-arbitrary way to implement stringp with non-eql results: (defun stringp (o) (if (typep o 'string) o nil))
18:45:20
aeth
I seem to rely on booleans (rather than generalized booleans) in two cases: (1) I'm storing something so the general boolean value would just be unwanted noise, e.g. something with :type boolean in e.g. a struct; or (2) I need to make a distinction past just having true/false, so e.g. keywords and t and nil all have some meaning in the API.
18:46:06
aeth
(for the second one, consider an API where t is default, nil disables it, and the keywords are niche alternate behaviors)
18:47:08
aeth
Neither are the return values, though. They're input values. And that's in the standard, too, e.g. with FORMAT. Generalized booleans are too useful in return values because you never know if the caller wants to use the extra information or not and that saves an extra return value.
18:49:19
aeth
Similarly, I also always return nil (or, more rarely, t) even if the function is only used for its side effects. Some do (values) but that might break code that uses certain multiple-value functions/macros (and everywhere else it just inserts a NIL return value)
18:51:45
aeth
Bike: Well, I mean, you could be using multiple-value-call to call a function that has the mistaken assumption that every function returns at least one value, which isn't true for those extremely rare functions that end in (values)
18:52:57
aeth
It sounds like it would never happen, but that's exactly the sort of thing that if it did happen someone will lose a day or two on it because no one thinks it would happen
18:53:11
pjb
aeth: also, it's good to use T/NIL instead of generalized boolean to give the garbage collector an opportunity to do some work.
18:54:52
aeth
pjb: Which means that it's "perfectly safe" (in a reasonable implementation) to return a fixnum or single-float or other, similar things that (probably) aren't boxed.
18:56:26
aeth
pjb: If you're talking about storing, then, yes, definitely, t/nil helps with the GC always. You don't want to accidentally refer to some hash-table of 40,000 elements that could have been collected hours ago if you didn't store a reference to it instead of t
19:44:50
Bike
ecl has some code to make things like (error '(or type-error simple-condition) ...) work. does anybody use such a thing? https://gitlab.com/embeddable-common-lisp/ecl/commit/c6e419101400ee5d4372d748f646011b1480d0a2
19:47:24
Bike
well, clhs says make-condition's first argument is a subtype of condition, so i guess it could be understood as standard
19:47:26
pjb
Bike: it looks like it's conforming! type---a type specifier (for a subtype of condition).
19:48:55
Bike
no, i mean the function ERROR takes a condition designator, and a condition designator is either a symbol or a format control or a condition.
19:49:02
pjb
Bike: error takes a condition n. 1. an object which represents a situation---usually, but not necessarily, during signaling. 2. an object of type condition.
19:49:39
Bike
yes and the designators are clearly defined in 9.1.2.1 and specify a symbol, not any subtype. okay? okay. so does anyone actually use this thing.
19:49:58
pjb
This is a great find! I've been definining conditions just to mix simple-condition with my errors!!!
19:50:43
Bike
well if you did (make-condition '(and my-error simple-condition) ...) that could still just be an empty type.
19:51:22
Bike
it's also in clasp, which is why i'm asking. dunno about others but i sorta doubt it. i'll check sbcl.
19:52:05
pjb
Bike: you're right about 9.1.2.1, but ERROR is specified to accept and OR type specifier, and MAKE-CONDITION is explicitely designed to accept it.
19:53:08
aeth
Tangentially related, but I'd say the weakest part of the standard is conditions. Didn't someone here write their own destructuring-bind just to get a consistent cross-implementation condition there?
19:53:46
pjb
Bike: error is specified to take a designator to a condition (glossary) with a very large definition.