freenode/#lisp - IRC Chatlog
Search
17:05:47
tryingoutlisp
I get an unbound-variable error. Let me pastebin an example so I can show you.
17:45:42
jmercouris
so, I'm running (bt:make-thread (lambda () (uiop:run-program "xyz"))), how can I know when xyz has started?
17:46:09
jmercouris
mind you, xyz is a long-running process, and will continue to run, it's not like I'm looking for an exit code or anything
17:52:29
flip214
or you look at the child process' CPU usage - and after 1 sec or so you know it's "up" (and not crashed yet)
17:52:54
flip214
or you can use ptrace and see when it has reached some important point (listening socket open, etc.)
17:54:24
|3b|
but yeah, if you need to interact with it, probably better to just have it tell you when it is ready if possible
17:54:50
flip214
jmercouris: is there some external effect you can watch for? like a http server which you can ask for /status or so?
17:55:06
flip214
jmercouris: signals are not that easy to handle correctly; even less so in multi-threaded programs.
17:59:57
jmercouris
so I'm not sure how to loop on retrying the command until I don't get a connection-refused-error
18:06:11
fortitude
jmercouris: you might want to use that handler case in a function that returns T or NIL based on whether the connect succeeded
18:08:25
fortitude
jmercouris: if it helps, handler-case is known as try/catch in other languages, so if you've ever used that before, you can do the same sort of things
18:09:04
jmercouris
(make-window) in the above code is making the XML-RPC call which depends on the other program to be running
18:10:29
jmercouris
dlowe: ah, so you set the loop expression it is looking out for within the cases
18:18:31
|3b|
ACTION tends to just loop on 2nd value of ignore-errors when i'm expecting lots of errors :p
18:23:04
fortitude
jmercouris: your handler-case form doesn't have any error clauses, and your handler-bind form doesn't have a body (they're two separate ways of handling errors)
18:24:13
fortitude
what you want is (handler-case <your thing> ((sb-bsd-sockets:connection-refused-error () <your handling code>)))
18:26:20
fortitude
jmercouris: if it makes you feel better, I can never remember which syntax goes with which form either
18:31:07
jmercouris
you know, I often look at the hyperspec, and I'm still not that good at understanding it
18:31:49
fortitude
jmercouris: the grammar notation can be a little tricky sometimes, but it helps if you pair it with the examples
18:37:48
malice
However, there is an effort by phoe called CLUS, short for COMMON LISP ULTRASPEC, which tries to provide a better hyperspec: http://phoe.tymoon.eu/clus/doku.php?id=cl:macros:handler-case
18:38:08
jmercouris
I don't want to disparage the ultraspec project, but it is on permanent hiatus afaik
18:39:06
malice
dlowe: On more than one occasion I found that examples weren't clear enough or didn't showcase what I wanted to know (and I do not think I was looking for anything extraordinary).
20:15:42
veddox
Hey everyone, I have a bit of a problem with usocket and I'm wondering whether somebody here might have the time to help...
20:16:45
veddox
Basically, I am working on a client-server game. The relevant code is here: https://gist.github.com/veddox/d0df0d6ea685a348d5674c30b2cdfe6d
20:18:08
veddox
I can create the server (`run-server`), and connect to it (`connect-server`), and `handle-connection` will confirm a connection has been made
20:18:34
veddox
However, when I then call `query-server`, the string I send to the server socket won't arrive
20:19:36
veddox
It appears the stream is not being flushed, but I do call `finish-output` (line 102), so I'm a bit baffled.
20:20:06
dlowe
(format servstr request) request should probably be a string or you shouldn't use FORMAT
20:20:48
veddox
It is one. For test purposes I call it as (query-server "ACK") - which ought to return "ACK ACK"
20:21:15
sjl_
dlowe is saying that if your request happens to contain format directives, it'll do surprising things
20:22:13
sjl_
How do you know the string you're sending doesn't arrive? I see where you log the connection, but not where you log the strings you receive
20:23:54
sjl_
I've had this bite me before -- everything's actually working, but my final log line was stuck in a buffer waiting to be flushed
20:24:18
veddox
logging is a macro: (defmacro logging (str &rest format-args) `(write-to-file (format NIL ,str ,@format-args) *logfile* T))
20:26:43
veddox
`write-to-file` takes a string or a list of strings and writes them all to file (calling `open` directly), the closes the file connection
20:30:52
dlowe
veddox: right. if you know the packet is sent then you know a lot more about where the problem might be
20:31:39
veddox
@sjl_ Yes I do. I get "received a connection", "sending request" and "waiting for server response"
20:34:33
sjl_
be careful wil parsing user-supplied input into symbols in a package -- since they don't get GC'ed you can exhaust the server's memory by just sending tons of symbols
20:45:46
veddox
Thank you very much for your help! I've been chasing that bug for a couple of days now :-)
22:00:11
elderK
Guys, is it standard practice to, when loading a "system" without ASDF, to compile a file, and load it immediately after?
22:00:45
elderK
I may be misunderstanding compile-file, but as far as I know, each call of compile-file basically runs the compiler in a new environment, one based on the environment in effect when compile-file was called.
22:00:52
pjb
elderK: notice that just compiling the file doesn't put the definitions compiled in the run-time environment!
22:01:04
elderK
So, to compile a whole system, you compile the files, load them, which brings their stuff into the environment ready fro the next compile-file to use.
22:01:26
pjb
"defun is not required to perform any compile-time side effects. In particular, defun does not make the function definition available at compile time. "
22:01:57
elderK
pjb: Right, which is why if you use the function as part of compiling some file, you need to wrap it in an eval-when.
22:01:59
pjb
So, just try it: Put (defun foo () 'foo) in a file foo.lisp, and (compile-file "foo.lisp") (foo) <- boom undefined function error!
22:02:22
elderK
But, say, we compile/load file A. And it defines a function. When we compile file B after A, the function is available - since we loaded it from the compiled file A
22:03:19
pjb
If you just compiled a bunch of files, the definitions of one wouldn't even be known to the other you'd get undefined function errors while compiling B for functions defined in A.
22:03:44
pjb
To prevent the warnings, you could use (with-compilation-unit (mapc 'compile-file '("A" "B")))
22:03:57
elderK
So basically, unless you're using some function - or data generated somehow - during compilation of a file that defines that function or builds that data, you don't need eval-when.
22:04:14
pjb
But (dolist (f '("A" "B")) (load (compile-file f))) works better, and you end with being able to call the functions in the REPL.
22:05:10
elderK
pjb: Thank you. It seems like, to actually compile a system defined in multiple files, you'd have no choice but to compile->load each file. Since, otherwise, stuff that one file needs, wouldn't be visible to it in the compilation environment.
22:05:37
pjb
elderK: if there are dependencies between the files, they need to be loaded ot compile the next, yes.
22:05:52
pjb
If two files don't have any dependencies, they can be compiled, without loading one or the other.
22:06:00
elderK
I.e. compile-file always creates a new environment based on the one in effect at the time compile-file was called. Any changes the compiler makes to the environment during compilation, are not guaranteed to still be in effect once compile-file terminates.
22:07:45
elderK
pjb: Right, but ASDF is smart enough (via use of depends-on) to compile a bunch of independent things, without loading after each. Like, it'll load the things that are needed before the compilation of stuff that depends on those things, right?
22:09:12
elderK
pjb: Another question: What's the deal with IO errors encountered during write-sequence? Do they cause file-error to be signalled?
22:10:32
aeth
Currently you can get an AMD x86-64 32 core / 64 threads for $1799 and next year there will be an AMD 64 core / 128 thread CPU for probably a few hundred more... and then the price will slowly come down over the next 10 years until every serious programmer has one, and then we'll really miss not having parallel compilation.
22:10:50
elderK
pjb: :D Another question: Does call-next-method regenerate the applicable-method-list if necessary?
22:11:30
aeth
Oh, and IBM's POWER isn't far behind AMD. And in some measures it could be ahead because it'll have fewer cores, but 4x hyperthreading instead of 2x
22:12:56
elderK
pjb: I'm just curious because atm, I'm allowing you to specify a symbol as a parameter, rather than a concrete object. The method specializing on the symbol, just retrieves an object based on that symbol, and reinvokes the GF on the object.
22:13:10
elderK
It'd be neat if I could call-next-method instead, since I'd assume that'd avoid reinvoking :around
22:13:18
aeth
ebrasca: Take a look at this, this isn't easy to understand: https://github.com/fare/asdf/blob/master/lisp-action.lisp
22:13:56
pjb
elderK: each time you call a GF, an applicable-method-list is computed. (But it may be cached).
22:14:54
aeth
I think the hardest part about understanding ASDF is that you can't just navigate it with M-. because *your* version of ASDF is going to be "compiled" all into one file.
22:14:59
elderK
pjb: So this is valid? (defgeneric f (a)) (defmethod f ((a symbol)) (call-next-method (get-thing a)) ?
22:15:02
pjb
"When providing arguments to call-next-method, the following rule must be satisfied or an error of type error should be signaled: the ordered set of applicable methods for a changed set of arguments for call-next-method must be the same as the ordered set of applicable methods for the original arguments to the generic function. Optimizations of the error checking are possible, but they must not change the semantics of call-next-me
22:16:21
elderK
I'm using :around methods to force a certain default for optional arguments, for all methods on the GF.
22:18:55
_death
elderK: in general I avoid optional/key params in generic functions.. instead I have an ordinary defun as the user's interface and it should call a generic function, the extender's interface
22:21:56
aeth
ebrasca: The problem with Lisp compilation is that there are globals that could be modified that have an effect on the compilation. For instance, some people for whatever reason decide to #+sbcl (setf sb-ext:*derive-function-types* t) even though that's imo the wrong thing to do as a library. There are also portable ones like *read-default-float-format*
22:25:00
jcowan
aeth: probably the moral is to compile-file only from a fresh Lisp instance each time. Slower but safer.
22:44:08
aeth
I think the way to do it would be to track all of the "default" globals (i.e. ones that come with the implementation), which can be implementation-specific, and restore them to the default value after each system, which could be different from their actual default value if the user wants something like *read-default-float-format* as 'double-float
22:44:58
aeth
(Also, if run from SLIME, all of the stream globals would have different values from the original without the user explicitly setting them.)
22:51:55
elderK
Is there a convention for like, exporting symbols that are meant for public use, and naming those that are exported but intended for developers?
22:52:07
aeth
There are still two complicating factors that I can think of right now: (1) *features* is designed to be appended to and (2) this only allows parallel compilation for independent libraries because once you get A depending on B, B could introduce its own globals that A depends on.
22:52:15
elderK
_death: Say, I use read-from as the public-facing API for reading some binary type. It does type checks, defaulting, etc.
23:05:47
|3b|
write code that makes you learn new things, or try to find better ways to wrfite your code
23:12:12
whartung
better to do new things in new code than redoing old code. in the end you know more, and your projects do more rather than just polishing the same wheel over and over and over again.
0:03:31
ebrasca
So 1 option it to left code and make new code better and other is make old code better but less code.
0:08:27
aeth
ebrasca: When writing something new, you'll eventually have a realization that something old you wrote should be rewritten. At that point, do it.
0:08:44
aeth
(As long as it's not a library that someone else is using. Then you're restricted because you can't break the API.)
0:13:12
pjb
elderK: instead of prefix symbols for different uses or protection leves, you can define different packages, for users, developers, etc.
0:13:19
whartung
since I write code not for the sake of writing code, I tend to put time in new software to do new things than updating old software to do the same thing it always has done before. If I have to modify older software, then I would certainly consider incorporatng whatever I’ve learned since I wrote in to the new changes I’m making, if appropriate.
0:15:14
pjb
elderK: (defpackage "YOUR.IMPLEMENTATION" (:use "CL") (:intern "FOO" "BAR" "BAZ")) (defpackage "YOUR.API" (:use) (:import-from "YOUR.IMPLEMENTATION" "FOO" "BAR") (:export "FOO" "BAR")) (defpackage "YOUR.USER" (:use) (:import-from "YOUR.IMPLEMENTATION" "BAZ") (:export "BAZ"))
0:15:54
pjb
So you can write your code in the package, YOUR.IMPLEMENTATION, and develoers can use YOUR.API:FOO and YOUR.API.BAR, while users would use YOUR.USER:BAZ.
0:24:07
elderK
pjb: :P Damn, I'm using % as a marker to say "internal, but you can use it if you're doing something weird."
0:39:10
|3b|
"this is dangerous, so make sure you know what you are doing if you call it, but it is exported so it is a supported API"
0:43:19
elderK
Is there any effective difference to like, adding something to a symbol's plist in the macro expander itself, to doing the same in the expansion in an eval-when (:compile-toplevel)?
0:55:54
elderK
Bike: By macro forms, do you mean that the macro expansion function might be invoked in weird times and stuff?
0:59:25
whartung
depends on the macro. Some macros may be part of a larger context that makes sense to capture context level state.
1:01:50
jcowan
The main thing is not to do anything in a macro (except for debugging etc.) that is not idempotent.
1:02:52
whartung
well, in my field example, you could see the “my-set” field set could contain a list of fields that are defined within the scope of “with-field-set”, so you need a list, or vector, or something to capture them. field would be an example of a macro with a side effect.
1:05:34
whartung
the entire “field set” is a contrived example (I have no code defining fields sets, I can’t expand on the detail as to what a field-set is, or does, or when you would use one, etc.)
1:06:02
whartung
it’s simply demonstrative of a rare case where you may have macros that work together.
1:06:48
whartung
the “with-field-set” creates a context within which the “field” macro works at aiding in the defintion of the field set.
1:07:30
whartung
the side effect is how the individual “field” macros affect the context created by “with-field-set"
1:08:18
whartung
for example if you have 2 field macros, then the list of fields in the field-set will be 2 fields long. If you define 3, then it’s 3 fields long. That list is an attribute of the field-set that the field macro affects.