freenode/#lisp - IRC Chatlog
Search
8:43:46
beach
xificurC: It doesn't clobber the global value of the variable, because you bind it before incrementing it.
8:44:53
White_Flame
it's a compile-time decision on whether or not the variable is declared special, that determines what LET does
8:45:32
beach
xificurC: The tradition is also that each thread gets its own binding, and that they share the global value.
8:46:19
White_Flame
they can also be done via (defun foo (*x*) ...) which also establishes a dynamic binding for *x* using what's passed in
8:46:46
beach
xificurC: (defparameter *x* 0) (defun ff () (print *x*)) (defun gg () (let ((*x* 1)) (ff)))
8:49:03
White_Flame
a common machine code implementation is that when looking up the value of a special variable, first it checks the threadlocal table. If there's no binding there, it checks the global symbol-value of the symbol
8:50:21
White_Flame
and again, that choice is compile-time, depending on whether or not the referred variable is/was declared special or not
8:51:24
xificurC
ok, so in (defparameter *x* 0) (let ((*x* 100)) CODE-HERE) everyone using *x* at runtime will see the leted value, which is what dynamic binding is all about. The threading version works because specials can also be in a thread-local storage
8:52:48
xificurC
I still don't understand the sentence "the standard says that dynamic bindings are scoped to a function and everything it calls" though
8:53:14
White_Flame
(progn (let ((*x* 100)) ...*x* is seen as 100 here and in called functions...) ...*x* is back to normal)
8:55:41
White_Flame
(let ((*print-circle* nil)) (format t ...)) will cause FORMAT to see a new value of *print-circle*, for instance, but any other thread won't, nor will anything in the current thread outside the LET
8:56:08
White_Flame
specifically, outside the dynamic extend of LET, ie when it's active on the call stack and hasn't exited yet
8:57:34
xificurC
White_Flame: ah so I can imagine "if it's not on your call stack you can't see it"?
8:58:18
White_Flame
if a special binding has entered, then everything in the thread will see that new binding (unless another inner binding overrode it)
9:01:08
beach
xificurC: I know of no Common Lisp implementation that does it differently with respect to threads. Without threads, it is standardized behavior.
9:02:09
xificurC
beach: what other implications are there from this requirement? You're saying threads aren't mentioned but I don't see what else benefits from this behavior
9:02:47
beach
xificurC: As White_Flame pointed out, you can alter the behavior of things like FORMAT without passing an argument to them.
9:03:21
xificurC
beach: yes but if the binding wasn't thread-local it would still apply the same way
9:03:45
beach
xificurC: yes, but if the binding were a lexical binding, it would not behave that way.
9:03:59
White_Flame
" The effect of binding a dynamic variable is to create a new binding to which all references to that dynamic variable in any program refer for the duration of the evaluation of the form that creates the dynamic binding. "
9:04:51
xificurC
beach: yes that's the point of dynamic binding, I get that. I'm asking what other benefits are there from the fact that the binding is connected to the stack
9:05:46
xificurC
if it was altered in a global table that is shared across threads you would still have the same behavior with the FORMAT example
9:07:10
xificurC
White_Flame: so the standard doesn't mention threads but the requirements it imposes necessitate thread locality. And I don't see what other benefits are there from those requirements, i.e. why aren't threads mentioned
9:07:49
White_Flame
and threads aren't mentioned because they basically weren't invented at the time that the tech they were consolidating was created.
9:07:57
beach
xificurC: You are right. There are no other benefits to special variables than the fact that they allow dynamic bindings and that this is a unique property of Common Lisp.
9:08:37
beach
xificurC: A few minutes ago, you did not understand the mechanism of dynamic binding, so it is natural that we try to check that you now do.
9:09:19
White_Flame
the main benefit of special variables is side-band context, either global or scoped
9:09:25
xificurC
beach: I imagined it to work *not* thread safe, e.g. with a shared global table. But my test in sbcl proved me wrong
9:10:18
beach
xificurC: You also imagined something else, i.e. that (let ((*x* 1)) (incf x)) would alter the global value of *x*, which is not the case.
9:11:26
beach
So we are just making sure that you understand the benefits of special variables, even when there are no threads involved.
9:11:47
xificurC
I just imagined it to be something like (setf tmp *x*) (setf *x* 1) (incf *x*) (setf *x* tmp)
9:12:30
White_Flame
or (let ((old-x *x*)) (setf *x* 1) (incf *x*) (setf *x* old-x)) to be a little more idiomatic
9:12:44
shka
xificurC: essentially, each new binding to special variable shadows old binding for everything that comes after it on stack
9:12:58
beach
xificurC: Yes, and that won't work if there is an error and a non-local transfer between the save and restore.
9:13:21
beach
xificurC: Dynamic bindings are guaranteed to be undone in case of a non-local transfer of control out of the dynamic scope.
9:14:34
xificurC
I already understood and used the benefits of specials. I didn't understand why a let over it is thread safe.
9:14:56
xificurC
You guys said the standard requires it to behave in a way which is basically always implemented in a thread safe manner.
9:15:19
White_Flame
because "for the duration of the evaluation of the form that creates the dynamic binding" is interpreted that way
9:16:19
White_Flame
and scopes happen to be thread-local, by interpretation of that "during" description
9:19:17
xificurC
I was thinking "if I were to implement CL and read that line would the thread-safetiness be clear to me from that sentence?"
9:19:57
beach
xificurC: It's the only sane way of doing it. Otherwise, a thread could not count on the value of its own variables.
9:20:09
White_Flame
because the actual "time during which ... a binding ... is defined" is technically global, but unpredictable outside a thread
9:21:17
White_Flame
I think LOL is an interesting exercise, but I don't like the data-hiding of the way it uses closures
9:22:02
xificurC
beach: yes but you really have to think of threads to get a surprising effect from it when keeping it in a global table
9:22:53
White_Flame
a dynamic binding in a single threaded environment has well-defined boundaries. a global-trampling dynamic binding in a multithreaded environment loses those well-defined boundaries, while thread-local retains them
9:23:18
White_Flame
yes, but it also means you can't change them at runtime easily, which is very non-lispy
9:24:20
White_Flame
ie, if you create an object whose implementations are lambdas floating in hidden closure variables, then redefine the functions in the source code, the existing objects will nto be updated. If they were plain DEFUNs or DEFMETHODs, then the source code could change the behavior dynamically
9:24:30
beach
xificurC: In many respects, standard objects are strictly more general that closures, at least for SICP-style data hiding.
9:25:36
beach
xificurC: Since CLOS is so powerful, it is usually better to use standard objects than closures for data hiding.
9:26:41
jmercouris
beach: that sounds like a terrible idea, but I haven't done it, so I can't be sure
9:26:55
White_Flame
bad for debugging & development, in particular. You should still use well-defined interfaces and not just directly trample data, but explicitly barring ALL access is counterproductive in an interactive environment
9:28:24
White_Flame
having to pollute all your objects with logging functions, for instance, is a massive ugly nuisance, as opposed to letting your logger peek in as deeply as it needs to
9:28:59
jmercouris
even in OOP languages that have private members, they usually allow introspection and reflection
9:29:06
xificurC
but the world is a hostile place and the devs will try to kill your objects, you have to encapsulate!!! /s
9:32:46
xificurC
I always imagine the CL mascot from land of lisp just watching the programmers, year after year, implementing half-assed versions of what already exists for 50 years, scratching its head thinking just wtf is going on in other people's minds
9:34:00
makomo
White_Flame: i see your point about LoL. how would you for example "solve" the following problem: i had an object that you could (un)register callbacks with, and it would call these functions when a particular thing happened. the callbacks were taken as function objects.
9:34:46
makomo
White_Flame: now, when you pass in a function into this registration, such as #'SOMETHING, and later on redefine SOMETHING, you're still left with the old version of SOMETHING attached to your object
9:35:05
White_Flame
makomo: but I woudl probably define a struct or defvar to hold it (depending on scope) instead of just closuring it
9:35:52
makomo
White_Flame: since i wanted the benefit of interactivity/redefinition, i went with storing a symbol and then looking up it's symbol-function :D
9:35:54
White_Flame
makomo: right, because that's a _configured data object_, not just default class-style code
9:36:18
White_Flame
and yeah, symbols are the right way to do it if you want global redefinition of all instances to be possible
9:36:23
makomo
White_Flame: hm right, so it's not really a problem then, because you explictily did it that way
9:37:26
makomo
but i think LoL is a great book. it's an awesome lesson in macrology and a good brain strecher :-)
9:39:05
xificurC
makomo: I did a few years back but I didn't understand all of it. Reading it now (1/3 in maybe) and getting more from it
9:41:23
xificurC
I remember when I was reading it the first time someone here complained that defmacro! isn't safe when called in a nested fashion
9:42:34
makomo
xificurC: for example, sbcl processes the comma inside a backquote as a STRUCT i think
9:43:08
makomo
so codewalking the thing will give you a struct which is an atom (and also not a symbol)
9:44:56
makomo
the project aims towards a portable codewalker, but "portable" in the sense of using heuristics/specializing for different implementations, i think
9:59:26
jmercouris
I have no idea which system is defining this package, so I can't imagine how to fix it
10:02:13
jmercouris
when dropped into the restarts screen, is it possible to execute any arbitrary lisp in the image?
10:02:38
makomo
jmercouris: you can execute lisp code within any of the frames. press "e" in the slime window
10:07:41
TMA
jmercouris: but (find-package '#:static-vectors) returns #<PACKAGE "STATIC-VECTORS"> after (ql:quickload "static-vectors")
10:24:04
TMA
jmercouris: there is a problem with "static-vectors" on sbcl/freebsd then. I cannot help you further, I do not use freebsd. Sorry.
10:34:47
makomo
jmercouris: this seems to be the code https://github.com/cffi/cffi/blob/master/toolchain/bundle.lisp#L213
10:40:18
makomo
my idea was that the errors you got are because OS-COND wasn't defined as a macro or something
10:45:12
jackdaniel
downlaod prefered asdf (if you use sources, make will produce asdf.lisp file), and call (load (compile-file "asdf.lisp")) before quicklisp/setup.lisp is called
10:46:20
jackdaniel
QL first checks, if ASDF is already loaded (if so, it does nothing), after that it calls (require 'asdf) (that gives you asdf bundled with implementation). if this yields nothing (errors that module is not found), it loads asdf 2.26 which is bundled with quicklisp as a fallback
10:47:15
shka
is it sufficient to wrap defclass in optimize for safety 3 in order to ensure that i won't get the wrong type?
10:49:54
White_Flame
I would think it is highly dependent on when/where CLOS dispatch is recompiled, and if slot accessors are inlined somehow
10:52:11
jackdaniel
if you really want to load custom ASDF - I think yes. but maybe I have confused things (as Xach's veto would suggest)
10:52:37
jackdaniel
shka: I think he was referring to my sloppy explanation of ql algorithm of ensuring ASDF
10:53:43
jmercouris
jackdaniel: I was under the impression that sbcl --load quicklisp.lisp will already handle this?
10:54:23
jackdaniel
because QL calls require for asdf module, which is bunded with the implementation (if no asdf is loaded beforehand)
10:56:13
jackdaniel
I have a trust issues with ASDF upgrade mechanism, but in principle you should be able to load ASDF on top of existing ASDF
10:56:29
jackdaniel
because Quicklisp does call require ASDF for you (as I have pointed out *twice* already)
11:54:41
shka
jmercouris: when i started programming in C++ i had this very old machine with athlon 3200+ and 2GB of RAM
13:06:43
shrdlu68
https://imgur.com/a/hy7tRe4, screenshot from https://youtu.be/Z4oYSByyRak?t=11m40s
13:07:38
shrdlu68
His assertion is that it is not possible to handle heap exhaustion in Lisp, among other languages he mentions, and thus "it is impossible to write perfect software in these languages">
13:08:07
jmercouris
what does it mean to write "perfect software"? of course it is possible to prove lisp programs
13:09:07
jackdaniel
perfect software is the software which meets criteria subjectively chosen by the person who presents the topic ;)
13:09:34
jackdaniel
shrdlu68: in principle yes, implementation may raise a condition (and they often do)
13:13:05
jmercouris
better usage of your time might be reading about how to prove programs, and the set of languages that exist for proving programs/algorithms
13:13:17
jmercouris
of course, they have not lived up to the hype, but they are still interesting ideas
13:13:32
shrdlu68
His argument is, that function will always return the correct output for the correct input - there won't be malloc errors, etc.
13:14:06
jmercouris
just because a program has state or memory does not mean that it cannot be proven
13:15:18
jackdaniel
that reminds me a discussion whenever CL allows arbitrary big integers or the physical computer limitation counts here and CL can't have arbitrary big integers
13:16:29
shrdlu68
If one attempted to add two large bignums on a system that's running out of memory, what exception would a lisp implementation raise?
13:16:52
_death
it's like saying 1+1=2 is false because some gamma ray flipped a bit.. different levels of reality
13:18:15
jackdaniel
which is a condition inheriting from storage-condition, which inherits from serious-condition
13:20:56
jackdaniel
jmercouris: you may say whatever you want – that doesn't mean people will understand you
13:22:48
jmercouris
jackdaniel: I am asking, IF we can agree that this condition is not defined in the CLHS and it results in undefined behavior, based on that youtuber's definition, can we say that CL is "non-perfect"?
13:28:26
jmercouris
jackdaniel: yeah, the perfection crtieria is that one guy's perfection criteria, not myo wn
13:29:15
jmercouris
I think my sentence is pretty clear, though I also understand the point your making, "what is perfection"
13:29:53
shka
is it correct? http://www.crategus.com/books/closer-mop/pages/sb-mop_fun_slot-definition-type.html
13:29:54
jackdaniel
if it is: doesn't have threads in the specification, CL is not perfect. if it is: doesn't have defined behavior for memory exhaustion in the spec, CL is not perfect. ;) fwiw he was talking about a perfect software, not a perfect language (judging from the screenshot)
13:31:19
jackdaniel
copy-paste from http://metamodular.com/CLOS-MOP/slot-definition-allocation.html ?
13:34:00
p_l
until it's pulled from under you externally, like typical case for C program on Linux, or the essentially equivalent case of people disabling GC on early LispMs
13:34:55
jackdaniel
p_l: I don't know about other implementations, but ECL has preallocated memory for reporting memory conditions
13:35:46
p_l
jackdaniel: well, it's *ECL*, not "le random C/C++ crap written on and tested on only on Linux" ;)
14:37:32
vindarel
Hello (common) lispers, little question on capturing standard output. I know with-output-to-string, but this doesn't suit my need because I'd like to return the string immediately, to not break the printing of the application. I'd like something like a defadvice, but this doesn't exist in SBCL. Do you think of something ? thx
14:38:40
Bike
do you mean that you want to print to standard output but also capture it in a string?
14:40:04
vindarel
Actually I don't care to capture to a string, I'd like to change it before it is printed (to highlight stuff).
14:42:50
vindarel
A reader macro ? I'd like to change output from third party code, that won't use the reader macro.
14:44:35
dlowe
You could set *standard-output* to an echo-stream, then use a thread for reading from that echo-stream and writing your changed version to standard output.
14:44:48
vindarel
Well ok thanks, this is what I needed to know. I'll re-think my programmatic interface then.
14:45:02
dlowe
You could also use the gray streams extension, which would allow you to make a different kind of stream
14:47:13
dlowe
Typically, though, you want to keep your data as structured as you can until just before you display it, to avoid munging text like this.
14:48:01
vindarel
looking at gray-streams can be a good exercise. Still, I imagine it'd have been easy with a defadvice… maybe.
14:49:36
dlowe
You will find that Younder actually has not written any lisp at all and is a poor source of information.
14:52:19
Younder
oh, I see. I should have read the context better. I have however worked with read macro's.
16:18:26
jackdaniel
you need to keep things straight – if you want to call C (or C++) from CL, then you use FFI (scenario when your application is written in CL and you want to use C library)
16:19:29
jackdaniel
if you want to call Common Lisp (and use it) from C application, you probably need ECL (or MKCL)
16:20:10
jackdaniel
Fare: well, usually when I see someone forking software something tells me, that there ought be a reason
16:21:02
Fare
I believe Jean-Claude had ideas on how to handle interrupts and other low-level details in C++
16:21:43
jackdaniel
from my reading of the old mailing lists it is not the case, but I was not around to argue about that
16:23:46
jackdaniel
black_13: either way, if you want to call C/C++ from Common Lisp – use FFI, if you want to call Common Lisp from C/C++ use one of the mentioned implementations. If you simply want to write application, you may use Common Lisp all the way down
16:24:05
Fare
As far as porting ASDF goes, it looks like MKCL fixed some of the bundle issues that I had with ECL (I believe that ECL fixed them since, but I've lost track.)
16:36:04
jmercouris
quick update, my issues were most definitely related to the version of asdf that I had
20:18:18
White_Flame
to add to the discussion around https://imgur.com/a/ws1VDeU , his own thesis completely fails, because calling that function might cause a stack overflow in trying to push the return address & parameter. It's still a "hidden allocation"
20:29:39
pjb
White_Flame: indeed. The C standard defines a not-turing complete programming language, since it's not guaranteed that you can call functions.
20:30:43
jackdaniel
loosely related: http://www.yodaiken.com/2018/05/20/depressing-and-faintly-terrifying-days-for-the-c-standard/
20:34:27
pjb
There is newbie lisp code around, but there's also a lot of good CL code, and even very nice CL code.
20:34:41
p_l
recent brouhahaha with Mono developers finding out that XLc maps page 0 as read-only page full of zeroes is a nice example
20:35:12
White_Flame
wow, this guy just basically reinvented java-style explicitly required exception handlers
20:42:18
rpg
Is there some way to use conditional compilation (#+) to include code that is dependent on SBCL version?