warweasle has quit [Quit: rcirc on GNU Emacs 24.4.1]
robotoad has quit [Quit: robotoad]
janivaltteri has quit [Quit: leaving]
shifty has joined #lisp
robotoad has joined #lisp
* pillton
requests permagreen to change nick to temporbrightwhite.
<elderK>
:D Electric Violet, even! :D
Mr-Potter_ has quit [Ping timeout: 245 seconds]
Kaisyu has joined #lisp
graphene has quit [Remote host closed the connection]
Oladon has quit [Ping timeout: 250 seconds]
graphene has joined #lisp
<fouric>
does quicklisp download and compile packages in parallel?
rumbler31 has joined #lisp
<Xach>
fouric: no
Kundry_Wag has joined #lisp
rumbler31 has quit [Ping timeout: 246 seconds]
<fouric>
Xach: is there a reason it's not being done aside from "not yet implemented"? e.g. some sort of not-inherently-thread-safe thing
<fouric>
(also thank you for the quick and concise response)
<elderK>
fouric: I'm no expert on Lisp implementations but imagine what would be necessary.
<elderK>
It would be one thing, to ensure that "unrelated" stuff was compiled / loaded etc in parallel.
<fouric>
(that's what i was thinking)
<elderK>
But to think about the effect on the environment, as things were being compiled / loaded.
<elderK>
I bet it /could/ be done. But, I imagine it would be a very detailed process, and a bit like navigating a minefield.
<Bike>
e.g. sbcl cannot compile in parallel (short of forking)
<Bike>
so there's that
<elderK>
I mean, the specification does grant the possibility that the environment in which a file is compiled, is "based on" the environment the compile-file is called from, but could be distinct from the environment it "spawned from." Of course, most implementations (in my experimenting), share the environment.
<elderK>
Bike: Interesting.
<elderK>
Bike: :D Are the details explained as to why, somewhere? I'd find it a fascinating read.
<fouric>
that's super unfortunate
<Xach>
fouric: i have never thought about doing it. it doesn't seem worth the trouble to me.
<Xach>
having thought about it now for a few minutes
<fouric>
lol fair enough
<fouric>
although hypothetically if someone wrote a decent set of patches, would you accept them?
<elderK>
fouric: I'm not sure it's super unfortunate. I suppose it really depends on the size of the stuff you're building.
<Bike>
elderK: there's a big lock around the compiler, because it reads and writes global structures without any particular regard for coherence. as far as i understand.
<fouric>
elderK: Mezzano took like upwards of 10 minutes for me
<elderK>
Bike: Makes sense.
<Xach>
Bike: soon to be gone, or already gone, i think!
<fouric>
perhaps closer to an hour
<Bike>
that so? good to hear
<Xach>
dougk posted about it a week ago
<fouric>
and also if we want to build larger projects in CL, tools that do things in parallel are always better to have
<elderK>
fouric: Mezzano, while incredibly impressive, has kind of different constraints.
pierpa has joined #lisp
<elderK>
fouric: You'd have to talk to froggey as to learn more about Mezzano's compiler and all that stuff.
<Xach>
fouric: I like the idea of parallel builds because that's ASDF's domain, and the implementation's. parallel fetching shouldn't be too hard in theory if threads or something are supported. but that's not universal.
<elderK>
Xach: Is SBCL moving towards supporting like, parallel compilation in the future? Or are these changes jsut to help improve performance on multi-core systems?
<fouric>
Xach: would a parallel-fetching patch that worked for *some* platforms (using e.g. bordeaux-threads) but didn't make things worse on the others be OK?
<fouric>
elderK: doesn't Mezzano bootstrap itself using an existing Lisp?
<elderK>
fouric: It builds an image and stuff, sure. But once it boots, everything is being built in Mezzano, afaik.
<ebrasca>
Hi
<fouric>
lol
<elderK>
It side-steps the necessity to have like, a stable FS system by using a file server.
<fouric>
ahhh, you're right
<elderK>
fouric: That's why it takes so long to boot the first time, and perhaps later.
<fouric>
well, but take things like the NeXT browser (which is on HN frontpage today :D)
<elderK>
Which, has benefits and drawbacks. The benefits are that Mezzano can compile to suit the architecture it's running on, with the available features.
<elderK>
fouric: You'd have to talk to jmercouris for that :)
<fouric>
elderK: yes, but afaik it's built entirely with a "vanilla" CL
<fouric>
which could be SBCL
<fouric>
...and the larger it gets, the slower compile times are going to be
<elderK>
Right. I guess if you wanted, you could check out the Next browser and you know, see how long it takes to build? :D
<fouric>
etc.
<fouric>
i just did
<fouric>
erm, i just built it
<fouric>
didn't time it
<fouric>
let's see
<Xach>
fouric: no, it shouldn't involve outside dependencies.
<Xach>
fouric: well, that part is a "no". but in theory a system that parallelizes downloads with a possible cap on simultaneous downloads at 1 would be ok, I think.
<fouric>
darn
<elderK>
fouric: I haven't yet written anything substantial enough in CL to really... feel the pain. That being said, making heavy use of STL in a "nontrivial" C++ project is painful almost immediately. I imagine CL is easier to parse, and perhaps to analyze in some ways, than other languages. Perhaps this means that we can compile larger projects in less time. Who knows?
<elderK>
fouric: I mean, I build SBCL from source. And it builds pretty damn quickly.
<Xach>
that is the most pressing thing to optimize for compiler writers
<elderK>
Aye.
<fouric>
lol
<elderK>
I wonder if there are techniques in CL-world, similar to those in C/C++ land, to like, reduce compile-time dependencies from one module to another. You know, stuff like PIMPL or simple forward-declarations and stuff.
fikka has quit [Ping timeout: 240 seconds]
Kundry_Wag has quit [Ping timeout: 268 seconds]
meepdeew has joined #lisp
dale has quit [Quit: dale]
Kundry_Wag has joined #lisp
arescorpio has joined #lisp
fitzsim has quit [Quit: ERC (IRC client for Emacs 27.0.50)]
fikka has joined #lisp
milanj has quit [Quit: This computer has gone to sleep]
chens has joined #lisp
esper0s has joined #lisp
Kundry_Wag has quit [Remote host closed the connection]
ebrasca has quit [Remote host closed the connection]
esrse has joined #lisp
nirved has quit [Ping timeout: 252 seconds]
chens has quit [Remote host closed the connection]
anewuser has joined #lisp
dddddd has quit [Remote host closed the connection]
eminhi has quit [Ping timeout: 245 seconds]
eminhi has joined #lisp
mindCrime has joined #lisp
dale has joined #lisp
malice has quit [Ping timeout: 256 seconds]
robotoad has quit [Quit: robotoad]
igemnace has quit [Quit: WeeChat 2.3]
igemnace has joined #lisp
<p_l>
elderK: afaik they aren't needed because the system binds much later
shifty has quit [Ping timeout: 250 seconds]
igemnace has quit [Client Quit]
igemnace has joined #lisp
robotoad has joined #lisp
arescorpio has quit [Ping timeout: 250 seconds]
<equwal>
Is there a way to get a double-backquote macro like this one to evaluate without using EVAL? How might I do that?
<equwal>
(lister 'first 'second) -> (list first second)
<equwal>
oops (lister 'first second) -> (list first second)
<equwal>
But I'm aiming for (lister 'first second ) -> (list <value of first> <value of second>)
_death has quit [Ping timeout: 272 seconds]
eminhi has quit [Quit: Lost terminal]
smokeink has quit [Remote host closed the connection]
fitzsim has joined #lisp
smokeink has joined #lisp
<Bike>
the problem is with second
<Bike>
the macroexpander function receives the form SECOND as an argument, and you want the value of that form in the macroexpansion
actuallybatman has quit [Ping timeout: 246 seconds]
<Bike>
you have to get from point a to point b somehow
<equwal>
I got it to work with a wrapper,
<equwal>
(defmacro outer-lister (x y)
<equwal>
`(lister ,(cadr x) ,y))
<equwal>
I often find myself in a situation where I want to change the evaluation of a complicated macro and I just can't seem to get it done.
<pillton>
Why?
<equwal>
Using cadr also seems like a massive kludge to unquote something.
<equwal>
Well I have a function like `LET` that has some binds and code, but I want to be able to pass the binds as an environment variable instead of as raw code.
<pillton>
Do macros related to your LET like operator retrieve something from the environment?
<equwal>
I was putting together a FORTH in elisp, and it makes sense to call it with something like (eforth ((forth-fn . elisp-fn) ...) forth-code). Once I wrote that I realized that I needed to be able to write (eforth *ENV* forth-code) for code reusability .
mindCrime has quit [Ping timeout: 245 seconds]
<Bike>
oh, so you don't want the value in the expansion.
pierpa has quit [Ping timeout: 256 seconds]
<equwal>
Well I need the expansion of the new eforth-wrapper to be (eforth *env* forth-code) -> (eforth-old <val of env> forth-code)
<Bike>
i think you should probably just use a function for the basic semantics
xkapastel has quit [Quit: Connection closed for inactivity]
<no-defun-allowed>
run, run far away
shrdlu68 has joined #lisp
drewes has joined #lisp
makomo has joined #lisp
<equwal>
Hopefully you aren't doing that in an effort to learn the language
<emaczen>
equwal: I might have my own parser that can be expressed in a BNF variant
frgo has joined #lisp
frgo has quit [Remote host closed the connection]
frgo has joined #lisp
varjag has joined #lisp
meepdeew has quit [Remote host closed the connection]
frgo has quit [Remote host closed the connection]
kajo has joined #lisp
varjag has quit [Ping timeout: 250 seconds]
frgo has joined #lisp
frgo has quit [Ping timeout: 250 seconds]
frgo has joined #lisp
mht has quit [Ping timeout: 250 seconds]
frgo has quit [Ping timeout: 272 seconds]
frgo has joined #lisp
<splittist>
good morning everyone
<beach>
Hello splittist.
frgo_ has joined #lisp
frgo has quit [Remote host closed the connection]
angavrilov has joined #lisp
irdr has quit [Ping timeout: 268 seconds]
easye has quit [Remote host closed the connection]
robdog has joined #lisp
Cymew has quit []
varjag has joined #lisp
frgo_ has quit [Remote host closed the connection]
frgo has joined #lisp
dddddd has joined #lisp
Guest12374 has joined #lisp
elfmacs has joined #lisp
Cymew has joined #lisp
kajo has quit [Ping timeout: 250 seconds]
nolanv has quit [Ping timeout: 246 seconds]
nolanv has joined #lisp
smokeink has joined #lisp
jochens has joined #lisp
lisbeths has quit [Remote host closed the connection]
jxy has quit [Read error: Connection reset by peer]
jxy has joined #lisp
dvdmuckle has quit [Ping timeout: 246 seconds]
groovy2shoes has quit [Excess Flood]
groovy2shoes has joined #lisp
nirved has joined #lisp
dvdmuckle has joined #lisp
hhdave has joined #lisp
hhdave_ has joined #lisp
impulse has quit [Ping timeout: 246 seconds]
anewuser has quit [Ping timeout: 250 seconds]
impulse has joined #lisp
hhdave has quit [Ping timeout: 246 seconds]
hhdave_ is now known as hhdave
elfmacs has quit [Disconnected by services]
elfmacs has joined #lisp
elfmacs has quit [Client Quit]
heisig has joined #lisp
lavaflow has quit [Ping timeout: 246 seconds]
themsay has quit [Ping timeout: 250 seconds]
themsay has joined #lisp
neosloth has quit [Read error: Connection reset by peer]
elderK has quit [Quit: WeeChat 1.9]
Mr-Potter_ has joined #lisp
eminhi has joined #lisp
elderK has joined #lisp
_death has joined #lisp
schjetne has joined #lisp
jochens has quit []
pierpal has quit [Quit: Poof]
pierpal has joined #lisp
jochens has joined #lisp
jochens_ has joined #lisp
frgo has quit [Read error: Connection reset by peer]
frgo has joined #lisp
pierpal has quit [Remote host closed the connection]
jochens has quit [Ping timeout: 246 seconds]
robdog has quit [Remote host closed the connection]
yoonkn has quit [Remote host closed the connection]
<schjetne>
May I ask a not-strictly Lisp question here, since you'd probably have to be a Lisper to understand what I'm talking about? If so, does anyone have any ideas how to get around the lack of restarts in non-CL exception systems?
<beach>
Try us! :)
<no-defun-allowed>
C's setjmp is what I usually refer to for unwinding.
<no-defun-allowed>
Actually, no, that's closer to blub style exception systems.
<schjetne>
I'm doing the classic PCL log processing task, where I have files with lines that in turn has fields. If a field fails to parse I want to log an error, but I obviously want to log which file and line it is. So I have the choice between catching at the file level, and then losing every other line and field, or pass filename and line number to the field parsing routines, which means boilerplate and coupling
<beach>
schjetne: You should be able to implement a near-complete Common Lisp-style condition system in C.
<schjetne>
This is Kotlin, which biggybacks on the Java system and the JVM
<heisig>
schjetne: Depends on the language of your choice. C++ -> use Clasp, C -> use ECL, Java -> use ABCL :)
<schjetne>
*piggybacks
<heisig>
Heh, Kotlin + ABCL sounds interesting.
Zaab1t has joined #lisp
eminhi has quit [Ping timeout: 250 seconds]
<schjetne>
I've made a typesafe DSL in Kotlin, which is nice for non-programmers (or programmers not heavily invested in the codebase) since they can get handy completion and typechecking. I suppose it's possible to consume the result of the DSL in ABCL
<heisig>
Alternatively, you could check how ABCL implements restarts.
Guest12374 has quit [Read error: Connection reset by peer]
<schjetne>
One option is to pass a callback that is the restart to the line parser which in turn passes it to the field parser where the throwing happens
nowhere_man has joined #lisp
<schjetne>
But that sort of defeats the purpose of exceptions, when you have to do all kinds of in-band signalling, you're not far from manual error checking like old-fashioned C, or the pure functional languages.
<ogamita>
Nope, kotlin means android, means non-JVM java VM, means not ABCL.
<schjetne>
ogamita: I'm using the standard OpenJDK
<ogamita>
in that case, ok, ABCL could help you.
<schjetne>
So ABCL is an option (but I'm not sure I want to deal with a lot of foreign function calling)
<ogamita>
it would be a nice project to add dalvik and ART as backends to ABCL…
<ogamita>
schjetne: Ken Pitman has a metalinguistic implementation of the CL condition system including restarts; it could be ported to any language… (theorically).
<schjetne>
Another option could be to pass the responsibility on the error logging system to know in which file and line the problem happened (and ideally which line in the DSL files too, I wonder if that could be somehow extracted)
<schjetne>
But that probably means still passing something as explicit parameters, Kotlin lacking dynamic scope.
<splittist>
If the logger wraps the parser and provides the stream(s) to the parser, then it can track stream progress, perhaps.
<v0|d>
whats the least system ram that I can run a lisp machine on?
<beach>
v0|d: What kind of "lisp machine" did you have in mind?
* Odin-
needs to mess around with ulisp.
<Odin->
Would be interesting to see if it can be extended to use an SPI RAM chip.
<schjetne>
Maybe I can throw a list of all the exceptions thrown when passing the fields, and then throw a list of all the exceptions thown when parsing the lines, and catch all of them in order at the file level.
<no-defun-allowed>
David Schmidt was selling a macivory machine with 4 megawords which is about 16 to 20MB of memory if you wanted something modern-ish and not embedded.
<v0|d>
beach: i tried to compile small ECL binaries back in the day yet faild to run on routers
<no-defun-allowed>
Did you use the right libc and kernel headers?
<schjetne>
Java exceptions have a notion of a cause, which can be another exception. In this case there would be multiple causes. There would be no way to control the restart behaviour, but it should do the trick.
<no-defun-allowed>
Embedded machines are very, very picky about those AFAIK.
<v0|d>
no-defun-allowed: yeah I know.
<v0|d>
now I have a chance to control the distro so i'll give it a try next month.
<v0|d>
I now have the infrastructure to cross compile a linux rootfs/kernel
<v0|d>
beach: any plans to add coroutines to cmu or sbcl?
esper0s has quit [Remote host closed the connection]
lavaflow has joined #lisp
``Erik has joined #lisp
<jackdaniel>
v0|d: you may be interested in fact that green threads (coroutines) and delimited continuations will be in next ECL release
<shka__>
jackdaniel: both green threads and native threads?
<jackdaniel>
native threads are already there, no need to add them
<jackdaniel>
but yes, it will be possible to use both at the same time (i.e a few native threads on which multiple green threads run)
<shka__>
wow
<shka__>
pretty awesome
xificurC has joined #lisp
<loke`>
jackdaniel: That's very intyeresting. What does the API look like? Similar to Scheme?
<loke`>
(i.e. call-with-current-continuation)
<jackdaniel>
I can dig it up (I have it somewhere saved)
<jackdaniel>
(documentation that is)
<elderK>
Lo all
jmercouris has joined #lisp
<jmercouris>
does anyone know of a cl library for sqlite that doesn't use cffi/libsqlite.so?
<minion>
jmercouris, memo from elderK: Upvoted :)
<jmercouris>
elderK: Nice, thank you :)
<jackdaniel>
loke`: http://hellsgate.pl/files/6d156f6b-user.pdf (navigate to multithread) - this is old ecl documentation from before introduction of native threads (coroutines evaporated in a meantime)
<jmercouris>
I'm trying to completely eliminate cffi from my application, and if I can't find a suitable replacement for a sqlite wrapper, then I'll have to implement my own pseudo database with files in Lisp :D
<elderK>
:P I take it Minion is not useful for /private/ memos? :P
<Odin->
jmercouris: So, you're basically asking if someone has reimplemented SQLite in Common Lisp?
gxt has quit [Ping timeout: 252 seconds]
esrse has quit [Ping timeout: 246 seconds]
<jmercouris>
Odin-: yes, more or less
<jackdaniel>
if you refuse to use ffi you don't have many options left. you either need a database which you may access via some wire protocol and set up on the machine (i.e postgres), or you serialize/deserialize data
<jackdaniel>
cl-store is useful for the latter approach
<jmercouris>
jackdaniel: what are the advantages of cl-store vs just printing and then reading the data structures from a file?
<jackdaniel>
as of sqlite: it is not a standard but rather sql database engine, so "cl library for sqlite" doesn't make much sense, "clone of sqlite" would be a better phrasing
<jmercouris>
e.g. let's say I have a list of alists, why not just print them to a file? why might I use cl-store in this case? not trying to argue, trying to understand
<jmercouris>
ok, so, what do you think I should do?
<jackdaniel>
cl-store may serialize for instance hashtables (you'd have to effectively reinvent serialization by yourself if you insist on printing objects to file)
<jackdaniel>
conditions, classes etc
<jmercouris>
jackdaniel: aha, I see, good point!
<jmercouris>
so if I end up serializing things that aren't simple lists of strings or something, then it would be quite useful
<jackdaniel>
also serialization format may be (not necessarily is!) more compact and faster to read/write to disk / over the network
<Odin->
Particularly because there's a bunch of types with no readable form mandated by the standard...
<jmercouris>
so here's another question, that is on a completely different track
<jmercouris>
let's say you are developing a system, and you want it to depend on another system
<elderK>
Interesting. Alexandria really doesn't like being "bundled"
<jmercouris>
that you are also developing, would you put those in the same repository, or different reposiitories?
<jackdaniel>
afair cl-store allows specializing your own serialization backend
<jmercouris>
jackdaniel: I believe you are correct with regards to that
<shka__>
yes
<Odin->
jmercouris: The thing about SQLite is that it's a full-featured relational database. It can do a _lot_ of neat tricks that aren't obvious if you're just thinking about storing values by key. :p
<jackdaniel>
as of question what I think you should do: I think you should access sqlite via ffi
<jmercouris>
rather than reinvent my own pseudo-db
<jmercouris>
I see
<jmercouris>
maybe this is a bad reason, but I'm highly motivated by issues in distribution
<Odin->
SQLite is everywhere.
<jackdaniel>
and regarding the second question: keep dependencies in the same repository and update them after testing they work (for builds), but also mainain a separate repository if you want to publish your library i.e on quicklisp
<Odin->
Seriously.
<jmercouris>
jackdaniel: like a mirror repository or something?
<jmercouris>
ok, I will do that
<jackdaniel>
it depends what you plan to do. if you are interested in providing final builds, then versioning all dependencies makes a lot of sense
<jackdaniel>
if you publish a library - not so much
<jackdaniel>
if you want something in between, well, there is no good answer.
<jmercouris>
Odin-: that's not my issue per se, for example, when I distribute a binary for macOS, I think some users are having issues because the image contains paths to locations of sqlite on my disk (because I installed via macports), things like that
<jmercouris>
s/(because I installed via macports)/(because I installed sqlite via macports)
<jmercouris>
ok, I will see how this part of the codebase evolves, and maybe I will break it out into a library depending on its usefulness/whether I decide to keep sqlite or not
<jmercouris>
however, I appreciate the advice and will take it into consideration
<jmercouris>
I will look at what kind of data structures I plan on persisting/traversing and decide if it is simple enough to do in just lisp
<jmercouris>
maybe my needs aren't as great as something a powerful facutly like sqlite provides
<jmercouris>
s/facutly/faculty
<Odin->
Hrm. I haven't really dealt with binary images much, but I'd presume there's a way to have the FFI object loading (which shouldn't depend on the exact location, but use system configuration) to happen when the image is loaded?
<jmercouris>
Odin-: probably there is, that sounds reasonable enough
<jackdaniel>
Odin-: yes, cffi looks in standard locations by default
fikka has quit [Ping timeout: 245 seconds]
<Odin->
jackdaniel: I'm just leaving space for the possible existence of completely insane implementations. :p
<jmercouris>
the issue with macOS, is that a user using brew, will not have things in standard locations
<jmercouris>
I have another question, where can I learn more about how struct comparison is done for a hash table with a :test of equalp?
<Odin->
Isn't there a way to have brew expose its environment to an application?
<jmercouris>
Odin-: I would not know, I don't use brew :\
<jackdaniel>
jmercouris: in clhs
<elderK>
Guys, is there a way to get ASDF to spit out an ordered list of files, like, that it loads for some system?
<jackdaniel>
namely: description of equalp
<elderK>
Say, "Gimmie a list of files in compile/load order, respecting dependencies."
<jackdaniel>
elderK: fat chance, but I'd like such feature
<elderK>
Darn. It would be really useful.
<jackdaniel>
you may dig into asdf's "plans" and try to generate such output from it
<jackdaniel>
because during first past indeed a "plan" is created
<jackdaniel>
and in theory it has all the information you need to load/compile system
fikka has joined #lisp
<jackdaniel>
another super-userful feature I'd love to see is: dump plan into a file which may be loaded without asdf involved to (say) compile the system
<jmercouris>
jackdaniel: so you are saying that a hash-table in CL will literally traverse a whole list and use equalp as a comparator to find an object?
<jmercouris>
so the access times must be very slow then, no?
<jmercouris>
or, rather, the access time, would grow with the size of the hash table
<jmercouris>
if the above is true, it is erroneously called a hash table, and should be instead called a dictionary
<jackdaniel>
I'm not saying anything, I'm just redirecting you to the specification
nolanv has quit [Ping timeout: 246 seconds]
<jmercouris>
the specification of equalp, which implies it is using the equalp function
<jackdaniel>
you may also benefit from reading cleanup issues on make-hash-table
<jmercouris>
I'll investigate, thanks
<jackdaniel>
equalp was not initially planned to be an option for hash-tables, but a demand has been envisioned
<jackdaniel>
another nice reference to read is "equals" predicate writeup in CDR
nolanv has joined #lisp
nolanv has quit [Client Quit]
schjetne has quit [Ping timeout: 250 seconds]
<ogamita>
jmercouris: for postgres, there's a socked-based interface.
gxt has joined #lisp
pierpal has joined #lisp
<jmercouris>
hmm, but that still makes distribution hard, but neat to know nonetheless
<elderK>
ogamita: I wouldn't want the structure to be reinstantiated over and over, though.
pierpal has quit [Read error: Connection reset by peer]
igemnace has quit [Ping timeout: 246 seconds]
irdr has joined #lisp
<ogamita>
elderK: See: 3.2.4.2.2 Definition of Similarity
<elderK>
THank you
igemnace has joined #lisp
<ogamita>
elderK: IMO, by default structures are not similar one to the other. This section says that make-load-form defines a similarity between its argument and the object produced by its result, which is necessary for logical consistency. But it says nothing of the similarity between two different structures that happen to have the same slots.
<ogamita>
elderK: Therefore, AFAICS, CL will do no coalescing of the structures, but make-load-form could return a form that would internalize the structures it would create, and it could return several times the same one.
<ogamita>
ie. you would have to implement the interning of structures yourself.
pierpal has joined #lisp
<elderK>
ogamita: Well, I use make-load-form already. But, like, you know, it expands to a form that recreates some instance, say.
<ogamita>
But notice what I said above: unquoted -> no expectation of coalesing or immutability. make-load-form couldn't known if the instance was quoted or not!
<elderK>
But if I have some expansion: `(thing ',structure)
<elderK>
Or ,structure or whatever, I'd prefer it didn't keep calling (make-instance ...) every time that form was executed.
<elderK>
(Class, not structure)
<ogamita>
So if you implement such a internalizing make-load-form, you should document it clearly that all your structure literals should be considered immutable, quoted or not.
<elderK>
Is it possible to have a "class literal"?
<ogamita>
You can define a reader macro to read such a literal.
<ogamita>
See for example the file format for gsharp.
<shrdlu68>
elderK: Yes, it's the programmable PL after all :)
<elderK>
I'm not sure what I want to do is sensible, anyway.
<elderK>
There's a "top-level" function, read-from. It expects a symbol denoting the type to read, etc.
pierpal has quit [Read error: Connection reset by peer]
<elderK>
Then there are other functions, that don't do type checking and are internalish. They are specialized on type metaobject.
<elderK>
%read-from say.
<ogamita>
You can use: (#1=#S(point :x 1) #1# #1#)
<ogamita>
then it won't be instanciated several times.
razzy has joined #lisp
<elderK>
My macro expands into a call to read-from, rather than %read-from. Because, at that point in the expansion, there is no "visible" metaobject. The macro expander knows the metaobject (and that metaobject /will/ be avilable at runtime)
<elderK>
So I was thinking I could side-step that read-from, and use %read-from with a 'class literal', patched into the expansion
<elderK>
But I don't think doing that will really buy me much.
<elderK>
All the current way means is that there is some extra type-checking done, and a conversion from the "symbol" to teh "type metaobject"
<Odin->
jmercouris: Common Lisp's type system is by no means a one-to-one mapping, which can also confuse.
<jmercouris>
I'm trying to fix the s-xml-rpc library which casts "t" to a string and "nil" to a string when returned by a function instead of a boolean
milanj has joined #lisp
<jackdaniel>
from topics nearby, alexandria has a predicate called empty
zch has joined #lisp
<jmercouris>
and by "t" and "nil" I mean T and NIL
nowhereman has joined #lisp
nowhereman is now known as Guest14049
<jackdaniel>
while T and NIL are all fine, I find what Scheme did much more practical
nowhere_man has quit [Read error: Connection reset by peer]
<Odin->
jackdaniel: My guess is Common Lisp was constrained by history.
<Odin->
It was, after all, not a specification from an empty slate.
<jmercouris>
It seems we are paying tech debt since the dawn of time, here we are running x86 processors...
m00natic has joined #lisp
<jmercouris>
lots of sunken cost fallacy, but we are too short sighted as a species :D
<jmercouris>
anyways, sorry for the off-topic rant
<jackdaniel>
sure, I get that (and I'm not complaining), I'm just pointing out that it is a little unfortunate at various occasions
<Odin->
jmercouris: Sunken cost is only a tiny part of the issue here.
<Odin->
Network effects are at least as big a contributor.
smokeink has quit [Remote host closed the connection]
<jackdaniel>
_death: I saw that, funny :-)
drewes has quit [Ping timeout: 246 seconds]
<Odin->
... there is that, of course.
eminhi has joined #lisp
fikka has quit [Ping timeout: 250 seconds]
smokeink has joined #lisp
pierpal has joined #lisp
solyd has quit [Quit: solyd]
<ogamita>
and by the way in scheme, else can be redefined, so (cond #f (else 1)) may return #void.
<ogamita>
So better write it (cond #f (#f 1)).
<ogamita>
(ie. hygienic macros are not; notice that cond is defined as an hygienic macro).
jsc has joined #lisp
jsc is now known as status402
solyd has joined #lisp
pierpal has quit [Ping timeout: 268 seconds]
nicksmaddog has joined #lisp
anewuser has joined #lisp
fikka has joined #lisp
optikalmouse has joined #lisp
<elderK>
ogamita: I wonder if hash tables have a "load form"
<elderK>
I'll have to check
zch has quit [Quit: Leaving]
zch has joined #lisp
<jackdaniel>
they usually do, however hash-table class is not guaranteed to be a structure-class (like it is on SBCL) so it may fail on conforming common lisp implementation
warweasle has joined #lisp
optikalmouse has quit [Quit: optikalmouse]
<Bike>
Well Actually hash tables can be dumped yes
<Bike>
not necessarily printed readably though
<jackdaniel>
Bike: do I get this part wrong (from make-load-form): "Conforming programs may call make-load-form directly, providing object is a generalized instance of standard-object, structure-object, or condition."?
<Bike>
no, you're right that it doesn't have to be through make-load-form
<Bike>
it's possible i missed some context here, sorry
<jackdaniel>
ah, that's what you mean
<jackdaniel>
thanks
<Bike>
i mean, stuff like vectors are dumpable too, but not through make-load-form necessarily
<Bike>
(iirc ecl defines make-load-form for basically everything, though)
<elderK>
Loop is so darn handy.
<jackdaniel>
elderK: it is - until it is insufficient (or too complicated); it is not extensible and hitting undefined behavior with it is not that very hard given how it is specified
<elderK>
jackdaniel: A lot of the time I find that I can use a let, and a dolist or something inside that, but more often than not, I make use of loop.
<jackdaniel>
(i.e order of clauses, or variable values in finally clause)
<elderK>
Of course, it proably loops kind of horrible, since I use with = ... for hte same reason I'd use the surrouding let otherwise.
<jackdaniel>
most of the time I use mapc combined with collect macro, and if I'm in need for something more sophisticated I use DO (and in rare occasions I write a macro which is built on top of DO)
<jackdaniel>
but sure, simple cases are very easy with loop too
frgo has quit [Read error: Connection reset by peer]
shrdlu68 has quit [Ping timeout: 246 seconds]
smokeink has quit [Remote host closed the connection]
FreeBirdLjj has joined #lisp
schjetne has joined #lisp
<elderK>
jackdaniel: I feel this would probably be more complex if I had done it using let and other stuff: https://pastebin.com/BFXHLazL
Demosthenex has quit [Ping timeout: 250 seconds]
pierpal has joined #lisp
<elderK>
Is check-type effectively the same as (assert (typep object 'type)) ?
<Xof>
there's a loop and some fancy restarts as well
<elderK>
:P I wish check-type evaluted the type spec :P
<_death>
well, assert also has fancy restarts ;)
pierpal has quit [Ping timeout: 250 seconds]
Inline has joined #lisp
<elderK>
_death: :) I'll use (assert (typep .....))
<_death>
elderK: why not check-type?
Guest14049 has quit [Ping timeout: 252 seconds]
<_death>
is the type specified computed?
<_death>
*specifier
<elderK>
_death: Partly - I'm not sure it matters that much. I have subtypes of integer, defined based on binary-integer types.
<elderK>
These types for instance, ensure that a value is representable.
<elderK>
I'm using check-type integer in a few places, and I'd rather use check-type <the-actual-binary-integer-type>
<Xof>
you should be able to use subtypes of integer
<elderK>
The thing is, I don't know the precise type specifer until runtime
<elderK>
That's why I need to evaluate the type spec.
<Xof>
(check-type x (mod 4))
<Xof>
ah, well, then you must use a function call, yes
frgo has joined #lisp
<_death>
elderK: lisp supports wish-based programming.. you can define your own check-type-like macro..
<elderK>
_death: Aye :)
<elderK>
(assert (typep ...)) should be good enough for now, though.
<elderK>
_death: I'm trying to just... embace dynamicness :D
<elderK>
:P
pierpal has joined #lisp
<elderK>
If I have a make-load-form, and it calls some function in my package, does that function need to be exported from the package?
<elderK>
I imagine it does.
<_death>
packages don't contain or export functions
<elderK>
I mean, symbols :)
<elderK>
The symbol would need to be accessible, since the function I want to call is bound to that.
<elderK>
I have to stop murdering the terminology.
<elderK>
:D
dale_ has joined #lisp
dale_ is now known as dale
<jmercouris>
terminology can be important because it changes how you are thinking about the concepts
<elderK>
jmercouris: Very true
<elderK>
Damn, I really don't want to export this function.
drewes has joined #lisp
<jmercouris>
export this symbol*
<ogamita>
Then don't.
<elderK>
Maybe this is a time where :: would be useful - since the function is only ever going to be called from a macro's expansion.
<ogamita>
Nope, export instead an API you'd like.
<ogamita>
elderK: why don't you want to export the name of that function?
<elderK>
Because it's internal.
schjetne has quit [Ping timeout: 245 seconds]
<ogamita>
Then indeed, don't export it. As I said, write a public function that will call the internal function.
<elderK>
It's not meant to be exposed. The only reason I *want* to use it, as part of the form make-load-form returns.
<_death>
if you have a load form, there are no particular requirements of the symbols in it.. at load time, you need to make sure the package is there and when it is evaluated that they are fbound..
<ogamita>
export a generate-load-form function.
<elderK>
_death: So, I don't nee dto export them?
<ogamita>
Then could even be uninterned. (gensym).
<Bike>
elderK: the return value of make-load-form is not READ again, so the export status of symbols in it is largely irrelevant
<elderK>
Bike: Interesting. I thought it would be, so like, you know, it could reconstruct the whatever?
<Bike>
the form will be evaluated, in some sense. but there's no reason to READ the code in again, it's right there.
<Bike>
forms
jack_rabbit has quit [Ping timeout: 250 seconds]
Demosthenex has joined #lisp
<elderK>
I'm still not 100% on like... the details of make-load-form, and when the form it generates, is evaluated. How many times it is evaluated, etc.
<Bike>
when you load the fasl. once.
<Bike>
well, once per load.
Inline has quit [Remote host closed the connection]
sjl_ has quit [Quit: WeeChat 2.3-dev]
Demosthenex has quit [Ping timeout: 244 seconds]
sjl_ has joined #lisp
schweers has quit [Ping timeout: 264 seconds]
Demosthenex has joined #lisp
dale has quit [Quit: dale]
frgo has quit [Read error: Connection reset by peer]
solyd has quit [Quit: solyd]
heisig has quit [Quit: Leaving]
anamorphic has joined #lisp
anamorphic has quit [Client Quit]
anamorphic has joined #lisp
schweers has joined #lisp
<ogamita>
elderK: it's evaluated at load-time, when you load the fasl.
pillton has quit [Ping timeout: 264 seconds]
Inline has joined #lisp
zch has quit [Quit: Leaving]
Demosthenex has quit [Ping timeout: 246 seconds]
lnostdal has quit [Ping timeout: 250 seconds]
lnostdal has joined #lisp
solyd has joined #lisp
anewuser has quit [Ping timeout: 246 seconds]
fikka has quit [Ping timeout: 250 seconds]
FreeBirdLjj has quit [Remote host closed the connection]
ym has joined #lisp
FreeBirdLjj has joined #lisp
Demosthenex has joined #lisp
status402 has quit [Quit: status402]
FreeBirdLjj has quit [Ping timeout: 245 seconds]
josemanuel has joined #lisp
dddddd has quit [Remote host closed the connection]
mindCrime has joined #lisp
frgo has joined #lisp
cage_ has joined #lisp
FreeBirdLjj has joined #lisp
kajo has joined #lisp
meepdeew has joined #lisp
solyd has quit [Remote host closed the connection]
<elderK>
I post it here so you can take a look, if you find yourself bored and with nothing else interesting to do :)
<beach>
All those % signs are kind of distracting.
fikka has joined #lisp
schweers has quit [Ping timeout: 260 seconds]
lnostdal has joined #lisp
fikka has quit [Ping timeout: 246 seconds]
lowryder has joined #lisp
jmercouris has quit [Remote host closed the connection]
<elderK>
beach: :) I will try to avoid using such sigils in the next iteration, and in anything further I create.
<pfdietz>
My convention is to use % as the leading char of the names of flet or labels functions.
<elderK>
I need to learn more about such conventions. The Google Style guide doesn't really go into this stuff.
<elderK>
Still, I am mostly happy with what I have created so far. I am yet to heavily dog-food it. But, I feel like I'm made some progress.
slyrus2 has joined #lisp
varjag has quit [Quit: ERC (IRC client for Emacs 25.2.2)]
<elderK>
I guess the only way to keep improving, is to keep studying code written by others, continue posting here for feedback, and simply continue trying things.
<elderK>
And read relevant books :)
<beach>
Sounds right.
Khisanth has quit [Ping timeout: 244 seconds]
slyrus2 has quit [Remote host closed the connection]
CrazyEddy has quit [Ping timeout: 246 seconds]
Zaab1t has quit [Remote host closed the connection]
jochens_ has quit []
<pjb>
elderK: what is nil as a byte-order?
<pjb>
elderK: yes, %symbols should not be exported.
shka_ has joined #lisp
Zaab1t has joined #lisp
<pjb>
limiting yourself to 64-bit is not sane, it's insane and restrictive. IPv6 addresses are 128-bit, and in crypto, we often need even bigger numbers…
<elderK>
pjb: nil signals that the byte order is set dynamically, rather than hardcoded into the integer type itself. If byte-order is nil, the effective byte-order is determined by the current value of hte *default-byte-order* variable.
<elderK>
pjb: I have no hard limits.
<pjb>
%sane-bit-length
<elderK>
That is a non-zero multiple of eight. That's not 64bit.
<pjb>
For such enum types, you may consider using keywords.
<pjb>
Oh! right. I misread it. Sorry.
<elderK>
NP
Khisanth has joined #lisp
<pjb>
so, yes, % is used for "dangerous" functions, not just non-exported functions. Normal functions such as convert-from, convert-to, range, etc don't need it.
themsay has quit [Ping timeout: 250 seconds]
<elderK>
pjb: Even though they are not intended to be called by clients?
<pjb>
The "intended to be called by clients" is indicated by exporting the symbol.
jochens has joined #lisp
<elderK>
What is the convention for things that say, are not meant to be used by "general users", but can be used for "developers." Like, someone who's just using the library vs. those extending it
<elderK>
Or building on top of it.
<pjb>
elderK: I would define another package exporting the developer symbols.
<elderK>
pjb: I would like to learn when :: /is/ meant to be used.
<pjb>
k.binary.integers and k.binary.integers.api
warweasle_afk is now known as warweasle
<pjb>
Well, you use :: when you cannot do otherwise. Eg. when the developer of the library forgot to export a symbol that you really need to use. (and you can't patch the library).
<elderK>
So basically, avoid using :: at all costs. The current way I feel about it is "Beware"
<pjb>
But even in that case, it would be better to define a package exporting those symbols, since that would define clearl the API you are using.
<pfdietz>
Correct
<pfdietz>
:: is a code smell
<Colleen>
Unknown command. Possible matches: 8, time, set, say, mop, get, tell, roll, help, deny,
<pfdietz>
Thank you, Colleen
<elderK>
I wish package-local nicknames were universally supported :(
jochens has quit [Remote host closed the connection]
<pjb>
elderK: your parameter lists are strange: (offset type value vector). I would order them (type value #| -> |# vector offset)
<elderK>
The the #| -> |#?
<elderK>
*Why the
<pjb>
#| is a comment |#
<pjb>
I would group the parameter by category: input parameters first, output parameters next.
<pjb>
You may choose the other ordering if you want. But not mixing input and output parameters.
<elderK>
That makes sense.
hhdave has quit [Ping timeout: 250 seconds]
<pjb>
write-into has an implicit "parameter" which is the size of the integer written. It's specified by the type parameter. But since it takes an offset parameter, it would be better to return the size (or the new offset), rather than the value that has been written.
<pjb>
So one could make a loop to write several values easily.
<elderK>
I considered that too. And, yes, it would be more useful.
drewes has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
<elderK>
I will apply these suggestions :) And I will also work on getting rid of the %s and stuff.
<elderK>
Then unit tests, documentation.
xuxuru has joined #lisp
<sukaeto>
re: %, I always thought it was for implementation specific, or as pjb says "dangerous" functions
<sukaeto>
is there a sigil for "this symbol shall not be exported"?
<elderK>
Another issue, of course, is that I want to use short names like type-of and stuff, but CL already uses them :P
dvdmuckle has quit [Quit: Bouncer Surgery]
<elderK>
I know that's a horrible reason.
<sukaeto>
I sometimes put a . in front of symbols that name things that would otherwise be exported (e.g. slots whose accessor is named by the same symbol as the slot would be, if I didn't stick the . in the slot name)
<pjb>
Let's take an example. You implement a hash-table. There's a vector of buckets, and a function that finds the index to the right bucket. Not all buckects are filled with valid data. So if you use aref on the vector of buckets randomly, you could find invalid data and get bad results or behavior. Then you could have an accessor (%bucket ht index) that would let you use all the slots, but normal code should use (bucket-for-key ht
<pjb>
instead.
<elderK>
sukaeto: That sounds just as bad as %
dvdmuckle has joined #lisp
<pjb>
elderK: you can shadow symbols.
<elderK>
Can I shadow something in #:CL, if I use #:CL?
<pjb>
The only downside is that if you need to use a shadowed symbol, you need to qualify it: (cl:type-of 42)
<pjb>
Sure.
<elderK>
I will need to read more about packages and shadowing.
<elderK>
The (probably better) alternative is not to shadow, though, right? :)
<elderK>
Instead of %type, have binary-type. And instead of %name-of, have binary-type-name
<elderK>
And so on
anamorphic has quit [Quit: anamorphic]
<pjb>
For internal stuff, don't hesitate. If your shadowing symbol is exported, consider how your package will be used. If it's used with CL (or the package owning the symbol you shadowed), then you may consider defining a version of the CL package with your symbols instead, otherwise the user will have to use (:shadowing-import-from :your-package :s1 :s2 :s3 …)
<sukaeto>
elderK: well, on the one hand, I don't want to use something that has an understood meaning for a different meaning. On the other hand, I've never seen anyone else use a . prefix in Lisp - I kind of stole it from UNIX's hidden file model. So people may read that code and be like "wtf was this guy thinking?"
jkordani has joined #lisp
<elderK>
sukaeto: I always associated % with "private or internal" and ! as "BEWARE"
<pjb>
sukaeto: . is often used in examples showing how to implement standard operators, to avoid shadowing (or in scheme where no such shadowing exists).
<pjb>
(defun .cons (a d) (lambda (k) (funcall k a d))) ; for example.
<pjb>
(defun .car (k) (funcall k (lambda (a d) a))) (.car (.cons 42 33)) #| --> 42 |#
buffergn0me has quit [Ping timeout: 268 seconds]
jkordani_ has quit [Ping timeout: 252 seconds]
<elderK>
pjb: Other than the issues you have raised, are there any other major things?
mrd has quit [Ping timeout: 245 seconds]
<pjb>
So, for structure, you are basically re-implementing a simple MOP. Not bad. But eventually, perhaps you will learn about CLOS and the MOP, and then you will be able to implement your binary structures directly as a CLOS metaclass. This would give a better integration with CL.
<shka_>
pjb: he is aware of that possibility already
<shka_>
good evening everyone
<pjb>
Otherwise, it looks good.
<elderK>
pjb: I spent several days studying MOP and I have completed reading the book Jachy suggested. The main reason I avoided using the MOP here, was simply because it seemed that it would be simpler to do so.
<elderK>
Hey shka_.
<Jachy>
elderK: You're fast. :) Morning.
cage_ has quit [Remote host closed the connection]
<pjb>
Yes, it's not complex to implement a metaclass system :-)
<elderK>
:) shka_ suggested MOP to me a few days ago. It's definitely something I would like to move to. But only if necessary.
<elderK>
Particularly because I'm unsure of how to deal with class-style inheritance.
FreeBirdLjj has quit [Remote host closed the connection]
FreeBirdLjj has joined #lisp
<elderK>
pjb: Probably obvious but, can a class and a deftype have the same name?
<elderK>
Like, is there a "Class namespace" and a separate "type" namespace?
<elderK>
Actually, of course. find-class...
<pjb>
structures have single inheritance (the :include option). A given clos metaclass could restrict the number of superclasses.
<pjb>
elderK: defclass defines automatically a type of the same name.
<elderK>
pjb: I was more meaning like... CL defines classes for say, integer and cons and stuff. I was wondering if I could do the same, so that people could specialize on "primitive" binary types like unsigned integers and stuff.
<elderK>
pjb: Thank you for taking the time to critique my work. :)
<sukaeto>
elderK: and you may be right about that! The only reason I spoke up is because I'm pretty sure I'm doing it wrong (or at least, what I'm doing is less than ideal), and I wanted to see what other people in the channel would say.
<elderK>
Jachy: I found it a very interesting read. I especially enjoyed the contrasting of various OO approaches.
<elderK>
sukaeto: NP :) We're all learning, right? :)
FreeBirdLjj has quit [Ping timeout: 268 seconds]
<elderK>
sukaeto: I was curious if there was a standard convention for "I wanna call this variable SOMETHING but I can't, because it's shadow something else I need. So, I need to name it differnetly..."
<pjb>
Well, you use defclass to define some classes. So there are type designators of same name to designate their type already. The question would be if your classes weren't CLOS classes (or CL structures). How would you write (deftype foo () ?) You can always use satisfies I guess.
<sukaeto>
how's the old joke go? There are two hard problems in programming: Cache invalidation, naming, and off by one errors
<pjb>
elderK: you can play tricks: (let ((|my variable| 42)) (/ |my variable| 2)) #| --> 21 |#
<elderK>
pjb: I was more asking about how I could integrate my own "primitive types" just as things like "integer" and "list" are with CLOSs. Like, so you can specialize on something that is not a class instance, but a primitive.
<elderK>
Then again, "everything is an instance of a class"
<elderK>
Even integers and stuff - built-in classes, I guess
m00natic has quit [Remote host closed the connection]
<pjb>
\myvar or 𝚖𝚢𝚟𝚊𝚛 ;-)
<elderK>
I tend to the use the same conventions I use elsewhere: Shadowing is okay, if it's extremely obvious that they /are/ shadowed and stuff. Otherwise, use different names.
<Bike>
elderK: what would the actual representation of these objects be?
<pjb>
elderK: well the thing is that you cannot specialize built-in classes, only standard-classes and structure-classes.
<Bike>
CL mostly just lets you make structs and standard objects.
<pjb>
(and conditions).
<pjb>
which may or may not be structure or standard objects.
<elderK>
It would be nice if I could do the binary-parsing stuff without parsing integers and things byte by byte. But even so, doing it byte by byte avoids potential alignment issues if I were to use, say, CFFI to read integers...
<elderK>
And it also allows me to support a larger variety of potential sizes.
<pjb>
prefix ? is used for pattern variables. They're bound to the matched subexpression.
<elderK>
pjb: Say I did go the MOP route: I'd provide some macro, define-binary-class or whatever. But how could I stop people bypassing that?
<elderK>
I guess there really is no need to stop them, I guess.
<elderK>
Since define-binary-class would be the intended API. If they wanted to deviate or extend, well, you'd expect they knew what they were doing.
<pjb>
But outside of pattern matching, you can use them for whatever you want. ?![]{} are reserved for the user. (Specifically the dispatching reader macros #! #? #[ etc are formally reserved, nothing is said of the constituent characters ?![]{}, but we can consider them reserved).
<elderK>
I'd also like to learn more about type declarations, and when you should worry about them.
Colleen has joined #lisp
<pjb>
elderK: don't expect they know what they're doing. Provide a simple API that let them do what they want without knowing anything about it.
<elderK>
pjb: Right. But even if you do provide that simple API, people can still directly use defclass with your :metaclass and stuff.
<pjb>
True.
meepdeew has joined #lisp
<elderK>
I'd also need to think about how to make like, the read/write interface the same for "primitives" and "classes"
<elderK>
I guess you could easily manage that with eql specializers though.
<elderK>
Since for primitives like, integers and things, I'd still need to keep metadata.
<elderK>
Just not to structures / classes, since I'd be using the MOP for that
<elderK>
It could take care of the metadata.
Demosthenex has quit [Ping timeout: 250 seconds]
meepdeew has quit [Remote host closed the connection]
Demosthenex has joined #lisp
actuallybatman has joined #lisp
Guest14049 has joined #lisp
<pjb>
elderK: so basically, you need to define a type system to describe the binary types. This type system is not the same as the lisp type system.
<pjb>
elderK: you may want to have some gateway, some automatic correspondance between them, but it's not necessary.
<pjb>
elderK: the lisp values used to represent the binary values can be of different types/classes too.
<elderK>
Right.
<elderK>
Another detail I'd have to think seriously about is redefinition of classes and stuff with the MOP.
<pjb>
For example, you read a uint16/be as a lisp integer, character, bit-vector, etc. and vice-versa, to write a binary value, you can take different types of lisp values.
<elderK>
Like, if you redefined the class so that a slot's type were different. So, that the value in the instance is no longer conformant with the new type.
<pjb>
Including, you can define in lisp classes the ontology of binary types. Ie. a uint16/be could be an instance of a clos class uint16/be.
<elderK>
Right. But then you'd have to box your integers and things, no?
<pjb>
Well, with CLOS you can write update-instance-for-redefined-class methods.
<pjb>
elderK: Well, it wouldn't be the binary integer, it would be the CLOS representation of a binary integer.
<pjb>
like a DOM.
dddddd has joined #lisp
<elderK>
Well, yes. But that would mean for instance, instead of (+ int int) you'd have something like (+ (uint16/be-value whatever) ...)
<pjb>
Now, the advantage of that is that you can create a representation of binary structure as lisp objects.
<pjb>
and have an automatic way to convert the lisp objets to the binary representation.
<pjb>
Yes.
<elderK>
That adds a lot of overhead?
<pjb>
Now there's also the possibility to keep the binary values, and to have in lisp descriptors that will let you access the binary values directly.
<pjb>
Some.
<elderK>
I'm not sure I follow :)
<pjb>
In all cases there will be overhead.
<pjb>
The question is when you want to do the conversion between lisp objects and binary objects.
<elderK>
Well, the idea I was going on was that "binary types" were just... restricted or otherwise limited "normal Lisp types." The actual serialization of values is done as late at possible.
CrazyEddy has joined #lisp
<pjb>
In lisp you can manipulate the descriptor, and convert the value on-demand when needed. Or you can convert into a DOM (to keep the ontology of the binary type in lisp). Or you can convert into lisp objects (but then it's more complicated to make the correspondance between the two type ontologies, you may have to add descriptors, or you may have some ambiguities.
<pjb>
Ok. It's a choice.
<elderK>
I think I get what you're saying :)
<pjb>
Unfortunately, with this choice, we have the problem of lisp classes vs lisp types. a uint8 is a lisp type, but an instance of the same integer system class as a int32…
<pjb>
And we cannot define a subclass of cl:integer.
<elderK>
Aye. So you are unable to effectively specialize on say, uint8. Just "integer"
<elderK>
Yeah, exactly.
<pjb>
Hence you need to pass along the foreign type, like we do in cffi.
<elderK>
I mean, there are some real advantages to having the ontology as Lisp classes. But there are, imo, serious costs to that, too.
<elderK>
Since the idea for my library is to make it so you deserialize /to/ Lisp values. Or serialize /from/ Lisp values to binary.
<elderK>
I would like to avoid like, "boxing" as much as possible.
<elderK>
But of course, as you have noted, you wind up having to pass "type"s along somehow, since you cannot specialize on your more restricted primitive types.
<elderK>
That's why I was asking earlier, if we could extend the "primitive classes" that CLOS can specialize on.
<elderK>
But as you said, you cannot subclass "integer"
<elderK>
Which is a shame.
<pjb>
Well, if the boxing can store directly into the binary structure, it can still be efficient. But it depends on the operations you do. If you need to perform algorithmic operations on this data, it's better to keep it as pure lisp data, and to convert only for I/O.
<elderK>
Right.
<elderK>
The idea is that the binary "classes" are mostly just for "transport." You deserialize to an instance of them, so you can easily "get at" the values and stuff.
<elderK>
Also, note that my main target for use is with Mezzano.
<elderK>
That, at least to me, makes it more important to avoid any unnecessary boxing and things.
<pjb>
The other alternative, is to have your own class, so you can subclass an integer class, but then you will need an accessor when you want to use the value in lisp, because there are funcallable objects, but not "artimeticable" objects, or "sequencable" objects (but some implementations have extensible sequences).
<elderK>
This would be used to say, easily parse say, an inode structure.
vlatkoB has quit [Remote host closed the connection]
<pjb>
elderK: you may have a look at com.informatimago.common-lisp.heap.heap ; there, I implemented operations on the binary types to keep them in the binary store, instead of doing the operation in lisp.
<elderK>
The idea I have in mind is that computation is done on the /deserialized/ values. So, the Lisp values. When you operating on the stuff, you are not directly messing with the "binary" stuff. There's a very clear separation: You are always working on Lisp values. But you can convert binary to LIsp, and Lisp to Binary.
<elderK>
Unfortunately, urxvt is not matching those URIs.
<elderK>
Still, bookmarked for later study :)
<pjb>
Does you irc client log the conversations?
<elderK>
As for the cost of boxing, it really depends on how smart implementations are. If you have a class, say, with a "primitive" slot, you'd hope that would be stored directly in the class instance, if at all possible.
<pjb>
Then you can easily copy those url from the (local) log file.
<elderK>
No, it doesn't. But it's okay - I have booked your Github in general.
<pjb>
Indeed. AFAIK, it's possible with CLOS/MOP.
<elderK>
pjb: It really depends on how storage is handled. I guess you could for instance, create a special metaclass solely for "primitives" And make it so they store their values in-line, if possible.
<elderK>
Messed up sentence but I figure you get my meaning.
<elderK>
Using an "object ontology" would make the "IO functions" a lot more natural, though
<elderK>
Just write <thing> rather than write 'type thing
fikka has joined #lisp
Essadon has joined #lisp
<pjb>
You may also have a look at ASN.1 They have the same problem. Or even JSON.
<elderK>
Problem is, you'd wind up having two translation steps. First, deserializing from whatever to the "object ontology" version of the thing. Then you'd have another stpe, where you "unboxed" everything you cared about.
LiamH has joined #lisp
<pjb>
ie. binary is nothing special or primitive; it's just a given format with a given ontology, and we have to convert between two different worlds, with some in common and some quite different.
<Bike>
elderK: the problem with storing values unboxed is that the compiler has to cooperate in order to avoid unnecessary boxing/unboxing operations around accessors. this means the compiler has to be aware of the types of slots and accessors when compiling calls to accessors. this makes redefinition of the slot difficult (in general requiring recompilation of all code that calls the accessor)
<elderK>
I think for the time being, I will stick with the (write 'type ...) approach.
<elderK>
Since it better maps to my intended uses.
<Bike>
accessors, i guess
<Bike>
reader writer
<Bike>
as such, i'm not sure that any implementation stores unboxed values in standard objects
<elderK>
Makes sense.
<pjb>
elderK: if you have the time, try to implement several different ways. all lisp, DOM (the foreign ontology in lisp classes), all binary (possibly with CLOS/MOP).
<Bike>
if you do want unboxed values in a custom data type, defstruct is more likely to work, because redefining it is undefined.
<elderK>
It would be interesting. But I really, really want to avoid forcing people to manually box/unbox from Lisp values to the ontological ones.
<elderK>
Then again, you could have a "wrapper"
<elderK>
so that you have a layer that is like (write 'type value) which really just does the boxing and stuff behind the scenes.
Demosthenex has quit [Ping timeout: 240 seconds]
gxt has quit [Ping timeout: 268 seconds]
<elderK>
I guess you could also define a standard protocol for "boxing" and "unboxing" things. Like, unwrap <ontological-instance> and wrap <ontological-type-name> value
Demosthenex has joined #lisp
<elderK>
I really do wonder how like, things like Genera and stuff /did/ do efficient binary IO and stuff. I mean, for processing network formats and all kinds of things, I imagine you'd want the mapping to be as simple and fast as possible.
<elderK>
And cutting down on garbage would also be important too, I imagine.
fikka has quit [Ping timeout: 250 seconds]
<elderK>
So much to think about :) You've given me lots of ideas to digest.
<pjb>
basically, yes, lisp machines had low-level tricks (kind of like C casting, but with safety, since the memory slots are still type tagged).
<elderK>
Why are your symbols in the package not symbols buut strings?
<pjb>
Because packages use lists of strings, not of symbols. But most package operators accept string designators, ie. string, symbols or characters, to designate strings.
yvy has joined #lisp
<pjb>
So, we don't use normal symbols in defpackage, because they are interned in the current package, and when you use the defined package, there's a lot of collisions.
<elderK>
Right. So, that's why some people say #:every-symbol
<pjb>
Instead, we may use uninterned symbols, but I find it #:ugly, or keywords, but this fills the :keyword package. Finally strings have the advantage of uninterned symbols, but they're "NICE".
<elderK>
The main problem I see from using strings, is that it's up to settings as to whether 'foo is "FOO" or "foo"
<elderK>
:) So, largely personal preference.
<pjb>
Now there's the consideration about readtable case. Using uninterned symbols has the advantage of using the readtable case. While using strings requires typing the absolute name case.
<elderK>
I don't find "FOOBAR" any better or worse than #:foobar
<pjb>
Also, I like uppercase letters, I have fonts that draw them nicely.
* elderK
nods
<pfdietz>
Small caps font, as used by Death.
<pjb>
I learned programming in the 70s, there were a lot of terminals and printers with only upper case then.
<pjb>
Honestly, this makes a difference only when used in implementations with a "modern" mode implemented badly. Ie. with allegro CL (mlisp instead of alisp). clisp has also a modern mode (per package) so it doesn't break.
<elderK>
Modern mode?
<pjb>
where symbol names are lowercase by default.
<pjb>
So we don't have |CL|:|PROGN| but |cl|:|progn|.
<elderK>
:) SBCL shouts at me all the time :D
<elderK>
I figure it's like me, hard of hearing at times :)
<pjb>
You can put (setf *print-case* :downcase) in your rc file.
<pjb>
Since I do a lot of copy-paste from my repl to irc, I've this in my rc-file, so: (intern "FOO") #| --> foo ; :internal |# <--
<elderK>
I think I will do that :)
yvy has quit [Read error: Connection reset by peer]
wusticality has joined #lisp
nicksmaddog has quit [Ping timeout: 272 seconds]
pierpal has quit [Read error: Connection reset by peer]
pierpal has joined #lisp
Zaab1t has quit [Quit: bye bye friends]
milanj has quit [Quit: This computer has gone to sleep]
Demosthenex has quit [Ping timeout: 250 seconds]
nicksmaddog has joined #lisp
<pjb>
elderK: just beware that sometimes there's buggy code that use format ~A to build symbol names from symbols or other, and therefore you'll get downcased symbol names! Just non-buggy libraries instead ;-)
rippa has joined #lisp
<elderK>
pjb: How should you build symbols, assuming you are not using Alexandria? :)
<Xach>
phoe: i left you a comment re: protest breakage
<elderK>
Allo Xach!
<Xach>
elderK: hello
meepdeew has joined #lisp
<elderK>
Xach: How long do you think it will be before package-local nicknames are universal? :D Alternatively, how important it is these days to really "support" implementations other than say, SBCL or ECL?
<shka_>
elderK: ccl is working toward it
<Xach>
elderK: I think there needs to be a next round of planning and implementation of package-local nicknames. i don't think the current crop are adequate.
nicdev has quit [Ping timeout: 240 seconds]
<Xach>
I have a personal idea of how it can be done better but I have to get it out into the world for refinement (and rejection or acceptance)
<Bike>
oh, how so?
<Bike>
when i implemented them for clasp i just copied sbcl
meepdeew has quit [Remote host closed the connection]
<Xach>
I think it can (and should) be done without adding any new package.
<elderK>
Xach: Yeah, I'd definitely be interested in hearing shortcomings of say, SBCL's method
<Bike>
adding a new package to what?
<Xach>
Bike: "adding" isn't a good word. i mean using sb-ext, or ext, or sys, or whatever, to make use of them.
<Bike>
Oh.
<Xach>
I want portable use of package-local nicknames without compatibility layers, and I think it can be done.
<Bike>
So you don't want introspection functions, or what?
<Xach>
Bike: I think they can be done with standard CL functions with extra arguments and return values.
drewes has joined #lisp
<Bike>
i don't think adding return values to standard functions is allowed by the standard.
<Xach>
Neither are package-local nicknames.
<Bike>
i mean, not having a compat layer sounds nice, though
<Bike>
no, they're allowed as an extension, i think, but adding return values as an extension is specifically not allowed
Demosthenex has joined #lisp
<Xach>
Bike: that sounds relevant, do you happen to know where that's spelled out?
<Bike>
i think adding extra &key arguments might be okay, but i'm not sure
<Xach>
Bike: can't get any clearer than that. well, then my proposal wouldn't conform to that. bummer.
xuxuru has quit [Quit: xuxuru]
<Bike>
well, i think package local nicknames would mostly just be used in the form of :local-nicknames or whatnot in defpackage, which doesn't really require a compatibility layer
<Bike>
doing introspection stuff is a little rarer i think
kajo has quit [Ping timeout: 252 seconds]
kajo has joined #lisp
vlatkoB has quit [Remote host closed the connection]
marvin2 has joined #lisp
varjag has joined #lisp
slyrus1 has quit [Quit: slyrus1]
<elderK>
I have a question about the reader. Particularly with macro characters. The cylicness of the reader kind ofhurts my brain.
<elderK>
Like, let's say the reader... is reading. And the user has like, set a macro character. Depending on situation, the reader will invoke the function for that macro character, to handle the read.
<elderK>
But is the "read table" in use by that "macro character function" the same as the read table that was in effect at the time of reading?
<elderK>
Or is the read-table in effect in the macro function, the one that was in effect when the macro function was set / defined?
<elderK>
Or does it depend on whether it's an "interpreter", rather than a compiler?
permagreen has quit [Read error: Connection reset by peer]
Guest14049 has quit [Ping timeout: 252 seconds]
<elderK>
It kind of seems like, to "read", you need a functional implementation, because of reader macros...
permagreen has joined #lisp
SaganMan has quit [Quit: WeeChat 1.6]
Necktwi has quit [Ping timeout: 250 seconds]
Necktwi has joined #lisp
<Bike>
elderK: it just uses what's in *readtable*, so basically what's in effect at time of reading.
<White_Flame>
a reader macro can either recursively call READ which uses the readtable & normal reader rules, or it can consume character by character and do whatever it wants locally
<White_Flame>
obviously the latter is the terminal recursion case
<pfdietz>
The reader can also invoke eval.
<elderK>
Iono. It just makes my brain kind of explode. Like, I think there must be some "basic hardwired lexer" and stuff that powers the "core" language.
<elderK>
And then, everything else builds on top of that.
<elderK>
But the reader macros mean that this "lexer" is dynamic, which means craziness.
<elderK>
It just hurts my brain :D
<elderK>
Not necessarily in a bad way.
<White_Flame>
pfdietz: sure, but that's not what deals with the input stream & dispatching on characters. It's Lisp code, it can do whatever it wants ;)
<pfdietz>
I am somewhat ambivalent about customizing the reader. It makes it harder to write programs that grovel over general code.
Demosthenex has quit [Ping timeout: 246 seconds]
<White_Flame>
I have been noodling with concepts for a more purely declarative lex/parse
<elderK>
I just wonder how such a... reader is implemented. Like, let's say we "compile" our stuff to some form we can more easily execute. Say, byte code or something. Or maybe we just, literally remember the AST and walk it to execute.
<elderK>
So, we'd have to have a table that'd contain a pointer to the function to be invoked to do the reading. Since that can be redefined, we have to be able to decide whether to call some built-in compiled function to do it. Or, run the "potentially interpreted one"
Demosthenex has joined #lisp
<elderK>
Maybe it isn't so crazy.
angavrilov has quit [Remote host closed the connection]
<Bike>
um, asts and compilation and stuff take place a while after teh reader
<White_Flame>
right, the reader lexes and does some structural parsing
<White_Flame>
did the Lisp reader exist before the concept of "lexer" was established as we know it today?
<White_Flame>
because obviously there isn't a hard & fast lexer/parser boundary
<elderK>
I'm just trying to... match things up. I mean, how can reading be completely independent from... stuff. It can't just be a "typical lexer / scanner" because macro characters require us to invoke some function, that is potentially set by user.
<elderK>
so, in an interpreter, that would require us to then interpret that macro function so to continue the read.
<elderK>
No?
<Bike>
sure, but that's just done through funcall.
<Bike>
and funcall doesn't need to invoke the reader in any way (unless you're calling, like, READ itself)
<no-defun-allowed>
All reasonable Lisps use recursive descent which makes these things quite trivial.
<Bike>
i don't think describing what READ does as a recursive descent parsing is reasonable?
<elderK>
Bike: Right. But that implies that we can somehow "funcall" a function. Which means we need to have been able to read it, and somehow store it in a form we can call.
<Bike>
nah
<Bike>
it just needs to be there in memory
<elderK>
Yes, but the only way it could be there in memory, the function, is if we already read it, no?
<no-defun-allowed>
It's more appropriate than lexing/parsing, and I've heard it called that before.
<Bike>
(compile nil `(lambda () ,(random 347)))
<Bike>
behold, the function from nowhere.................
<elderK>
Bike: I'm assuming Lisp is being implemented in something other than Lisp itself.
<Bike>
that doesn't matter, and that's not always valid
<elderK>
How do you mean not always valid?
<Bike>
i mean there are lisp implementations written in lisp, of course
<Xach>
elderK: it would still be pretty normal to separate reading and evaluation in not-lisp
<Bike>
also that too.
<no-defun-allowed>
For example, the Unix Hater's Handbook compares it to the contextual grammar of C++, calling Lisp's parser "recursive descent, meaning you can write it on a piece of paper" from memory.
<Bike>
are you sure they were talking about common lisp
<elderK>
no-defun-allowed: There's parsing, then there's lexing. to me, they are independent.
<Xach>
evaluation is what makes the system do stuff, like create function objects and maybe associate them with a global name.
<elderK>
But really just different levels of hte same thing.
<Bike>
they are not independent in lisp
<Bike>
which is a little weird, admittedly
gxt has joined #lisp
<elderK>
Bike: Right. My main problem isn't with the fact that, lexing/parsing is basically "all in one." I've seen lexerless parsers.
<elderK>
My problem is with the fact that stuff that handles lexing, is well, dynamic.
<elderK>
Then again, I'm used to kind of static table-based lexers and parsers and things.
<Bike>
being "dynamic" pretty much just means the table is an object in memory rather than an off-line thing.
<elderK>
Yeah, I get that. I'm just thinking of the necessity to have some way to actually read code in the first place, so that the user's code that sets a new reader macr-function can be understood and patched in :P
nirved is now known as Guest2617
<Bike>
well, you start out with a lisp implementation.
nirved has joined #lisp
<Bike>
when you start sbcl or whatever, it doesn't read in all the code again or anything.
<elderK>
Bike: Which is to say, when you start the Lisp implementation - say from the standard image - everything is in place to read and understand standard Lisp. If it reads stuff, evaluates stuff, that changes that, well, okay, because it started off with the base syntax.
<elderK>
Right?
<Bike>
more or less
Guest2617 has quit [Ping timeout: 252 seconds]
<elderK>
I wonder why Scheme doesn't have reader macros.
<Bike>
i don't think it would fit with their ethos
<elderK>
And I wonder if that means Scheme would have a fairly typical kind of lexer.
<Bike>
probably. i haven't looked that deep at implementations, though
<elderK>
I really want to learn how to make a lisp implementation. Toy to start with, but increasing complex and non-toy-ish.
<elderK>
But I'm not really sure how to best start. Finishing LiSP and studying RABBIT, maybe,
<elderK>
:D
Necktwi has quit [Ping timeout: 250 seconds]
<Xach>
elderK: Lisp in Small Pieces is a good book on the topic. i like the progression it follows from simple to complicated
<Bike>
yeah, i think LiSP has some simple ones to start with
<Bike>
i mean a basic metacircular interpreter is like a page long, if you just have scheme special oeprators
Demosthenex has quit [Ping timeout: 272 seconds]
eminhi has joined #lisp
<elderK>
:) I wonder if I can do like, all the stuff it covers, but in CL rather than Scheme.
<elderK>
Like, implement its exercizes in Scheme.
<elderK>
er, in CL
<Bike>
probably
Demosthenex has joined #lisp
<elderK>
I also need to learn how to do ... like, usual lexing in Lisp. I'm used to implementing lexers in C using transition tables and stuff. Basically state[current_state][input_category] is the next state.
<elderK>
Bike: IIRC, he uses... Meroon for object stuff.
<elderK>
I imagine I could use CLOS :)
rippa has quit [Quit: {#`%${%&`+'${`%&NO CARRIER]
<elderK>
Now that is an interesting part message :D
Necktwi has joined #lisp
warweasle has quit [Quit: rcirc on GNU Emacs 24.4.1]
xkapastel has quit [Quit: Connection closed for inactivity]
mindCrime has quit [Ping timeout: 250 seconds]
emaczen has quit [Remote host closed the connection]
eminhi_ has joined #lisp
Necktwi has quit [Remote host closed the connection]
Necktwi has joined #lisp
eminhi has quit [Ping timeout: 244 seconds]
drewes has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
Demosthenex has quit [Ping timeout: 246 seconds]
xkapastel has joined #lisp
varjag has quit [Ping timeout: 244 seconds]
Demosthenex has joined #lisp
Bike has quit []
<pjb>
elderK: about *readtable* and reader macros, note that *readtable* is a special variable, therefore it has dynamic scope. lexical = WHERE, dynamic = WHEN. So the question is WHEN the reader macro is executed, what binding has the *readtable*. Of course, if the reader macro function is called thru the *readtable*, by reading the macro character, at that time, the *readtable* is bound to the readtable that contains the mapping of
<pjb>
macro character and the reader macro function.
<pjb>
elderK: but you can also call a reader macro function outside of reading (CL:READ).
<pjb>
elderK: and once the reader macro function is executing, nothing prevents you to bind *readtable* to another readtable!
<pjb>
Notice how the reader macro functionr ead-objcl-expression binds the *readtable* to *objc-readtable*.
Demosthenex has quit [Ping timeout: 240 seconds]
<pjb>
elderK: the syntax is [object messageWith: (foo) andWith: bar] where messageWith:andWith: must be read case sensitively amongst other things.
Demosthenex has joined #lisp
<pjb>
elderK: but if object is not a special identifier super, then it must be read as a lisp expression: [(if foo obj1 obj2) getIt] hence the other binding to *lisp-readtable*.
<elderK>
pjb: Of course, when the macro function is compiled, the syntax that is in effect... then, is set. Like, just beacuse you change the readtable, doens't mean the macro function suddenly gets recompiled, right?
<elderK>
I figure this is obvious but I wanted to check anyway
<pjb>
White_Flame: it was developed about at the same time. Remember that Fortran was defined earlier tha LISP. Backus and Naur formalized the BNF for ALGOL 58 in 1959.
<pjb>
elderK: what syntax? nothing is set when the reader macro function is compiled.
<pjb>
Setting the macro character doesn't compile anything.
<pjb>
elderK: And yes, you can also mutate the readtable bound to *readtable* itself while reading. Ie. you can write a reader macro function that will set macro-chracters while reading.
<pjb>
elderK: Probably a good track to follow for an obfuscated lisp contest…
Demosthenex has quit [Ping timeout: 244 seconds]
<White_Flame>
pjb: I think elderK means when the source code to the reader is compiled
<pjb>
White_Flame: However, the syntax of LISP (1959) was very simple. Basically, a lexer to read symbols, strings and numbers, and a parser for the sexp syntax.
<pjb>
White_Flame: elderK: yep, when the source code is compiler, it's the readtable that is bound to *readtable* in the compilation environment that is used. It can be the standard readtable, or something completely different. For example, if you write your reader macro in vacietis!
Demosthenex has joined #lisp
<pjb>
or in cl-python…
shifty has quit [Ping timeout: 250 seconds]
robotoad has quit [Read error: Connection reset by peer]
<pjb>
White_Flame: and in CL, the lisp reader is clearly defined in two parts: the basic lisp reader algorithm specifies the lexer (which is a tad more complex than what you'd do in general with lex (but you could do it in lex, there are states)), and then it defines the standard reader macros of which there are two kinds: macros such as #\" scan tokens such as strings, and macros such as #\( parse s-exps. Again, not much syntax here (
<pjb>
most complex is the dotted-list syntax!).
<pjb>
White_Flame: all the rest is done with macros working on s-exps.
<pjb>
(and special operators).
pillton has joined #lisp
robotoad has joined #lisp
slyrus1 has joined #lisp
Demosthenex has quit [Ping timeout: 244 seconds]
Demosthenex has joined #lisp
Kaisyu7 has quit [Quit: ERC (IRC client for Emacs 26.1)]
<buhman>
if I had a list of flags, and a flag I wanted to "toggle" by adding it or removing it from the list, is there a fancy way to do that?
<buhman>
.. where a "flag" is a symbol in this case
<pjb>
(setf (nth i list) (not (nth i list))) is slow.
<pjb>
and you can use find to test: (let ((flags (list :carry :zero))) (deletef flags :carry) (pushnew :minus flags) (values flags (find :carry flags))) #| --> (:minus :zero) ; nil |#
Demosthenex has quit [Ping timeout: 240 seconds]
<pjb>
On the other hand, with bitvectors, you can mask off flags more easily and efficiently than with sets (lists). (intersection flags mask) vs. (bit-and flags mask)
Demosthenex has joined #lisp
fikka has quit [Ping timeout: 246 seconds]
arescorpio has joined #lisp
LiamH has quit [Quit: Leaving.]
meepdeew has quit [Remote host closed the connection]