freenode/#lisp - IRC Chatlog
Search
10:05:43
sauvin
in sbcl, I'm suddenly getting hit with an "undefined variable" error or warning when I try (setq a '(1 2 3 4 5)). What could be wrong?
10:06:35
phoe
define your variables before setting them - globals via DEFVAR or DEFPARAMETER, locals via LET or LET* or the other utilities for binding
10:07:25
sauvin
Yeah, well, folks in this channel about 24 hours ago told me about that, which is why I'm asking. Worked in gcl, ain't working in sbcl, wtf!?
10:10:02
phoe
it's a good thing on one hand, and on the other, it has caused a fair share of breakages in libraries that were working before but then SBCL found ANSI CL conformance bugs in them
10:11:40
sauvin
Well, see, this was one of the reasons the folks here gave yesterday for me to move to sbcl: more conformant to the standard.
10:13:12
phoe
the question with SETQ on symbols always is: where is this particular symbol defined to be a variable?
10:13:37
beach
sauvin: It's kind of the other way around. It "works" in SBCL, since it signals a warning, and it does not "work" in GCL because it lets a detectable undefined situation pass silently.
10:17:34
sauvin
Because I don't understand it. I'm just now learning how to assign variables in lisp, and it's a lot more complex than in perl, and it's more complex than in the AutoLISP that I used to use heavily but haven't seen in twenty years.
10:18:12
no-defun-allowed
You are going to understand it even less, if you attempt to intentionally break it.
10:18:30
sauvin
So, anyway, let works at the top level. I'm a big fan of lexical variables anyway. I avoid globals wherever I can.
10:18:41
beach
sauvin: How is (setq <variable> <value-form>) more complex than <variable> = <value-form>?
10:19:39
no-defun-allowed
You are not breaking anything with LET. You're also not really breaking things with SETQ on undefined variables on its own, but attempting to dispose of the warnings your implementation makes for using SETQ in that way is breaking it.
10:19:59
no-defun-allowed
my $thing = ... would be like wrapping the rest of the body in (let ((thing ...)) ...)
10:20:20
phoe
declaring local variables in Lisp is done via LET and LET* and some other similar operators
10:21:16
no-defun-allowed
However, note that DEFVAR and DEFPARAMETER are always used to declare special variables, which are dynamically scoped. I think Perl is another one of the few languages with dynamically scoped variables.
10:22:03
no-defun-allowed
Yes, DEFUN, DEFPARAMETER and DEFVAR usually don't do what you want them to do, if you put them inside a function body.
10:22:08
sauvin
perl DOES have dynamically scoped variables, but there are very few circumstances under which their use encouraged.
10:22:49
no-defun-allowed
That is not so far off in Lisp; you use lexically scoped variables by default, but dynamic scoping is useful for cross-cutting "customization" of things.
10:23:21
sauvin
Yes, and i perl, I'd have to have some pretty convincing reason to use 'local', which means 'dynamic'.
10:24:39
sauvin
I'll look at that later. For now, many years spent swearing at the machine (and destroying more than one keyboard in the process), I tend to disfavour global variables. I just wind up tripping over them.
10:25:02
no-defun-allowed
For example, you can re-bind *standard-output* to send printed text somewhere else (provided it is printed to *standard-output*).
10:26:28
sauvin
Had to do that already. *default-external-format* defaults to utf-8, but trying to read a couple of files I have caused sbcl to puke, so I had to change that variable to ISO-mumble.
10:27:10
no-defun-allowed
But I use a fair few global variables in my work, mostly to put weak hash tables somewhere, so that I can de-duplicate objects I use.
10:27:28
phoe
and use dynamic variables either for passing context information along your call stack, and almost only for that.
10:28:28
sauvin
I tend to prefer passing parameters. Dynamic variables (in my other-language experience) are just another morass.
10:29:35
phoe
(with-output-to-string (*standard-output*) ...) hijacks the output stream and returns everything that was printed as a string
10:30:24
phoe
(let ((*package* (find-package :keyword))) (prin1 x)) prints X with all symbols being fully qualified, so with all package prefixes
10:30:53
phoe
it can contain functions which call functions which call functions which print to standard output
10:31:16
phoe
and, no, they aren't printing to standard output anymore; they're printing into the stream that collects stuff into a string
10:32:55
phoe
(defun foo () (princ :asdf)) (with-output-to-string (*standard-output*) (princ :qwer) (foo) (princ :zxcv))
10:32:56
no-defun-allowed
I am aware that Haskell (or GHC maybe, who can tell the difference) has dynamic binding, so they're not totally useless.
13:10:52
heisig
If I had a nickel for every bug I introduced because I closed over a LOOP variable, thinking it would create a fresh closure for each iteration, I'd have have two nickels. Which isn't a lot, but it's weird that it happened twice.
15:56:41
pfdietz
phoe: this is exercising the mutation tester, sanding off rough spots exposed by applying it to "real" code.
15:59:48
pfdietz
Just starting this round. split-sequence looks good, no real bugs found so far, just some cleanliness tweaking.
16:00:34
phoe
(split-sequence:split-sequence 0 (list 1 0 2 0 3 0 4) :start 2 :end 0) is capable of blowing the heap
16:01:42
pfdietz
I applied it to fset sometime last year and found a number of problems, even in code that had been covered.
16:02:51
pfdietz
But, as I said, this is more for shaking down the tester. I'm going to have a set of recommendations for testing framework writers too, to make their tests more useful here.
16:05:01
pfdietz
In this case, because once I kill a mutant I want to stop testing. No sense killing it again and again.
16:05:55
pfdietz
Also, I would like to be able to extract a subset of a test suite (say, just the tests that somewhere call function FOO) and just run those. No sense running tests that don't touch a mutated function.
16:07:00
pfdietz
It's easy to see which tests call FOO: instrument FOO, run the test suite. This assumes the tests have set some special variable that indicates which individual test is being run.
16:07:33
phoe
I assume you also could try to call Dissect and figure that out from the call stack, somehow... but, yes
16:08:22
pfdietz
Not sure that would work on generic functions, though. Maybe an around method, but what if one already exists.
16:11:48
_death
with such a who-calls database (kinda like screamer maintains) you could have relevant tests running automatically after redefining a function..
16:12:12
phoe
I assume you can always SETF FDEFINITION with some sorta funcallable instance that then calls the original FDEFINITION
16:29:34
_death
sbcl has sb-introspect and others have their own interfaces (and then there's xref.lisp).. (swank:xref :callers "foo:bar") seems to work, but not a very convenient interface for CL programs
16:30:43
pfdietz
Anyway, what I was aiming for here was API in test frameworks to make this useful (running subsets of test, and knowing which test is running).
17:16:37
Xach
i don't quite understand the location of the warning from http://report.quicklisp.org/2021-01-03/failure-report/local-time.html#local-time
17:23:24
aeth
A fun error I've been getting is when SBCL 2.0.2 (in e.g. Gitlab CI) STYLE-WARNINGs that the implicit return value of NIL in a COND with no default clause is not of some numeric type that the rest of the code expects. But SBCL 2.0.8, which I actually use (and yes, I should upgrade), is a bit smarter and complains about deleting unreachable code in those unreachable, literally-impossible default branches.
17:24:48
aeth
I suppose I should have an EFOO and CFOO version (like ECASE and CCASE) to those macros that generate CONDs so that the default branch is an error instead, since if you make it an error, it won't complain... except about deleting unreachable code, which can be safely hidden in a "(LOCALLY (DECLARE #+SBCL" with the right declaration.
17:25:04
pfdietz
Turn the last clause (<condition> . <forms>) into (t (assert <condition>) . <forms>)?
17:26:33
pfdietz
I plan to use these warnings in the mutation tester. If I want to substitute Y for X, I can insert a (unless (eql x y) ...) and if it complains about unreachable code, I know that's an equivalent mutant.
17:26:58
phoe
if you enjoy lisp compilers that don't yell at you for things, you definitely shouldn't try sbcl
17:28:15
phoe
I'd do that with handler-bind over invoke-restart around the signaling form in the REPL
17:30:46
Nilby
Hmmm. I was hoping to do in without forethought. Like an easy way to blast through encoding errors.
17:34:01
SpaceIgor2075
I finished reading A Complete Idiot's Guide to Common Lisp Packages and I feel like an incomplete idiot
17:37:28
SpaceIgor2075
So, to make a new package, in newpackage.lisp I should write something like: (defpackage newpackage :export '("new-stuff")) (in-package newpackage) (defun newstuff () "New Stuff!!")
17:56:55
Nilby
SpaceIgor2075: pretty close, but I would say: (defpackage :newpackage (:use :cl) (:export #:new-stuff)) (in-package :newpackage)
18:05:30
phoe
SpaceIgor2075: DEFPACKAGE options are not quoted, and remember that strings respect case whereas symbols, by default, don't
18:22:01
SpaceIgor2075
phoe: 1. why is :cl used instead of 'cl? 2. (:export #:new-stuff) has a # because new-stuff is a function, am i right?
18:22:56
phoe
and writing FOO causes the reader to intern the symbol named "FOO" in the current package
18:23:33
phoe
when you evaluate a DEFPACKAGE, this can happen in literally any package, because usually only after a package is defined you use IN-PACKAGE to switch into it
18:23:53
phoe
so a DEFPACKAGE form that has unqualified symbols like FOO in it can intern unnecessary symbols into other packages.
18:24:51
phoe
which kiiinda sidesteps the problem but not really, because now symbols are interned into the KEYWORD package, which can produce unnecessary keywords
18:25:15
phoe
option 3) is to use strings, which is permissible, but has issues if someone uses a different readtable case than the standard, upcasing one
18:26:01
phoe
and I personally suggest to use #:foo for everything in DEFPACKAGE, including imports and uses and exports and package-local nicknames
18:26:28
phoe
so (defpackage #:newpackage (:use #:cl) (:export #:new-stuff)) (in-package #:newpackage)
18:31:31
minion
sauvin: tclcs: The Common Lisp Condition System, https://www.apress.com/us/book/9781484261330
18:35:12
SpaceIgor2075
CL seems to be quite deep. Are there any books dedicated to other programming languages' condition systems?
18:35:12
phoe
the intended one was to write about the ideas, implementation, and use cases of the condition system
18:35:42
SpaceIgor2075
Or is it specific to CL that you can write a whole book on it's condition system?
18:35:59
phoe
the accidental one: I seem to have described how to implement a non-trivial piece of Common Lisp code, bit by bit, while testing it heavily in the REPL
18:37:53
Nilby
If we just copy the irc logs and throw a few headings on, i feel like we'd have like 2 more phoe books pretty quick.
18:42:23
sauvin
I should imagine that if the S/N ratio here is high enough, browsing the logs would be a great tool for brainstorming all KINDS of random stuff.
18:42:48
phoe
#lisp is moderated rather heavily when it comes to off-topic discussion, so S/N should be high in general