<aeth>
pjb: But you can easily write a function with more assumptions, in which case you must subclass duck or use before/after/around/etc. and can't just rely on having a defined quack. And CL doesn't care. Meanwhile, in Pythonland, duck typing is the idiomatic thing to do
<aeth>
CL isn't dogmatic with paradigms, only with formatting style and kebab-case
<aeth>
(And that's probablyy *why* CL style is so uniform)
<aeth>
*probably
smasta has quit [Ping timeout: 250 seconds]
wxie has quit [Ping timeout: 250 seconds]
smasta has joined #lisp
<asarch>
If I do: (defun foo () (format t "Hello, world!")), I won't see the message (unless I make the funcall of 'foo). However, if I do: (let () (format t "Hello, world!")), I'll see it. What is the name of those expressions that are "auto-evaluate" like LET, LET*, FLET, FLET*, etc?
cantstanya has quit [Remote host closed the connection]
<gilberth>
What do you mean by "auto-evaluate"?
<asarch>
In the example, the evaluation of the (format ...) message. With (defun) I would need to explicitly call the function to see the "results"
cantstanya has joined #lisp
<asarch>
And with LET I can immediately see them
<gilberth>
Yes. The purpose of DEFUN is to define the function and not to invoke it.
smasta has quit [Ping timeout: 255 seconds]
<pjb>
asarch: loading or compiling files follows somewhat the REPL model.
<asarch>
Exactly. Are there any other expressions that act like LET?
<gilberth>
All expressions act like that.
<pjb>
asarch: loading a file is a REL Read-Eval-Loop (printing can be asked with *load-print*)
<asarch>
?
<gilberth>
asarch: When you load a file, which I presume you do here, makes all forms [expressions] being evaluated.
<pjb>
asarch: compiling a file is a RCL Read-Compile-Loop (where compile-time side effects occur), but you will often load the file after the compile-file, and there you get the Read-Eval-Loop of the compiled code, so you get the run-time side effects.
smasta has joined #lisp
<pjb>
The compile-time side effect of defun is to note that foo is a function. The run-time side effect of defun is to define a function.
<aeth>
asarch: Well, you could think of the opposite of what you're talking about as lambda macros since they almost always directly or indirectly use lambda
dale has quit [Quit: dale]
<pjb>
The compile-time side effect of LET is to compile the LET form. The run-time side effect of LET is to bind variables and evaluate the body in that scope.
<pjb>
asarch: any question?
<pjb>
asarch: (note: there's no such notion as "auto-evaluate").
<asarch>
I would say "auto-execute" but...
<gilberth>
asarch: Still, not such a concept.
<pjb>
there's no such notion of "auto-<anything>" in CL!
<pjb>
I've explained the notion of evaluation and compilation above, but you should read CLHS, it's explained very well and with all details!
<aeth>
pjb: I think asarch is trying to distinguish between macros that return or bind an unevaluated lambda (like defun or that let-over-lambda book) and macros that evaluate immediately
<aeth>
(evaluate the body, I mean)
<aeth>
And yes it's really the generated code doing this, not the macros themselves
<pjb>
as explained, the standard specifies for each form, what are its compilation-time side effects, and what are its run-time side effects.
<pjb>
(there are also read-time side effects and load-time side effects, but they're more rare).
<gilberth>
aeth, pjb: It's not about compilation or macros, I believe. I figure that asarch has no clear understanding that the sole purpose of DEFUN is to define a function and be set.
<asarch>
Let's go by parts. You know, since JavaScript was inspired in the functional programming type of Lisp, you can actually construct things like: (function foo(x, y) {return x + y;})(1, 3)
<pjb>
the run-time side effect of DEFUN is to DEFINE a FUNCTION. Not to evaluate the body!
Arcaelyx has quit [Ping timeout: 250 seconds]
<pjb>
the run-time side effect of LET is to BIND some VARIABLES. AND to EVALUATE the BODY.
<gilberth>
asarch: Would "function foo () { console.log ("hey"); }" print something on the console?
<pjb>
So DEFUN and LET just do what they're specified to do.
<asarch>
1) I define a new function called "foo" with two arguments and, this is the part of my question, 2) automatically call this new function by giving it two parameters
<pjb>
asarch: so you can see that in the first time, the lambda is NOT called, but assigned to (fdefinition 'foo), while in the second case, it's called!
<pjb>
But what this says with lambdas, is just what the standard says in English.
<asarch>
I just was wondering about this in Common Lisp with something like: (let ((stream (open "my-file.txt"))) (format t "Contiene ~a~%" (read stream)) (close stream))
<pjb>
I mean, if you don't understand the difference between "Not evalaute the body" vs. "evaluate the body", how can you udnerstand the difference between (setf … (lambda (…) body…)) and ((lambda (…) body…) …) ?
<asarch>
Exactly
keep_learning_M has joined #lisp
<asarch>
This is the part I don't understand. What kind of "thing" is LET and, are there any other "things" like LET?
<aeth>
asarch: You'd use (with-open-stream ...) there instead of the let. And in general, you'd define or use a macro that wraps the body in an unwind-protect to ensure that close/cleanup/free/whatever is called. (Yes, free, if CFFI)
<pjb>
Perhaps you can understand the difference between Master Foo saying he will give you a keisaku hit on the head, and Master Foo actually giving you a keisaku hit on the head?
Oladon has joined #lisp
<pjb>
asarch: note that for your question contrasting DEFUN and LET, what LET is exactly doesn't matter.
<pjb>
Specifically, LET is a special operator, which can also be implemented as a macro, and DEFUN is a macro, which can also be implemented as a special opertor.
<pjb>
Since they're not functions, they don't use the normal function application rules, but instead, they use their own specific rules, so again, you need to read clhs to know what they do exactly. Which is what I explained succintly above.
<asarch>
As far I know, LET*, FLET, FLET* and PROGN "act" like LET
<pjb>
One DOES NOT EVALUATE THE BODY, the other DO EVALUTE THE BODY.
<asarch>
What other functions evaluate the body?
<pjb>
So you have the operators that do evaluate immediately their subforms, and you ahve the operators that don't.
<pjb>
No special names.
<asarch>
Oh :-(
<aeth>
asarch: you can probably call the whole class of (probably) macros a local-binding macro (even if LET itself might not necessarily be a macro in a certain implementation)
<pjb>
functions ALWAYS get their arguments evaluated before the function call!
<pjb>
You can also write macros that evaluate half and don't evaluate the other half, or macros that both evaluate and don't evaluate their subforms!
<aeth>
asarch: notice that FLET gets complicated...
<aeth>
asarch: FLET, like DEFUN, has parts that aren't immediately evaluated, even though the body is
<pjb>
here it both prints 42 when (BOTH (print 42)) is evaluated, and then twice more from the loop.
<pjb>
This is why we can implement control flow with macros.
<aeth>
asarch: With a macro you can do whatever you want with it. You're just working with source, e.g. (defmacro no-evaluation-at-all (&body body) `(quote ,body)) (no-evaluation-at-all (+ 1 1)) => ((+ 1 1))
<pjb>
asarch: you can take the question in the opposite direction. If you want the macro to evaluate the expression, basically the expansion will contain the expression in an evaluation place. If you don't want it to evaluate the expression, then it should return the expression in a non-evaluated place, such as inside a lambda form that is not called.
<pjb>
The later case of a lambda (without argument) used only to hold an expression that is not evaluated until that function is called, is called thunk.
<pjb>
We may often see a macro split into a function taking thunks, and a macro assigning expressions to thunks or not.
<gilberth>
pjb, aeth: I believe asarch is on a wrong track in thinking that LET would make things evaluated. Why this (LET () ..) around FORMAT. You skip that. I believe it is not about different evaluation times like macro expansion versus runtime here.
Lord_of_Life_ has joined #lisp
<pjb>
gilberth: good that we didn't talk about macroexpansion time so far, then.
<aeth>
pjb, asarch: Well, usefully it usually uses lambda directly or indirectly (including with defun). Most trivially, it can just use quote to not evaluate.
okeg has quit [Remote host closed the connection]
<asarch>
When you have to do one thing in one line, what do you usually use? FLET, LET, etc?
<pjb>
aeth: quote doesn't preserve scope (no closure there!) lambda is actually a macro expanding to (function (lambda …)) and function creates the closures.
<pjb>
asarch: lines don't exist in lisp. Only s-expressions.
<aeth>
pjb: I didn't say it was useful, I just said it doesn't evaluate there
<pjb>
asarch: you should forget everything and start from a fresh slate.
Lord_of_Life has quit [Ping timeout: 268 seconds]
Lord_of_Life_ is now known as Lord_of_Life
<asarch>
:'-(
<gilberth>
asarch: Okay. You know JavaScript?
<asarch>
Yeah. That was the reason I am here
<gilberth>
Fine.
<gilberth>
So a (defun foo () (format t "Hey!~%")) is like "function foo () { console.log ("Hey"); }" in JavaScript. Do you agree?
<asarch>
Yeah
<gilberth>
OK. Then why would you expect the former to print "Hey"?
<asarch>
Exactly
<gilberth>
See.
<asarch>
The former wouldn't do that
* gilberth
scrolls back for the orginal question.
<asarch>
Have you check CL-REPL for Android?
<gilberth>
asarch: I guess, this answers your question.
<asarch>
In that REPL, it is quite tiring to type with the touch screen (specially with the lots of typos)
<pjb>
asarch: use a bluetooth physical keyboard!
<asarch>
So, instead of do something like (defun foo () ...) and then (foo), you could save time with something like (let () (....))
<gilberth>
asarch: Sorry. Very Sorry. But I do not care about some REPL on some touch screen. What I care about is, that you get a basic understanding of Common Lisp.
<asarch>
Just one line!
<gilberth>
asarch: LET there is a red hering.
<pjb>
asarch: no.
<aeth>
asarch: Yes, but in your particular special case, there's a shortcut for (let () ...) called (progn ...) and it's usually not necessary.
<pjb>
asarch: notice the little words you used: "and then". Those little words have a VERY BIG importance!
<grewal>
In javascript, that's the diffence between function foo () {...} foo(); and { ... }
<pjb>
asarch: notably in what they leave out: the length of time between the defun and the call.
<pjb>
asarch: in a way, this lenght of time is even infinite, when it doesn't occur on the same lisp image.
<asarch>
I know, it depends most of the type of processor, right?
<aeth>
let's more of a shorthand for lambda e.g. (let ((a 42) (b 43) (c 44)) (+ a b c) instead of ((lambda (a b c) (+ a b c)) 42 43 44)
<aeth>
In some Schemes that might be the actual definition of let. Probably not a Common Lisp implementation, though.
<asarch>
WOW!!!
<asarch>
I didn't know you could use LAMBDA like this!
<aeth>
(oops, I forgot to close my let)
<asarch>
THAT WAS THE REASON OF MY QUESTION!!!
<asarch>
What other ways are there to do things besides LET?
<pjb>
asarch: and that was the reason why I wrote it well above. Don't you read my answers? Well, your bad.
<pjb>
asarch: there's an infinite ways to do things besides LET. Which one do you want?
<grewal>
asarch: What fo you mean by that question?
<asarch>
Actually, I am copying your answers to get a hard copy of them. I always save them in a physical folder
<asarch>
I save all your answers to study them for later
<asarch>
Which one is the most effective?
<grewal>
asarch: Which one what is most effective for what?
<pjb>
:-)
<gilberth>
*Sigh*
<pjb>
exactly.
<gilberth>
Can you please stop yelling. I did not yet find my ear plugs.
<pjb>
gilberth: type C-x C-- C--
<gilberth>
asarch: There is _nothing_ special about LET. Get it.
<gilberth>
pjb: I use ircii. I do not believe it would have an effect.
<pjb>
Well, apart the fact that it's a SPECIAL operator.
<pjb>
which means it has SPECIAL rules for the evaluation of its subforms.
<gilberth>
pjb: LOL. Sorry.
<asarch>
"Let over Lambda"
<gilberth>
pjb: But it not special in the sense, that every top level form of a file loaded is just evaluated.
<pjb>
such as it doesn't evaluate the variable names, it evaluates the initialization forms, then it binds the results to the variables, then it evaluates the body in a scope where those variables exist.
<pjb>
These are the SPECIAL rules of evaluation for LET.
<gilberth>
It also might be a macro.
<pjb>
Yes, this is what being a special operator means.
<aeth>
But it's not as special as in some languages, because it's an expression, and it returns a (probably) meaningful value. The rules are way simpler.
<pjb>
Being a special operator means that it's implemented specially by the CL compiler, or as a macro.
<gilberth>
But, it is not special in the concept asarch has about "special".
<pjb>
Being a (standard) macro operator means that it's implemented as a macro, or as a special opertor. See above.
<asarch>
:-P
<pjb>
THere's no "asarch's special concept"> Check the CLHS glossary!
<gilberth>
pjb: Don't tell me. I know all that.
<grewal>
No, but you can use the word special to refer to its ordinary English meaning and not its technical CL meaning
<asarch>
I wonder what would Mr. Richard P. Gabriel say about this...
<gilberth>
I could also nail a burger to my leg and turn it until I receive BCC.
<gilberth>
BBC, even.
<gilberth>
This perhaps spoiled the joke.
<pjb>
yea, better try to receive bbc with that burger than bcc…
<gilberth>
asarch: Anyhow, as pjb said, I am affraid you should back off a bit and get basics together. More reading for you, sorry.
<asarch>
I know, I know
<Josh_2>
oof
<gilberth>
Josh_2: Where do you come from? You sound like the spooky message from the off.
<Josh_2>
idk
<gilberth>
You don't know where you are? Strange.
<Josh_2>
Nope
<asarch>
Let's see if CL-REPL can actually do CLIM things...
<gilberth>
Josh_2: Interesting. I have the opposite problem. I know where I am, but I have no clue where I want to be.
<Josh_2>
xD
<gilberth>
asarch: Don't rush things. Sit down and learn! It's hard and cumbersome, I know. But do that, do you?
ski has quit [Ping timeout: 250 seconds]
emacsomancer has joined #lisp
libertyprime has quit [Remote host closed the connection]
akoana has joined #lisp
Oladon has quit [Quit: Leaving.]
torbo has joined #lisp
Fare has quit [Ping timeout: 245 seconds]
<mfiano>
If I have an (unsigned-byte 32) integer, say #xA1B2C3D4, what is a good way to reverse the bytes so it evaluates to #xD4C3B2A1?
ltriant has quit [Ping timeout: 245 seconds]
<aeth>
mfiano: Stuff similar to this comes up in here from time to time. I'd probably go with (let ((n #xA1B2C3D4)) (format t "~x~%" (logior (ash (ldb (byte 8 0) n) 24) (ash (ldb (byte 8 1) n) 16) (ash (ldb (byte 8 2) n) 8) (ldb (byte 8 3) n))))
<aeth>
It seems to be about 50% larger in SBCL's disassemble than the original two solutions, though. Probably because it's two DPBs and not optimized.
<aeth>
(this is after adding the type declaration)
<pjb>
Why do you care about assembly?
aindilis has quit [Read error: Connection reset by peer]
<aeth>
pjb: because when it's so incredibly fast that you can't meaningfully benchmark it, generated assembly size can still be a useful measure, assuming it's mostly using the same instructions.
<pjb>
And why do you want it so incredibly fast?
aindilis has joined #lisp
<pjb>
It would be better to want it so incredibly correct!
<aeth>
This sort of bit/byte thing is so full of bikeshedding because there are 10+ valid, short solutions and they're all very close to each other in both asm size and measured speed.
<pjb>
Hence writing the clearest one.
<aeth>
Clear is subjective here, too, imo.
notzmv has joined #lisp
<verisimilitude>
I wouldn't measure my Common Lisp based solely on what one implementation tells me it DISASSMBLEs to.
<aeth>
verisimilitude: What I was saying is that I'm using disassemble as a rough proxy for benchmarking here because it's too fast to benchmark
<verisimilitude>
You should simply use whichever functions are least ``powerful'' yet still suitable; don't use DPB if it doesn't need right justification, etc.
<verisimilitude>
Have you tried benchmarking it on other implementations as well, aeth?
techquila has quit [Remote host closed the connection]
techquila has joined #lisp
aindilis has quit [Ping timeout: 268 seconds]
<aeth>
verisimilitude: e.g. when I disasembled foo and bar, I could see that they're using basically the same set of instructions with basically the same generated size, so I can not take the 15+ minutes to try to do a proper benchmark of a too-fast function because the difference is probably noise
<aeth>
And in many cases I get the exact same disassembly, in which case I'd *really* be wasting my time with benchmarking
<verisimilitude>
Since Common Lisp is a fairly abstract language, I don't benchmark; I write whatever I think it should be, based on what I figure a mildly intelligent implementation would do.
ealfonso has joined #lisp
<aeth>
s/I can not/I can go ahead and \[3~ not/
<aeth>
oops, the terminal inserted noise
<verisimilitude>
Are these instruction differences using complex or benign instructions, aeth?
<aeth>
verisimilitude: I don't need to benchmark it in multiple implementations because if some implementation has some really slow implementation of e.g. dpb, then it's imo a bug in the implementation that can be fixed.
<verisimilitude>
Still, if I'm writing, say, a macro and I have the option between putting the same expression multiple times, which I know will evaluate to the same value, or using a LET to explicitly state that it's the same value in these locations, I'll do the latter so even a poor implementation will have it nice.
ym555 has quit [Ping timeout: 250 seconds]
<aeth>
I don't care about slow implementations because unless it's something exotic like JSCL, the slowness isn't an inherent property of the implementation and it can always be improved on the implementation's side. Why would I work around it and add work on my end?
torbo has quit [Read error: Connection reset by peer]
<verisimilitude>
This just ties into my believing a macro should always optimize its expansion itself and not rely on the implementation to do it.
<verisimilitude>
I write macros for stupid implementations, so they all benefit.
<verisimilitude>
Really, I shouldn't need to, say, optimize out PROGNs if they're empty or things such as that, but I'll still do it if it's easy.
<aeth>
Sounds like it doesn't scale to very large applications
<verisimilitude>
Fortunately, I'm writing Common Lisp and not Java.
<verisimilitude>
If you're Common Lisp is millions of lines, I'd think you've an issue.
<aeth>
I find it's hard to go past 5,000 to 20,000 lines because I keep finding new abstractions to make.
<verisimilitude>
In my eyes, a macro has the highest-level view of what it does, so the macro should always be the first thing to optimize the expansion.
akoana has left #lisp ["Leaving"]
<pjb>
clear is not subjective: if you use functions in the same category (using the same abstraction) you will get clearer code than if you mix abstractions.
<pjb>
Don't use ldb is you use ash.
<verisimilitude>
Look at SBCL's CASE as an example; it just compiles down to a COND. Does the compiler notice cases where it can be optimized? Why shouldn't CASE handle it, instead?
<aeth>
pjb: I'm not sure that's the case. Mixing ldb and dpb usually gets a real mess of indentation. The rotatef one is pretty clever, but it's less efficient and requires more knowledge to understand.
<verisimilitude>
But, I wouldn't write a compiler to optimize bad code, either. You should use CASE if you want CASE behavior and use COND if you want COND behavior, not have the compiler figure it out for you.
<pjb>
aeth: indentation can be solved by using names.
<pjb>
ie. LET.
<aeth>
verisimilitude: SBCL apparently optimizes its CASE when (speed 3)
techquila has quit [Remote host closed the connection]
ltriant has joined #lisp
<aeth>
verisimilitude: That's a bad example, though, because it's one of the most common macro cases (heh) that people have to write a custom CASE on top of COND because they want some slightly different semantics than CASE offers.
<verisimilitude>
A very intelligent compiler makes sense for, say, APL, but Common Lisp is nowhere near as abstract in this sense as APL.
<pjb>
aeth: or mostly, by using function abstractions so you don't have to see the indentation. Anyways, code is s-expressions, there's no indentation in s-expressions.
<verisimilitude>
I'm not seeing it, aeth.
<verisimilitude>
It's not in the macroexpansion, from what I see, anyway.
techquila has joined #lisp
techquila has quit [Remote host closed the connection]
aindilis has joined #lisp
techquila has joined #lisp
techquila has quit [Remote host closed the connection]
techquila has joined #lisp
Fare has quit [Ping timeout: 245 seconds]
nirved is now known as Guest81765
nirved has joined #lisp
Guest81765 has quit [Ping timeout: 258 seconds]
Arcaelyx has joined #lisp
arescorpio has quit [Remote host closed the connection]
caltelt_ has joined #lisp
kutsuya has quit [Remote host closed the connection]
_whitelogger has joined #lisp
aeth has quit [Ping timeout: 250 seconds]
aeth has joined #lisp
ltriant has joined #lisp
<asarch>
Ok
<asarch>
:-)
sauvin has joined #lisp
ebrasca has quit [Remote host closed the connection]
<beach>
Good morning everyone!
caltelt_ has quit [Ping timeout: 245 seconds]
libertyprime has quit [Ping timeout: 245 seconds]
dale has quit [Quit: dale]
vlatkoB has joined #lisp
Inline has quit [Quit: Leaving]
slyrus__ has quit [Remote host closed the connection]
slyrus__ has joined #lisp
<aeth>
verisimilitude: Okay, it looks like this is the optimization I was thinking of in SBCL: (defun foo (item) (declare ((member :foo :bar :baz) item)) (ecase item (:foo 42) (:bar 43) (:baz 44))) (disassemble #'foo)
<aeth>
What's going on is that it turns the four branches (else error) into three branches (with else, unlabeled, as :baz) if it knows that it cannot error
<aeth>
This is apparently separate from its dead code optimization (which you might expect with an impossible COND branch) since it only happens with (optimize (speed 3))
orivej has joined #lisp
<aeth>
verisimilitude: This optimization (which is for ECASE, not CASE) doesn't seem to happen when I define a function that uses the macroexpand-1 of the ecase (only difference was replacing the gensym with a regular symbol).
<aeth>
verisimilitude: nevermind it does, I copied and pasted it wrong
<aeth>
So it's actually COND that gets the optimizations
libertyprime has joined #lisp
frodef has joined #lisp
libertyprime has quit [Ping timeout: 246 seconds]
libertyprime has joined #lisp
libertyprime has quit [Ping timeout: 258 seconds]
<verisimilitude>
So, it's happening in the compiler, but not the macro itself.
libertyprime has joined #lisp
<verisimilitude>
That's the wrong place for that, I'd think.
scymtym has quit [Ping timeout: 255 seconds]
libertyprime has quit [Ping timeout: 250 seconds]
libertyprime has joined #lisp
techquila has quit [Remote host closed the connection]
<pjb>
verisimilitude: why wouldn't you want to optimize (defun foo (item) (declare (type (member :foo :bar :baz) item)) (cond ((eql :foo item) 42) ((eql :bar item) 43) ((eql :baz item) 44))) ? It's obvious that the last test is useless.
<pjb>
verisimilitude: you sound crazy wanting to remove optimizations that are perfectly good…
techquila has joined #lisp
techquila has quit [Remote host closed the connection]
techquila has joined #lisp
<aeth>
pjb: well not quite... it's turning the three eqls and a t (error ...) into two equals and a t, with the t being baz's return
<aeth>
s/two equals/EQLs/
JohnMS_WORK has joined #lisp
libertyprime has quit [Ping timeout: 268 seconds]
<pjb>
You can add any number of clauses once you've exhausted the case, they're dead code. This is why i didn't include the (t (error …)). Again, basic optimizations. I don't understand what's your problem.
<aeth>
pjb: and yeah for me the only surprise is that it requires (optimize (speed 3)) because I'd expect that to be part of its dead code elimination.
<aeth>
I guess at one point in the past (or for long CONDs?) it was (or is?) slow
<pjb>
also, not necessarily. It depends on how the COND is compiled.
libertyprime has joined #lisp
ltriant has quit [Quit: leaving]
<pjb>
the compiler could perform a karnaugh optimization on all the conditions, assuming other knowledge on the values (types, etc), and come with very simple tests. The only downside is that there is indeed a sequence constraint in COND that doesn't exist in CASE.
<pjb>
But if the conditions are side-effect free, which should be the case when they come from CASE, then the compiler can ignore the order and optimize it like the original CASE.
<pjb>
ie. what I'm saying: don't assume a trivial compiler.
shka__ has quit [Ping timeout: 245 seconds]
libertyprime has quit [Ping timeout: 255 seconds]
shka__ has joined #lisp
wigust has joined #lisp
jprajzne has joined #lisp
<verisimilitude>
I'm just writing that it's my opinion that complex macro optimizations belong in the macro, not the compiler.
<aeth>
sounds like that would duplicate a lot of effort since there are many macros that will produce roughly the same thing (e.g. lots of macros producing CONDs)
<verisimilitude>
If the logic reduces to a COND in parts, then it would be reasonable to have the logic of the COND handle further optimization, where valid.
wigust- has quit [Ping timeout: 268 seconds]
<verisimilitude>
With your ECASE example, you should, ideally, get an error whenever ITEM doesn't adhere to the type, so that optimization is rather irrelevant.
<pjb>
Nope. With the declaration, you would never get any error anyways, because you've told the compiler the item will NEVER be anything else than :foo, :bar or :baz. So there's absolutely no point in checking for any error here.
<verisimilitude>
Trading a runtime error for system crashing is bad.
<pjb>
hence NEVER DECLARE ANY TYPE!
<verisimilitude>
I've been planning to replace the DECLAREs in my CL-ECMA-48 with ASSERTs because of this, actually.
<verisimilitude>
Now, we agree there, but not on macros, still, it seems.
<pjb>
Indeed. Or check-type which expands to a call to assert.
<aeth>
verisimilitude: what pjb says isn't true, it will error just like in check-type in SBCL, it just won't be recoverable at runtime by providing a substitute value
<verisimilitude>
Well, that's implementation dependent was my point, aeth.
<aeth>
verisimilitude: and every other implementation I know of either does something sort of like check-type (like SBCL) or ignores the declaration
<aeth>
verisimilitude: the solution is to generate declare with implementation-dependent #+foo to make sure it's safe. Too bad (safety 0) in SBCL *is* unsafe.
<aeth>
(you would do that in a macro!)
nydel has quit [Read error: Connection reset by peer]
<verisimilitude>
If you don't care about optimization at this level, as I don't, then why bother with implementation-dependent declarations?
<verisimilitude>
Besides, a sufficiently intelligent compiler, which many of you seem to treat your implementation of choice as, would be able to determine types after such an ASSERT or CHECK-TYPE, without declarations, anyway.
<aeth>
Anyway, I used declare just for the simpler disassemble in SBCL. Its check is done before the entry point into the disassemble, but you can use #'sb-disassem:disassemble-code-component to see the full generated asm
<aeth>
verisimilitude: SBCL does determine the type after check-type, not sure about assert. There are two problems. (1) anything that depends on the declaration (like introspect-environment) won't see the inferred type (only the compiler can see it) and (2) the inferred type for the input variable is of type T in SBCL since any argument can come in, since you can substitute the value to one of the correct type at runtime.
<aeth>
This means that the optimizations are restricted to the function level and not beyond, since it's just a function taking in T to everyone else
<verisimilitude>
So, you're telling me it only optimizes the individual function with this?
<verisimilitude>
That's generally how it should be done, so good.
<verisimilitude>
Anyway, I couldn't care less about these particulars of SBCL; I will purposefully ignore whatever SBCL does when writing my Common Lisp, because I write to the standard only.
<aeth>
SBCL can do optimizations at the file or compilation-unit level if it has more information, which check-type doesn't give it. It can also optimize beyond that if sb-ext:*derive-function-types* is T, which makes it do the nonconforming assumption that an ftype will never change.
<aeth>
Never turn that on, except perhaps to distribute a final binary.
<aeth>
since it's nonstandard.
nanoz has joined #lisp
<verisimilitude>
If I were distributing a compiled Common Lisp program, I'd probably choose any other implementation first, purely because I don't want to feed SBCL's current dominant position.
<aeth>
verisimilitude: I think that's the main place where we disagree. As long as I can get my code to portably run on the major implementations, I'm fine with non-standard behavior... as long as it's nonstandard behavior that I can use portability libraries over or (less ideally) handle directly on my own.
<aeth>
verisimilitude: I would essentially be forced into using SBCL or maybe CCL to distribute my binaries if I made end-user applications, for performance reasons. At least if the platform supported it.
<aeth>
I write portable code because that may change in the future.
<verisimilitude>
ECL is a nice implementation, even if its ROOM doesn't work in every instance, which I dislike, and it refuses to DISASSEMBLE functions it should know how to display.
<aeth>
That last part is what really gets me. disassemble tells me if the implementation treats two identical forms as truly identical. This happening (or not) can really surprise you.
<aeth>
I like disassemble too much
<verisimilitude>
Well, I like Common Lisp itself; I don't like any particular implementation and hold no sentimental value towards any of them.
<verisimilitude>
Common Lisp is nice; every implementation is just a tool.
<aeth>
verisimilitude: well, SBCL is probably 3x to 4x slower than the best possible (with current techniques) CL compiler could be, so I don't really have a loyalty to SBCL.
<verisimilitude>
Have you compared it to Allegro or Lispworks?
<verisimilitude>
I'd imagine both of those are leagues better.
<aeth>
It's just that SBCL is currently the fastest and the one that is the most transparent (profiling, debugging, disassembly, etc.) and the one that gives the most useful compilation messages. Those three are pretty useful criteria imo
<aeth>
verisimilitude: I haven't used them, but I don't think they're better in this criteria except perhaps compilation messages. Where they seem to specialize is in value-added features, like GUI tools and embedded Prologs etc
<verisimilitude>
I run my programs through several implementations and there are plenty of things SBCL doesn't tell me that the others will.
<aeth>
s/in this criteria/in these criteria/
<aeth>
CCL catches some things that SBCL doesn't
<aeth>
Definitely never run just one implementation
<aeth>
SBCL can and will without warning fix a bug in an incompatible way if it's accidentally violating the standard so might as well catch it now and not when switching to SBCL 1.6.7
<jackdaniel>
nb; if you put actual lambda form to disassemble in ecl you'll get the expansion (ugly as it could be)
<verisimilitude>
I know, jackdaniel, but what's the excuse for not disassembling the CL functions?
<jackdaniel>
note the keywords
<verisimilitude>
ECL is the only implementation I've tried this with that's also failed with it.
<jackdaniel>
ECL compiles to C and then invokes C compiler on the resulting C code
<jackdaniel>
so disassemble in principle should decompile elf file and show C source code
<jackdaniel>
as of excuses, there is a simple one: it is hard so nobody bothered to implement it
<jackdaniel>
patches welcome ,-)
<jackdaniel>
less obvious but arguably more practical solution is to store function definitions with their compilation settings in the image (in their source code form) and compile to C for preview when disassemble on said functions is called
<verisimilitude>
It would be easier to store the bytecode, instead.
<jackdaniel>
bytecode disassembler is there and works just fine
<verisimilitude>
Yes, but not for those CL functions.
<jackdaniel>
(??)
<verisimilitude>
Anyway, I'm not meaning to hound you over this; it's just one of the first things that comes to mind when I compare ECL to other implementations.
<jackdaniel>
as of functions which are compiled to binary, what utility would give you such fake bytecode disassembly?
<aeth>
Personally, what I think should be the priority for other implementations is SBCL's gradual typing semantics. (i.e. slowly adding in static typing in addition to the dynamic typing for performance or reliability)
elderK has joined #lisp
<aeth>
That's usually how SBCL wins on benchmarks.
rumbler31 has joined #lisp
<verisimilitude>
Usually, I use the example of (DISASSEMBLE 'DISASSEMBLE).
<aeth>
Some of it is type inference, but it's mostly in heavily-DECLAREd/THEd/etc. code
angavrilov has joined #lisp
quazimodo has quit [Ping timeout: 250 seconds]
<verisimilitude>
Oh, so none of the CL functions are ever run through the bytecode mechanism, jackdaniel?
<jackdaniel>
all functions in core are compiled to native code
<jackdaniel>
bytecode is magnitude slower than native one
<verisimilitude>
I can figure, but I'm saying one easy way for DISASSEMBLE to work on those would be to store the bytecode with them and then simply DISASSEMBLE that.
<jackdaniel>
then I'll ask again, what is utlity of showing bytecode of function compiled with different compiler than a function which is run upon invocation?
<jackdaniel>
except cheating programmer into thinking, that disassemble works of corse
<jackdaniel>
course
<aeth>
could have a separate internal function for that, so it's available but you don't lie
<aeth>
I agree that disassemble says to me "this is what's actually going on"
<verisimilitude>
To me, DISASSEMBLE is supposed to be what the function actually is, at a compiled level, but technically something such as giving up, as ECL does, adheres to the standard.
rumbler31 has quit [Ping timeout: 250 seconds]
<jackdaniel>
I don't understand, sorry. I have function #'disassemble, it is some function which is stored in .o inside elf. why on earth anyone would want to see bytecode of a different function with the same source code compiled with the bytecodes compiler?
<verisimilitude>
I was just describing an easy way to avoid DISASSEMBLE giving up, even if it is a poor solution.
<jackdaniel>
it is a *wrong* solution
<jackdaniel>
it misleads the programmer
<verisimilitude>
The bytecode should properly correspond, of course.
<jackdaniel>
it doesn't show a disassembled function but something completely unrelated. It is as good as calling sbcl from ecl to disassemble its #'disassemble and print it in ecl
<aeth>
That's a good idea. You could do that by saving the source code of the function and then running SBCL via uiop:launch-program.
<verisimilitude>
This, to me, seems an issue best avoided entirely.
<jackdaniel>
either way I've only chipped because I thought (diassemble (lambda () (list 1))) may be useful to aeth (who examines different results depending on optimization settings)
<aeth>
(In case I was unclear, I was joking.)
<jackdaniel>
it was, no worries
<verisimilitude>
Still, you'd get great results that way, aeth.
<aeth>
What's more interesting is that you might not need uiop:launch-program to go the other way around, and run ECL from another CL. Does ECL work with CFFI?
<jackdaniel>
(defun random () 5 #| based on dice roll |#)
<verisimilitude>
ECL lets you embed C directly.
<jackdaniel>
aeth: it does, in principle it should be possible to run ECL from other CL implementation
lnostdal has quit [Ping timeout: 246 seconds]
<jackdaniel>
I'm not sure if anyone did try that though
<aeth>
jackdaniel: I wasn't aware that I had to lambda it
<aeth>
and that it would be bytecode
<aeth>
And that it won't work on everything else because that's C
<jackdaniel>
again, I'm lost. but I need to go now, see you later \o
<aeth>
jackdaniel: what's the relevant file I need to wrap for CFFI? I have... *checks calendar* 365 days to get cl-ecl ready for April 1st
<jackdaniel>
aeth: libecl.so
<aeth>
thanks
Josh_2 has quit [Remote host closed the connection]
Josh_2 has joined #lisp
nanoz has quit [Read error: Connection reset by peer]
<loke>
That hexstream guy sure looks like a Lisp version of Emacs's Xah. Although the latter is more successful at SEO
<verisimilitude>
What do you mean, loke?
<verisimilitude>
He seems fine enough, from what I've seen.
<verisimilitude>
I don't like Xach either, which helps.
<jackdaniel>
your morals, kind sir, are down the toilet. if from the fact that you do dislike somebody and another person smears the former one you like the latter, then there is no good comment for that.
<jackdaniel>
I said that because it must have been said, not that I enjoy what will come in a minute
<verisimilitude>
That's not the only reason. I'm not trying to be unpleasant.
<verisimilitude>
It's simply that, when someone calls Xach a sociopath and I think back to my interactions with him, I understand the accusation; it makes enough sense, to me.
<verisimilitude>
That IRC snippet from a decade ago doesn't help, either.
<aeth>
If you can criticize people from IRC snippits from years ago... well, oh no, I am not at all safe. You can probably criticize me from IRC snippits in the past 24 hours.
<verisimilitude>
I try to be nice to people in the same channel as me, at least by not directly and explicitly insulting them, but that's just my approach to it.
<aeth>
hexstream is very cruel on twitter.
<verisimilitude>
Well, I can't rightly comment on his Twitter, since I've seen very little of it. I dislike Twitter, in general.
<p_l>
... Can we not? If you want to discuss that kind of thing, can it be done in presence of the people involved instead of smearing backtalk on IRC?
<shka__>
ECL can also allow you to embed C++
<shka__>
if built with the proper flag
<shka__>
and it is usefull
<p_l>
shka__: I thought it was default for last few ears
<shka__>
*allows you
<shka__>
p_l: it wasn't in 2017, not sure if it is default now
<jackdaniel>
building with c++ core is not default and won't be
<jackdaniel>
embedding c++ as in a separate compiler profile is planned though
<shka__>
so separate build of ECL won't be required anymore?
<jackdaniel>
aeth: file.d is a c source file which needs to be preprocessed by dpp
<shka__>
that would make life easier
<jackdaniel>
thanks to that you may put a symbol in there, like @'ext::foobar'
<jackdaniel>
dpp is ".d pre-processor"
<aeth>
So it's for the @' stuff?
<jackdaniel>
yes, but not only symbols, function definitions with &optional and &key arguments too (and such)
<jackdaniel>
i.e @(return foo bar zet)
<jackdaniel>
you may check out dpp.c source code, it has a lengthy comment at the top describing augumented syntax
<jackdaniel>
dpp = defun preprocessor, not .d preprocessor (just looked at the file)
<jackdaniel>
would anyone be interested in a post about adding new numeric type to ECL as a native object?
<jackdaniel>
(pretty low-level and implementation-specific stuff)
<aeth>
jackdaniel: okay, thanks, now I think I can sort of read the source... its style still kind of is a bit tricky. I like how uniform CL's style is.
<jackdaniel>
if it were plain C it would be less readable
<jackdaniel>
you may check out by calling dpp on .d file
<jackdaniel>
to see how it would look like
<aeth>
jackdaniel: no, I mean the C style
<jackdaniel>
(or see .c files in build/ directory)
smasta has quit [Ping timeout: 245 seconds]
JohnMS has joined #lisp
JohnMS_WORK has quit [Ping timeout: 255 seconds]
scymtym has joined #lisp
hhdave has joined #lisp
hhdave_ has joined #lisp
hhdave has quit [Ping timeout: 246 seconds]
hhdave_ is now known as hhdave
esrse has quit [Ping timeout: 255 seconds]
smasta has joined #lisp
smasta has quit [Ping timeout: 246 seconds]
gxt has joined #lisp
m00natic has joined #lisp
asarch has quit [Quit: Leaving]
libertyprime has joined #lisp
pankajgodbole has joined #lisp
techquila has quit [Ping timeout: 250 seconds]
gravicappa has joined #lisp
smasta has joined #lisp
Ukari has quit [Remote host closed the connection]
Ukari has joined #lisp
smasta has quit [Ping timeout: 268 seconds]
__jrjsmrtn__ has joined #lisp
Demosthenex has quit [Ping timeout: 250 seconds]
Demosthenex has joined #lisp
Demosthenex has quit [Ping timeout: 246 seconds]
Demosthenex has joined #lisp
smasta has joined #lisp
smasta has quit [Ping timeout: 245 seconds]
thijso has quit [Remote host closed the connection]
q3d has joined #lisp
JohnMS has quit [Read error: Connection reset by peer]
JohnMS has joined #lisp
xkapastel has joined #lisp
ebrasca has joined #lisp
igemnace has quit [Quit: WeeChat 2.4]
Arcaelyx has quit [Ping timeout: 250 seconds]
libertyprime has quit [Ping timeout: 252 seconds]
ym555 has joined #lisp
phoe has quit [Quit: leaving]
<hjudt_>
one question about variable naming. when do i use -p ending? do i use it always when it can be (generalized) t/nil?
phoe has joined #lisp
phoe has quit [Client Quit]
atgreen has quit [Ping timeout: 250 seconds]
gxt has quit [Ping timeout: 245 seconds]
gxt has joined #lisp
<gilberth>
hjudt_: I put a "-p" there, if the variable or function yields a boolean value.
<jackdaniel>
functions coming with p sufix are predicates.
<hjudt_>
yes, we are only talking about functions/methods. btw methods too?
<gilberth>
*sigh* How are methods different from functions? Sure you do.
<jackdaniel>
if there is a hyphen in variable name, then put hyphen as well, i.e standard-char-p vs numberp
<jackdaniel>
if you have a typed variant of other predicate do not hyphenate it
<jackdaniel>
I think that's all to it
<hjudt_>
thanks
<gilberth>
If there is no hypen, don't add one.
<hjudt_>
just to be clear: if you don't have a predicate (function) but only a symbol, one does not follow the -p naming convention right?
<hjudt_>
i think that's really the question i wanted to have answered.
<hjudt_>
i knew about the hyphenation rules
<gilberth>
I follow the same rules for just symbols [variables].
<jackdaniel>
that depends on a taste. I too use postfix -p for variables when I want to indicate that it is a flag
<hjudt_>
ok, like updated-p when stuff has been updated?
<gilberth>
Yes.
<hjudt_>
or maybe better updatedp then...
<pjb>
if the predicate is a single word, the suffix should be p ; when the predicater is multiple words, it should be -p.
<pjb>
But you have to be careful, because the predicate may be single word, but still be prefixed by adjective words. Like string-lessp
<pjb>
It's the lessp of strings, not the string-less predicate!
<pjb>
(string-less-p x) would ask if x is string-less. (string-lessp a b) asks whether the string a is less than b.
<hjudt_>
yes, i think i got the hang of it. however, i am still thinking about whether i want to name my special variable *run-updates* or *run-updates-p*, which i use needs-updated-p in the code. *run-updates* just looks nicer...
<hjudt_>
s/which i use/when i use/
<pjb>
I prefer to avoid the suffix on variables or slot names, in general.
<jackdaniel>
when you think about it there is a nice ring to it, because "b" is "p" in a mirror - just like variable and function namespace mirror each other ;-)
elderK has quit [Quit: Connection closed for inactivity]
m00natic has quit [Remote host closed the connection]
__jrjsmrtn__ has quit [Read error: Connection reset by peer]
smasta has joined #lisp
vms14 has quit [Quit: WeeChat 2.3]
smasta has quit [Ping timeout: 250 seconds]
hhdave has quit [Ping timeout: 250 seconds]
Achylles has joined #lisp
milanj has quit [Quit: This computer has gone to sleep]
longshi has joined #lisp
gareppa has joined #lisp
milanj has joined #lisp
longshi has quit [Quit: WeeChat 2.4]
kajo has joined #lisp
smasta has joined #lisp
gxt has joined #lisp
__jrjsmrtn__ has joined #lisp
nowhere_man has joined #lisp
pankajgodbole has quit [Ping timeout: 244 seconds]
Fare has quit [Ping timeout: 264 seconds]
Fare has joined #lisp
techquila has joined #lisp
Fare has quit [Ping timeout: 255 seconds]
gareppa has quit [Quit: Leaving]
edgar-rft has joined #lisp
q9929t has quit [Quit: q9929t]
lucasb has joined #lisp
spoeplau has quit [Ping timeout: 244 seconds]
Pollwa has joined #lisp
hiroaki has joined #lisp
cage_ has quit [Remote host closed the connection]
smasta has quit [Ping timeout: 246 seconds]
gravicappa has quit [Ping timeout: 245 seconds]
varjag has quit [Ping timeout: 268 seconds]
smasta has joined #lisp
Josh_2 has joined #lisp
Achylles has quit [Remote host closed the connection]
sauvin has quit [Read error: Connection reset by peer]
smasta has quit [Ping timeout: 245 seconds]
kenu has joined #lisp
<kenu>
hi
DrPete_ has quit [Ping timeout: 255 seconds]
<kenu>
why I get The variable CONFIG:BLE is unbound
<kenu>
with (defvar BLE "dsfdsfdsfds")
<kenu>
?
DrPete has joined #lisp
<Bike>
maybe a package inconsistency?
<Bike>
like, the defvar form is in one package and whatever code is signaling the error was read in another.
<jackdaniel>
if you put there (cl:defvar *BLE* "Bike was right.") does it work?
varjag has joined #lisp
Fare has joined #lisp
DrPete has quit [Ping timeout: 250 seconds]
DrPete has joined #lisp
<kenu>
@jackdaniel, yes with :cl it works, but the package I call it in has (:use :cl) added
MightyJoe has joined #lisp
cyraxjoe has quit [Ping timeout: 245 seconds]
smasta has joined #lisp
skelic2 has joined #lisp
<aeth>
kenu: did you put an in-package at the top of the file (or if there is a defpackage at the top of the file, under the defpackage)?
<aeth>
(if you want to be extra safe, cl:in-package)
<aeth>
Every file should either begin with an in-package or with a defpackage followed by an in-package, depending on the style. Without that, the package you're in is essentially just a side effect of the load process.
rumbler31 has joined #lisp
skelic2 has quit [Quit: Leaving]
Ukari has quit [Remote host closed the connection]
<kenu>
the problem seemd to be that I had (:use :cl-user) insted of (:use :cl) but why its possible to call (defvar) within REPL which is (in-package :cl-user) without problems
<kenu>
?
Ukari has joined #lisp
amerlyq has quit [Ping timeout: 246 seconds]
amerlyq has joined #lisp
milanj has quit [Quit: This computer has gone to sleep]
vlatkoB has quit [Remote host closed the connection]
ym555 has joined #lisp
<aeth>
kenu: cl-user is a package that uses cl. It doesn't use and reexport everything in CL. So internal to CL-USER everything in CL will work. There actually is a :use-reexport in uiop;define-package's custom macro to define packages, but that's not the default behavior (and shouldn't be)
<aeth>
s/uiop;/uiop:/
libertyprime has joined #lisp
smasta has quit [Ping timeout: 245 seconds]
<aeth>
kenu: Packages are just namespaces for symbols, including built-in ones like cl:defvar. Everything is part of a package. If you don't USE a package or IMPORT-FROM a package some of its specific symbols then you must explicitly provide its prefix (like "cl:")
<aeth>
But symbols can also be private to a package, so you only use the ones that are exported by that package.
<White_Flame>
(uninterned symbols such as #:foo are not part of a package, and are used transiently when unique or temporary symbols are required in constructing forms)
<aeth>
Oh, you can only drop the prefix if you defined it local to that package, or if it is USEd/IMPORTed-FROM. Obviously if you just (defun foo () "Hello.") in the REPL you don't need need to do (cl-user::foo)
<aeth>
(The :: is how you access unexported symbols. Never use it in production, only for debugging. Exported symbols can be accessed with : or ::)
libertyprime has quit [Ping timeout: 250 seconds]
DrPete has quit [Ping timeout: 250 seconds]
DrPete has joined #lisp
angavrilov has quit [Remote host closed the connection]
<Xach>
Like "never use eval", that advice can be couched in "unless it helps you get something done, and you understand the consequences"
smasta has joined #lisp
DrPete has quit [Ping timeout: 250 seconds]
<aeth>
Xach: The only exception I've found to that rule so far is when someone doesn't export a type name (or class name, which is also the type name in that case) and I need to use it in e.g. check-type