jackdaniel changed the topic of #commonlisp to: Common Lisp, the #1=(programmable . #1#) programming language | Wiki: <https://www.cliki.net> | IRC Logs: <https://irclog.tymoon.eu/libera/%23commonlisp> | Cookbook: <https://lispcookbook.github.io/cl-cookbook> | Pastebin: <https://plaster.tymoon.eu/>
rgherdt has quit [Quit: Leaving]
<Kingsy> alright. looking
eddof13 has joined #commonlisp
zaymington has quit [Ping timeout: 268 seconds]
donleo has quit [Ping timeout: 272 seconds]
random-nick has quit [Ping timeout: 264 seconds]
pfdietz has joined #commonlisp
bendersteed has quit [Quit: bendersteed]
varjag has quit [Ping timeout: 260 seconds]
notzmv- has joined #commonlisp
notzmv has quit [Ping timeout: 255 seconds]
notzmv- is now known as notzmv
zaymington has joined #commonlisp
tyson2 has joined #commonlisp
azimut has quit [Quit: ZNC - https://znc.in]
azimut has joined #commonlisp
<aeth> So I'm thinking of doing an iteration macro for restricted forms of iteration. For instance, DOTIMES always terminates assuming (1) you don't SETF/SETQ/etc. the iteration variable (which could in theory be protected by a gensym so you actually iterate on the gensym and SETFing won't matter) and (2) you don't (ab)use the implicit TAGBODY that all DO forms have (which no one cares about) and (3) you don't
<aeth> have a loop or recursion in the body of the DOTIMES that itself doesn't terminate (unavoidable because CL is Turing complete).
notzmv- has joined #commonlisp
<aeth> However, you could pair this property of DOTIMES (which in a slightly modified form would always terminate given the restrictions) with some parts of LOOP (count, sum, maximize, and minimize... and maybe even collect and append) which lets you combine the usefulness of "always terminates" with functional puirty (because now it returns a useful result instead of having to set)... and perhaps also combine
<aeth> it with counting down and counting up (or down) in steps (as long as it remains either strictly increasing or decreasing), repeat (if you don't need the variable itself), or sequence iteration (assuming it is not a circular list). This in itself isn't enough (because, again, the body can contain an infinite loop), but the same macro within the context of a DSL can provide those guarantees.
notzmv has quit [Ping timeout: 255 seconds]
<aeth> But it may not be fully useful without conditional increment (or conditional decrement), which would present the possibility of the condition always being false (in other words, an infinite loop again). But that might be fine.
<aeth> I mean, not having that might be fine.
thuna` has joined #commonlisp
eddof13 has quit [Quit: eddof13]
notzmv- is now known as notzmv
ymir has joined #commonlisp
igemnace has joined #commonlisp
ymir has quit [Ping timeout: 260 seconds]
zaymington has quit [Ping timeout: 272 seconds]
Lord_of_Life has quit [Ping timeout: 256 seconds]
Lord_of_Life has joined #commonlisp
eddof13 has joined #commonlisp
eddof13 has quit [Client Quit]
ymir has joined #commonlisp
eddof13 has joined #commonlisp
eddof13 has quit [Quit: eddof13]
varjag has joined #commonlisp
<aeth> designed it... e.g. (do-finite (:up i 10) ...) as roughly (loop :for i :from 0 :below 10 ...) vs (do-finite (:upto i 10) ...) as roughly (loop :for i :from 0 :to 10 ...) so e.g. (:upto i (1 10)) as roughly ":for i :from 1 :to 10" and (:downto i (10 1 2)) as roughly ":for i :downfrom 10 :downto 1 :by 2" while :down would terminate with :above winding up being somewhat halfway LOOP and halfway DO-family.
varjag has quit [Ping timeout: 255 seconds]
<aeth> so up/upto/down/downto/repeat iteration (as in LOOP, it terminates at the first terminating thing) combined with :do/:sum/:count/:maximize/:minimize body, guaranteed(*) to terminate...
<thuna`> Would a signature like (ITER-TYPE VAR [BEG] END [STEP]) be too (not sure what word to use) confusing/unexpected?
<aeth> yeah, that's the problem
<thuna`> Sorry, I missed the beginning of the conversation
<aeth> nothing in CL, even in macros and stuff (which will just use destructuring-bind), really has optional (probably &optional) forms in the beginning instead of at the end
<aeth> no, it's not part of the conversation that you missed, it's just a problem with the syntax
<thuna`> Well, I imagine the macro would handle it by checking the length, and set the actualy signature to (ITER-TYPE VAR &rest ARGS)
<aeth> I think (?) either having END or (BEG END [STEP]) is less confusing to people than [BEG] END [STEP]
<aeth> but I'm sharing it now in case that's not the case I guess, or in case there's some other obvious flaw
<thuna`> I think (ITER-TYPE VAR { END | (BEG END [STEP]) } ) is fine, if a tiny bit unpleasant, aesthetically. I understand why (ITER-TYPE VAR [BEG] END [STEP]) would not be reasonable.
<aeth> though it's not quite iter-type in general with that syntax because consider a possible extension that allows LOOP-style list and vector iteration... (:list item <list> <optional-step>) or (:vector item <vector> <optional-step>)
<thuna`> optional-step?
<aeth> where the list would use nthcdr until NIL and the vector would just use a hidden increment variable until > length... though lists have in (like dolist) and on (returns sublists)...
<thuna`> Like in :by #'cddr?
<aeth> yes
<aeth> though it would use nthcdr
<aeth> so e.g. (do-finite (:list i (list 1 2 3 4) 3) (:do (print i))) would iterate twice, printing 1 and 4 while (do-finite (:list i (list 1 2 3 4 5) 2) would iterate three times printing 1 and then 3 and then 5... CAR on the sublist of the NTHCDR until the sublist is NIL
<thuna`> If the only guaranteed thing is the variable and the object to loop over/across/wrt. you could take it a step further and make it (VAR ITER-TYPE OBJ &rest ITER-ARGS). For example, (i :downto 10 :from 25 :by 2), or (obj :in list :by #'cddr). But that *does* tend a bit too much towards LOOP syntax.
<aeth> (though the finiteness guarantees would go away if the list is circular)
<aeth> thuna`: yes, I started out in my design just using LOOP syntax from https://www.lispworks.com/documentation/HyperSpec/Body/m_loop.htm
<ixelp> CLHS: Macro LOOP
<aeth> but I think that may be more confusing
<aeth> at least for iteration whose entire point is to be restricted, unlike LOOP
bilegeek has joined #commonlisp
<thuna`> Depends on the tooling I would say. If you could dispatch the accepted signature for ITER-ARGS based on ITER-TYPE it would be fairly easy for the user to figure out what they can do. Although that is not really a given.
<thuna`> If the goal is to be restricted I don't think cramming down multiple kinds of looping into a single function is the way to go.
<aeth> the goal is to be, to the best of its ability, finite because the clause-based LOOP is very, very easy to accidentally infinite loop in (I got it several times while experimenting!) and that's just interrupt and then 'a' to abort when on the CPU, but I want to write things that run on both CPU and GPU
istewart has joined #commonlisp
<aeth> it, of course, cannot be perfect because the body, if Turing complete (and maybe the GPU side wouldn't be!), can still infinite loop somewhere
<thuna`> So how do you do this, by running checks on the state at each iteration?
mulk has quit [Ping timeout: 260 seconds]
pfdietz has quit [Quit: Client closed]
mulk has joined #commonlisp
X-Scale has joined #commonlisp
<aeth> if every :up or :upto is unconditionally increasing and every :down or :downto is unconditionally decreasing and every do-finite needs at least one :up, :upto, :down, :downto, or :repeat (or perhaps also e.g. sequence-iteration, which should also always terminate if non-circular and not used on an infinite lazy sequence)
<aeth> and if the body cannot modify the iteration variable(s), which is just using a gensym as the actual iteration variable...
<aeth> then it shouldn't by itself infinite loop, although it could call something that infinite loops e.g. (do-finite (:repeat 4) (:do (loop)))
<thuna`> You could then make this a wrapper around LOOP like so, yes? E.g by expanding any :DOWNTO/UPTO/etc. into an equivalent with a gensym then have a :FOR <variable> = <gensym> and then you could add an :INITIALLY check for all :FOR/:ACROSS/etc. loops.
<aeth> what's clearly missing from LOOP is the for-as-equals-then := e.g. (loop :for i := (call-function) ...) although it could in practice exist (:with probably will exist) as long as there's another clause that would guarantee a termination
<aeth> I mean, missing from this that is in LOOP
josrr has quit [Remote host closed the connection]
<thuna`> Sorry, I might be thinking of elisp's cl-loop
<aeth> This could be implemented as LOOP, yes. Or DO. At least on the CL.
triffid has quit [Remote host closed the connection]
<thuna`> Is for-as-equals-then not it?
<aeth> I was unclear, for-as-equals-then is the name for = or := (doesn't matter your style, even foobar::= works) because you can also (optionally have a :then after it)
<thuna`> ,(loop for i in '(1 2 3) for elt = i collect elt)
<ixelp> => (1 2 3)
<aeth> What I mean is that while that is in LOOP, it is not in my design for my restricted (Turing incomplete) iteration (which, when run on the CPU side, in CL, doesn't give guarantee finite because the body can just call (loop) and loop infinitely)
<thuna`> Ok, (I think) I see. In that case, is there a reason to avoid using LOOPish syntax in DO-FINITE, aside from it being a DO* macro?
<aeth> On the GPU side, if the language winds up being Turing complete, I could color every function that's not total functional (total functional = provably terminating), and forbid it within DO-FINITE, but besides that restriction, the CPU and GPU code would appear to be the same
<thuna`> That would probably work, depending on how much of :CL ends up being total
<aeth> As for not using LOOP clause syntax, I'm not sure that having something that's very, very different from LOOP (although fairly similar to being a subset in its feature set to the point where the macro could just target LOOP) having almost LOOP syntax is much better than having its own syntax because you have to learn it anyway.
<chsasank> aeth: looking at your zombie raptor code. can you point me to file where you model the static single assignment part of SPIR-V?
<aeth> chsasank: oh it's a mess at the moment because it was a 3000 line file that I had to crudely cut up into smaller files so there's some stuff in spir-v-types and spir-v-instruction (why didn't I pluralize it? I probably will when I move the file to a new directory) that are there solely because of the order of the files depending on each other
<aeth> chsasank: but broadly speaking, it's the concept of spir-v-id that currently lives in data/spir-v-types and that will probably get its own file when I reorganize things better
<chsasank> ok lemme look at spir-v-types.lisp
<thuna`> While it might kind of look like LOOP if you squint, I don't see many pitfalls with a (VAR ITER-TYPE OBJECT &key &allow-other-keys) or (VAR OBJECT &key &allow-other-keys) signature, assuming the arguments are named properly. That could also allow extending it by specializing on ITER-TYPE and/or OBJECT, if that's something that you are considering.
<aeth> chsasank: That is, everything (that has a result, anyway) gets assigned a spir-v-result-id that eventually becomes a unique spir-v-id (the (unsigned-integer 32) that SPIR-V actually works on for its SSA), but the latter happens (ideally, I'll have to clean it up more) at the end so if I do optimizations (I currently do not) any removed area isn't assigned an ID that doesn't even show up in the final
<aeth> instructions
<chsasank> ok, yeah reading it didn't really help me 😅. It seems to be about types.
<aeth> Instructions that have an associated SPIR-V type (almost all of them) also have a spir-v-result which contains the spir-v-result-id and the spir-v-type as well as any constant information if it is constant
<aeth> which is why it ended up in spir-v-types
<aeth> though in reality it should be its own file that spir-v-types depends on
<aeth> but it would be quite short because spir-v-result needs types, while spir-v-result-id and spir-v-id do not
<thuna`> Something like (VAR :REPEAT :TIMES N) or (VAR :RANGE :FROM A :TO B :BY N :INCLUDE-TO T) or (VAR LIST :BY #'CDDR) and so on.
<chsasank> anyway, lemme tell you the context: I am working on backend. Looking to generate LLVM instructions like how you did with SPIR-V. I am struggling with how to model SSA in a lispy way.
<aeth> the names are... uh... well, I started simple and naive and then had to keep adding on more things... I will probably do a few more cleanup passes over it before it's ready
igemnace has quit [Read error: Connection reset by peer]
<chsasank> See this code: https://llvmlite.readthedocs.io/en/latest/user-guide/ir/examples.html. In python (and C++), they model SSA by using pointers.
<ixelp> Example—defining a simple function — llvmlite 0.42.0dev0+76.ga6159f9 documentation
<aeth> chsasank: so, the way I do the generation of SPIR-V is that any s-expression is evaluated and that evaluation returns a spir-v-result (spir-v-result-id + spir-v-type + constant information) and as a side effect, there's a dynamically scoped special variable *instructions* that the instructions are pushed onto
<chsasank> and how do you reference the result of this instruction?
<aeth> it's just a struct that can be compared with e.g. EQL
<aeth> thuna`: I think the pitfall with your design is that it's easy to write something that's semantically wrong with the freeform LOOP linguistic clauses, while if you start with e.g. (:up ...) it's clear what is and isn't valid (because it must go up)
<aeth> thuna`: It's also an opportunity to advantage the syntax that is generally more common and familiar to people (in LOOP, you write :below for <, because :to is <=, even though :below is generally what you want in a 0-based language... making the former :up and the latter :upto makes the most common case the most concise case)
<chsasank> aeth: not sure I follow you. Can I see a (simple) example of this in your code base?
<thuna`> aeth: I agree, though you could just add other "iterator descriptors" (for the lack of a better word) with the same semantics, replacing :RANGE with :UPTO/:UP/:DOWNTO/:DOWN and removing the :INCLUDE-TO option.
<thuna`> You could remove :RANGE or keep it as a dwim option, if you've defined the others it doesn't matter too much
<aeth> chsasank: in my current design (and I will probably lean into it even more over time), almost everything is a function working on spir-v-result objects, e.g. https://gitlab.com/zombie-raptor/zombie-raptor/-/blob/005e32aa9e1b0f545eec34476954395cba85e3e2/data/spir-v.lisp#L481-488
<ixelp> data/spir-v.lisp · 005e32aa9e1b0f545eec34476954395cba85e3e2 · zombie-raptor / zombie-raptor · GitLab
<aeth> so the %vec2 constructor takes in two spir-v-results, each representing an ID (not yet assigned!) and an associated SPIR-V type %single-float (the % is to make it clear it's types actually existing in SPIR-V rather than something higher level)
<chsasank> got it you're passing structs around
<aeth> in %vec2, if those results are also constant, it creates a constant vector object (syntax not final); otherwise, it generates an instruction with instruction* to the hidden special variable
<aeth> instruction* says that it's an instruction type-bc (has a result ID, and has a type ID associated with that result ID... a has no result (no assignment in the SSA) and b only has a result ID)
<chsasank> so this means your design of SSA is pretty much same as pointer based design I showed before?
<aeth> well, it's object-based... where generating instructions (unless they're type a and have no result) also creates an object... seemed the most obvious way to do it at the time
<aeth> CL doesn't really think in pointers except when doing CFFI
<chsasank> I don
<chsasank> I don't mean literal pointers, but objects whose id will be used
<aeth> objects whose actual numeric ID (as opposed to a mere "ID" object) will be generated as late as possible.
igemnace has joined #commonlisp
<chsasank> correct, you traverse the graph once the whole thing is constructed, then you assign numbers/ids
<aeth> the IDs are global, but fragments of the program could in principle be reused between different shaders
<aeth> So the IDs not only should be assigned as late as possible, but they should also be pure/immutable (and thus have no actual numeric ID at all, and just serve as a stand-in for the future ID). I don't think I do that yet.
<aeth> chsasank: and, yeah, you have to traverse it to assign numbers/ids in a very, very particular order
<chsasank> got it, very similar to LLVM builder API
<chsasank> I am wondering if there's no lispy way of doing this
<chsasank> sort of like DSL that is barely above our IRs
zaymington has joined #commonlisp
<aeth> for SPIR-V you have to go imported instruction IDs (GLSL or OpenCL) -> instructions and types (together; and they need to know the extended instruction set IDs) -> the rest of the early sections (e.g. debug information and annotations... they don't assign anything but they need to refer to things already assigned)
<aeth> and then reorder the generated instructions to be in the expected order rather than in the order the IDs need to be assigned/read in
<chsasank> I feel there should be some sort of way to make this easy
<chsasank> CPS is somewhat similar to SSA. Can we use concepts from CPS to make it simpler?
<aeth> continuation passing style isn't simple at all
<chsasank> yes I hate it as well :P
<chsasank> reminds me of callback hell from JS
<aeth> I'm guessing you'd just wind up with yet another IR
<aeth> and it's not like you'd be able to get a usable call/cc out of it on the GPU
<chsasank> I have no interest in doing CPS. In fact if you see the paper first showed the correspondence b/w CPS and SSA, they actually limit the CPS: https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=7cb90be27017772fa441981d3d362741056efd57
<chsasank> they create three lambdas: for return, call and jump
<chsasank> CPS is sort of super set of SSA
dinomug has joined #commonlisp
X-Scale has quit [Quit: Client closed]
X-Scale has joined #commonlisp
ymir has quit [Ping timeout: 260 seconds]
<chsasank> seems like a relevant paper: https://arxiv.org/pdf/2201.07272.pdf
<beach> I don't think CPS is a "super SSA".
<beach> Or "super set of SSA" rather.
thuna` has quit [Remote host closed the connection]
<beach> The CPS conversion algorithms I have seen, start by doing "assignment conversion", which turns every assignment into a function call. That step makes the program automatically SSA, but it also loses most of the advantages of SSA, namely to make each assignment introduce a new variable.
<beach> So if your CPS conversion algorithm is a linear-size transformation, then it can't have the main advantage of SSA, because SSA sometimes results in a quadratic blow-up.
<beach> In other words, you can't get the main advantage of SSA with a linear-size transformation.
tyson2 has quit [Remote host closed the connection]
<beach> But if your code does not have assignments, it is already SSA of course. But then the CPS conversion is not a substitute for SSA, but just a way to make continuations explicit.
ymir has joined #commonlisp
dnhester` has quit [Ping timeout: 264 seconds]
chiselfuse has quit [Remote host closed the connection]
chiselfuse has joined #commonlisp
<beach> younder: Writing the garbage collector in Common Lisp is not a fundamental problem. You just define functions for reading and writing arbitrary addresses in memory. It is mainly an issue of debugging it. I believe froggey wrote the Mezzano garbage collector in Common Lisp.
<beach> younder: Most of the SICL code is compiled using the SICL compiler. During bootstrapping, only the reader (Eclector) and the SICL compiler (and for reasons of bootstrapping, also an extrinsic version of the package system (Parcl)) are executed by the host Common Lisp system, and they are written in portable Common Lisp.
<beach> younder: And since the combination of Eclector and the SICL compiler are written in portable Common Lisp, then they can of course be used to compile Eclector and the SICL compiler, but that is done late in the bootstrapping process.
dnhester` has joined #commonlisp
micro has quit [Ping timeout: 260 seconds]
dnhester` has quit [Ping timeout: 252 seconds]
dnhester` has joined #commonlisp
dnhester` has quit [Ping timeout: 246 seconds]
mathrick has quit [Remote host closed the connection]
b3lm0nt has quit [Ping timeout: 268 seconds]
micro has joined #commonlisp
chomwitt has joined #commonlisp
zetef has joined #commonlisp
dnhester` has joined #commonlisp
shka has joined #commonlisp
<chsasank> @beach: you're right. I am realizing my program is already in SSA. It's just that I need to figure out how to translate to much much simpler primitives that are present in a IR like LLVM as opposed to much high level language of mine.
<beach> I see.
<chsasank> In fact I see how my programming language is now basically SSA++
chomwitt has quit [Ping timeout: 260 seconds]
benkard has joined #commonlisp
<chsasank> and I can probably have LLVM IR represented in FL directly
dnhester` has quit [Ping timeout: 255 seconds]
<chsasank> ie. DSL from LLVM IR is FL with diff primitives
mulk has quit [Ping timeout: 256 seconds]
benkard is now known as mulk
<beach> That's a lot of acronyms right there.
<chsasank> I know :(. FL = functional level language
crumbles has quit [Quit: ZNC - https://znc.in]
<chsasank> this FL language seems to be modelling the dataflows by making dependencies very explicity.
dnhester` has joined #commonlisp
b3lm0nt has joined #commonlisp
pve has joined #commonlisp
dnhester` has quit [Ping timeout: 252 seconds]
wacki has joined #commonlisp
dnhester` has joined #commonlisp
amb007 has quit [Ping timeout: 255 seconds]
traidare has joined #commonlisp
azimut has quit [Ping timeout: 260 seconds]
notzmv has quit [Ping timeout: 260 seconds]
dnhester` has quit [Ping timeout: 256 seconds]
amb007 has joined #commonlisp
Pixel_Outlaw has quit [Quit: Leaving]
ymir has quit [Ping timeout: 264 seconds]
zetef has quit [Quit: https://quassel-irc.org - Chat comfortably. Anywhere.]
msavoritias has joined #commonlisp
zetef has joined #commonlisp
waleee has quit [Ping timeout: 264 seconds]
waleee has joined #commonlisp
istewart has quit [Quit: Konversation terminated!]
istewart has joined #commonlisp
rtypo has quit [Ping timeout: 256 seconds]
rgherdt has joined #commonlisp
istewart has quit [Quit: Konversation terminated!]
ymir has joined #commonlisp
occ has quit [Ping timeout: 246 seconds]
occ has joined #commonlisp
ymir has quit [Ping timeout: 255 seconds]
micro has quit [Remote host closed the connection]
micro has joined #commonlisp
dinomug has quit [Remote host closed the connection]
danza has joined #commonlisp
varjag has joined #commonlisp
dnhester` has joined #commonlisp
waleee has quit [Ping timeout: 256 seconds]
dnhester` has quit [Ping timeout: 264 seconds]
X-Scale has quit [Quit: Client closed]
Cymew has joined #commonlisp
notzmv has joined #commonlisp
danza has quit [Read error: Connection reset by peer]
danza has joined #commonlisp
mgl has joined #commonlisp
zetef has quit [Remote host closed the connection]
zetef has joined #commonlisp
danza has quit [Ping timeout: 255 seconds]
alcor has joined #commonlisp
traidare has quit [Ping timeout: 246 seconds]
dnhester` has joined #commonlisp
prxq has quit [Quit: http://quassel-irc.org - Chat comfortably. Anywhere.]
<ebrasca> How to compare wrap around numbers?
<beach> What are those?
bendersteed has joined #commonlisp
<ebrasca> I think it is Modular arithmetic
<beach> And how do you want to compare them?
<ebrasca> After 255 will go 0
<ebrasca> How todo > or < on them
<beach> That makes no sense, unless you just want to use ordinary < and >.
<ebrasca> if I add 1 to 255 and end in 0 I expect 0 to be bigger than 255
<beach> There is no way to do that.
<beach> Because there is no way to distinguish between 0 and 255+1.
<ebrasca> TCP does it
<beach> Good for TCP. Then just do the same thing.
<ebrasca> I think I understand how todo it now, thanks beach.
<beach> Good. Care to explain?
<ebrasca> I just need to use the window size for the bigger or smaller comparisons
<beach> Window size?
traidare has joined #commonlisp
<beach> I mean, either you have modular arithmetic and then you can't distinguish 0 and 255+1, so it can't be done, or else you don't have modular arithmetic.
<ebrasca> how much data you or them can send without acknowledgement
<ebrasca> that is the window size
<ebrasca> beach: Did I make sense?
<beach> Nope, because I don't know TCP very well, and I maintain that you can't have modular arithmetic and such a comparison. So I suppose then that you don't really have modular arithmetic.
<mfiano> I am very confused
amb007 has quit [Ping timeout: 246 seconds]
<mfiano> You asked about integers and modular arithmetic
<mfiano> How do you compare ,(ldb (byte 8 0) (1+ 255)) and ,(ldb (byte 8 0) 0) ?
<ixelp> (ldb (byte 8 0) (1+ 255)) => 0, while (ldb (byte 8 0) 0) => 0
<mfiano> There are no window sizes in integers
<ebrasca> mfiano: wrap around numbers
<mfiano> You must fully state your problem domain and code I think
prxq has joined #commonlisp
<mfiano> What I posted was a wraparound number.
<mfiano> That is called modular arithmetic
prxq has quit [Client Quit]
<ebrasca> mfiano: I already figured it out I think. Sorry fur being confusing, I don't know the name of this.
<mfiano> Well then show the code
prxq has joined #commonlisp
<prxq> define-class is such a breath of fresh air.
<mfiano> Is that from some library?
<ebrasca> mfiano: I did not say I have written the code, I just know what I need todo. Give me a sec.
<aeth> is it some sort of system where 0 > 255 but otherwise the numbers are ordered as expected?
<aeth> in which case you'd test ZEROP before doing > or < etc.
<ixelp> GitHub - atlas-engineer/nclasses: A `define-class` macro for less boilerplate
<mfiano> oh defclass* fork. no thanks :)
<beach> prxq: It is my experience that macros like that are useful only when the class is used in a trivial kind of way, which is rare. Like all slots have the same constellation of :INITARGs, :INITFORMs, :READERs, :ACCESSORs, :WRITERs, :ALLOCATION, etc.
<prxq> well in my experience the boilerplate hog that is defclass really stands in the way of rapid prototyping :-) In like, I'd rather do something else than touch this humongous bag of explicitry.
<beach> I see. Good luck.
wacki has quit [Quit: Textual IRC Client: www.textualapp.com]
amb007 has joined #commonlisp
danse-nr3 has joined #commonlisp
<ixelp> *scratch*.txt · GitHub
<mfiano> Please help whoever decides to use that
<mfiano> As in, some higher power, not one of us
<prxq> what is wrong with this?
<mfiano> For starters, package level concepts should not be associated with symbols that are shared
<mfiano> ignore-errors is a big no-no in this case
<mfiano> I could go on. Treat your slots as separate symbols from your accessors. Exporting slots or accessor names makes no sense. Only symbols can be exported, and this is a huge footgun.
donleo has joined #commonlisp
<beach> Yeah, that's pretty awful, and it confirms my experience mentioned above.
<ebrasca> mfiano: I know how todo a <= b <= c. https://pastebin.com/x5rQcnpK
<ixelp> (defun =< (a b c) "a <= b <= c" (if (< a c) (<= a b c) ;; Se - Pastebin.com
<mfiano> What is the utility exactly, of defining generic "autogenerated access" documentation strings? Not to mention, for implementation details that are not part of documentation (slots)
<mfiano> accessor*
<mfiano> I mean, why not leave them out. What do you get by having such generic documentation? And what do you get when you add public documentation to private details?
<mfiano> I am confused
<aeth> holy shit
<aeth> you know the macro's good when it uses (ignore-errors ...)
<mfiano> Likely because slot documentation is pointless and implementations know it
dnhester` has quit [Ping timeout: 255 seconds]
<aeth> I've had to do this before, but not often enough to remember it without looking it up: (locally (declare #+sbcl (sb-ext:muffle-conditions sb-ext:compiler-note)) ...)
<aeth> but I don't think I've ever had to do (ignore-errors ...)
<prxq> "Exporting slots or accessor names makes no sense." I'll file that under 'purism' :-) Anyways I always have resented defclass' bureaucratic overhead.
<beach> aeth: Oh, so you have never implemented PROPER-LIST-P? :)
<mfiano> It actually has it's perfectly acceptable use-cases, believe it or not. This is not one of them.
<mfiano> its*
<mfiano> beach was thinking of what I was thinking
<aeth> beach: I think I may have tried before just settling for using alexandria's, which doesn't seem to use ignore-errors... it may not be fast enough for your use cases, though
<beach> aeth: (defun proper-list-p (object) (numberp (ignore-errors (list-length object))))
<mfiano> If we take pure to mean its opposite; taint, and you like purifying your protocols, then I can accept that.
<aeth> I think I may have used ignore-errors around parse-integer before
<beach> aeth: The idea is that LIST-LENGTH should be the only place where circularity is detected, because that code is a bit messy.
<beach> But I guess most people don't care so much about code duplication.
<aeth> ignore-errors around parse-integer has it return NIL intead of error on a bad parse, which is often useful behavior
<beach> Also, having circularity detection in one place means it can be optimized. With duplicated code, it invariably is buggy or slow i some copies.
<aeth> I wasn't aware list-length was the circularity test
<beach> But now you are?
<aeth> yes
<aeth> I've tested for circularity before
<beach> Great!
zetef has quit [Remote host closed the connection]
<beach> To be fair, it took me a while to settle on that definition of PROPER-LIST-P. I did it with duplicated code the first few times. :)
dcb has quit [Quit: Connection closed for inactivity]
<prxq> ignore-errors also returns the condition, which is useful sometimes.
<pve> prxq: You might also let your editor insert the "boilerplate" instead of using a macro.
<prxq> pve: that's true.
<pve> prxq: for instance, I wrote form-cycle (https://github.com/pve1/form-cycle) mostly for myself, but I just love it so much I feel like I should share it with you :)
<pve> prxq: ignore the weird stuff in the video, just check out the defclass part
<prxq> will do, thanks!
<pve> but obviously you can have much simpler ways of inserting code too
X-Scale has joined #commonlisp
bilegeek has quit [Quit: Leaving]
mm007emko has quit [Ping timeout: 264 seconds]
mm007emko has joined #commonlisp
danse-nr3 has quit [Ping timeout: 252 seconds]
danse-nr3 has joined #commonlisp
igemnace has quit [Read error: Connection reset by peer]
igemnace has joined #commonlisp
mm007emko has quit [Read error: Connection reset by peer]
mm007emko has joined #commonlisp
farseen has joined #commonlisp
pfdietz has joined #commonlisp
farseen is now known as itsfarseen
danse-nr3 has quit [Ping timeout: 255 seconds]
danse-nr3 has joined #commonlisp
itsfarseen is now known as farseen
farseen is now known as itsfarseen
Mon_Ouie has quit [Ping timeout: 252 seconds]
dnhester` has joined #commonlisp
danse-nr3 has quit [Ping timeout: 246 seconds]
lucasta has joined #commonlisp
dnhester` has quit [Ping timeout: 256 seconds]
<paulapatience> I've added cl-all to Guix and fixed the quoting of ABCL's wrapper script, so one can run 'guix shell abcl ccl clisp ecl gcl sbcl cl-all -- cl-all -p EXPRESSION' to evaluate an expression on all of ABCL, CCL, CLISP, ECL, GCL, SBCL.
<paulapatience> The glaring omission is Clasp, but its dependency management makes it a chore to write a Guix package for.
<paulapatience> I do want to write one eventually.
tyson2 has joined #commonlisp
random-nick has joined #commonlisp
amb007 has quit [Ping timeout: 272 seconds]
amb007 has joined #commonlisp
brokkoli_origin has quit [Remote host closed the connection]
amb007 has quit [Read error: Connection reset by peer]
amb007 has joined #commonlisp
danse-nr3 has joined #commonlisp
rogersm_ has joined #commonlisp
danse-nr3 has quit [Remote host closed the connection]
danse-nr3 has joined #commonlisp
brokkoli_origin has joined #commonlisp
itsfarseen has quit [Ping timeout: 268 seconds]
josrr has joined #commonlisp
traidare has quit [Ping timeout: 256 seconds]
itsfarseen has joined #commonlisp
rogersm_ has quit [Remote host closed the connection]
rogersm_ has joined #commonlisp
X-Scale has quit [Quit: Client closed]
mgl has quit [Ping timeout: 255 seconds]
Oddity has quit [Ping timeout: 260 seconds]
rogersm_ has quit [Remote host closed the connection]
rogersm_ has joined #commonlisp
rogersm_ has quit [Remote host closed the connection]
rogersm_ has joined #commonlisp
Alfr has quit [Quit: Leaving]
donleo has quit [Ping timeout: 268 seconds]
son0p has quit [Ping timeout: 252 seconds]
ronald has quit [Ping timeout: 268 seconds]
ronald has joined #commonlisp
traidare has joined #commonlisp
pfdietz has quit [Quit: Client closed]
dnhester` has joined #commonlisp
NicknameJohn has joined #commonlisp
azimut has joined #commonlisp
dnhester` has quit [Ping timeout: 260 seconds]
fe[nl]ix has quit [Quit: Valete!]
Alfr has joined #commonlisp
fe[nl]ix has joined #commonlisp
rtypo has joined #commonlisp
cl-arthur has quit [Read error: Connection reset by peer]
cl-arthur has joined #commonlisp
eddof13 has joined #commonlisp
infos has joined #commonlisp
ymir has joined #commonlisp
BrokenCog has quit [Quit: leaving]
pfdietz has joined #commonlisp
remexre has quit [Remote host closed the connection]
remexre has joined #commonlisp
chiselfuse has quit [Remote host closed the connection]
chiselfuse has joined #commonlisp
ec has quit [Remote host closed the connection]
ec has joined #commonlisp
ec has quit [Remote host closed the connection]
ec has joined #commonlisp
ec has quit [Remote host closed the connection]
ec has joined #commonlisp
ymir has quit [Ping timeout: 256 seconds]
varjag has quit [Ping timeout: 252 seconds]
danse-nr3 has quit [Ping timeout: 252 seconds]
danse-nr3 has joined #commonlisp
traidare has quit [Ping timeout: 264 seconds]
rgherdt has quit [Ping timeout: 272 seconds]
pranavats has left #commonlisp [Disconnected: Hibernating too long]
eddof13 has quit [Quit: eddof13]
NotThatRPG has joined #commonlisp
eddof13 has joined #commonlisp
alcor has quit [Remote host closed the connection]
alcor has joined #commonlisp
son0p has joined #commonlisp
rgherdt has joined #commonlisp
Cymew has quit [Ping timeout: 272 seconds]
rogersm_ has quit [Remote host closed the connection]
occ has quit [Ping timeout: 240 seconds]
rogersm_ has joined #commonlisp
rogersm_ has quit [Ping timeout: 260 seconds]
dcb has joined #commonlisp
dnhester` has joined #commonlisp
occ has joined #commonlisp
istewart has joined #commonlisp
dnhester` has quit [Ping timeout: 260 seconds]
pranavats has joined #commonlisp
mgl has joined #commonlisp
eddof13 has quit [Quit: eddof13]
occ has quit [Ping timeout: 264 seconds]
eddof13 has joined #commonlisp
nij- has joined #commonlisp
mm007emko has quit [Ping timeout: 264 seconds]
mm007emko has joined #commonlisp
nij- has left #commonlisp [Using Circe, the loveliest of all IRC clients]
son0p has quit [Quit: Bye]
rogersm_ has joined #commonlisp
rogersm_ has quit [Ping timeout: 255 seconds]
ymir has joined #commonlisp
occ has joined #commonlisp
occ has quit [Read error: Connection reset by peer]
son0p has joined #commonlisp
occ has joined #commonlisp
<ebrasca> How to translate "((int32_t)((a) - (b)) < 0)" into lisp?
rainthree has joined #commonlisp
<cdegroot> (< (- a b) 0) unless you really need the right binary type for optimization purposes?
<cdegroot> That cast is after the compare though, so you want a number back instead of a logic (boolean) value?
zetef has joined #commonlisp
<ebrasca> I am just interested in the True or false part
<mfiano> First you would need to know the bits type of 'a' and 'b' in that scope
<ebrasca> 32bit unsigned
<mfiano> then it is simply:
<mfiano> (ldb (byte 32 0) (+ a b))
danse-nr3 has quit [Read error: Connection reset by peer]
danse-nr3 has joined #commonlisp
yitzi has joined #commonlisp
<mfiano> Modular arithmetic can be done other ways without ldb too. You can use ASH if you'd like for example
<ebrasca> I don't see hot todo then ((int32_t)((a) - (b)) > 0)
<mfiano> (plusp *)
<ebrasca> I see
<ebrasca> I am not familiar with ldb
<ebrasca> even that I used it in the past
<mfiano> Ok then we can do it another way that might make it easier
occ has quit [Ping timeout: 264 seconds]
<mfiano> (ldb (byte 32 0) x) is the same as (logand x *largest-number-before-wraparound*)
danse-nr3 has quit [Ping timeout: 264 seconds]
<mfiano> (ldb (byte 32 0) x) means that if x evaluates to anything more than 32 bits, wrap it around keeping the bit width of 32
zetef has quit [Remote host closed the connection]
<mfiano> In CL, integers are of arbitrary precision, and may or may not be allocated on the heap
<mfiano> They have an infinite number of most significant bits, so we have to translate these lesser languages
<ebrasca> I remember now, I just forgot about this.
<mfiano> Oh!
zaymington has quit [Ping timeout: 246 seconds]
<mfiano> You started with unsigned and you need to cast to signed
<mfiano> You need some sign extension here
<mfiano> This is not going to be so simple to explain now
zxcvz has joined #commonlisp
<ebrasca> Why is it is a + b ?
occ has joined #commonlisp
<mfiano> Because sign extension changes the range
<mfiano> int32 has a different range than uint32
<gilberth> To split hair: In C, if 'a' and 'b' are unsigned int types (int32_t)((a) - (b)) < 0 is either false or UB.
<mfiano> These were written as simply as I can to help you build up what you need. Good luck:
<mfiano> (defun ensure-ub32 (x) (logand x #.(1- (ash 1 32))))
<mfiano> (defun u32->i32 (x) (- (ensure-ub32 (+ x #1=#.(- (ash 1 (1- 32))))) #1#))
<mfiano> with your code being (u32->i32 (+ (ensure-u32 x) (ensure-u32 y)))
<mfiano> These names are very bad.
<mfiano> sorry ensure-ub32
<bike> gilberth: false i understand, but how would you get UB?
<bike> if the result is out of range, maybe...?
occ has quit [Read error: Connection reset by peer]
<gilberth> bike: If a and b are unsigned then (a - b) is unsigned as well and thus always >= 0. Conversion of an out of range value to a signed integer type with C is UB.
<mfiano> We do not even know if this is using C++ in a C way. Are the semantics changed in any of those standards?
<mfiano> But, good to know
<bike> out of range, right.
<ebrasca> I think the C code is C99
<gilberth> ebrasca: Same for C99.
<mfiano> Just pick up a copy of Hacker's Delight, and be delighted for an extended period of time.
<bike> i think the basic point here is that the C arithmetic rules are pretty complex and lots of people misunderstand them, so it might be better to just say what arithmetic operation you want to happen irrespective of C.
<bike> "lots of people" including, e.g., me
<mfiano> ebrasca: You really need to know how to do bit manipulation very well, if you are to translate fixed-width type arithmetic to CL
<gilberth> Anyhow, for all practical purposes the author wanted to say (a < b) and got confused.
masinter has joined #commonlisp
<mfiano> and also that C is very complex and the rules are strange
igemnace has quit [Quit: WeeChat 4.2.1]
<gilberth> C is surprising because with unsigned integer types it specifies modulo arithmetic, while for signed integer types it says that out of range is UB.
<bike> incidentally yes, C++ does have different arithmetic rules from C. I think they'd be the same in this case, but shifts on signed integers are more defined in C++20 than in C.
<gilberth> bike: Interesting. Did they actually specify an arithmetic right shift with C++?
<bike> yes.
<bike> "The value of a >> b is a/2^b, rounded towards negative infinity (in other words, right shift on signed a is arithmetic right shift)." according to cppreference, because hell if i can understand the actual standard
<gilberth> Hmm. Interesting.
<gilberth> I happen to know C's rules because atm I am working on my expression compiler for noffi and was wondering whether I signal a runtime error on out-of-range conversion to signed integers.
rogersm_ has joined #commonlisp
mm007emko has quit [Read error: Connection reset by peer]
Mon_Ouie has joined #commonlisp
mm007emko has joined #commonlisp
notzmv has quit [Ping timeout: 272 seconds]
rogersm_ has quit [Remote host closed the connection]
eddof13 has quit [Quit: eddof13]
jon_atack has quit [Ping timeout: 260 seconds]
zxcvz has quit [Quit: zxcvz]
dnhester` has joined #commonlisp
st_aldini has joined #commonlisp
rogersm_ has joined #commonlisp
mark` has joined #commonlisp
st_aldini has quit [Read error: Connection reset by peer]
rogersm_ has quit [Ping timeout: 256 seconds]
st_aldini has joined #commonlisp
dnhester` has quit [Ping timeout: 268 seconds]
rogersm_ has joined #commonlisp
rogersm_ has quit [Remote host closed the connection]
thuna` has joined #commonlisp
st_aldini has quit [Client Quit]
X-Scale has joined #commonlisp
Pixel_Outlaw has joined #commonlisp
st_aldini has joined #commonlisp
traidare has joined #commonlisp
zaymington has joined #commonlisp
donleo has joined #commonlisp
tyson2 has quit [Remote host closed the connection]
msavoritias has quit [Ping timeout: 268 seconds]
occ has joined #commonlisp
Oddity has joined #commonlisp
rogersm_ has joined #commonlisp
occ has quit [Ping timeout: 264 seconds]
rogersm_ has quit [Ping timeout: 255 seconds]
rainthree has quit [Ping timeout: 264 seconds]
X-Scale has quit [Ping timeout: 250 seconds]
occ has joined #commonlisp
ymir has quit [Ping timeout: 246 seconds]
occ has quit [Ping timeout: 255 seconds]
eddof13 has joined #commonlisp
eddof13 has quit [Client Quit]
st_aldini has quit [Quit: st_aldini]
eddof13 has joined #commonlisp
st_aldini has joined #commonlisp
occ has joined #commonlisp
josrr has quit [Remote host closed the connection]
<ebrasca> mfiano: I asked the AI the same thing and this is his answer "(< (truncate (- a b)) 0)".
mariari has quit [Ping timeout: 272 seconds]
<mfiano> o.O
<mfiano> That is pointless code
jonatack has joined #commonlisp
occ has quit [Ping timeout: 252 seconds]
azimut has quit [Remote host closed the connection]
azimut has joined #commonlisp
rogersm_ has joined #commonlisp
eddof13 has quit [Quit: eddof13]
waleee has joined #commonlisp
eddof13 has joined #commonlisp
rogersm_ has quit [Ping timeout: 255 seconds]
mariari has joined #commonlisp
<edgar-rft> that's what happens when you ask awful intelligence
gxt_ has quit [Remote host closed the connection]
gxt_ has joined #commonlisp
occ has joined #commonlisp
<bike> back in the day you'd have to pay someone to write crappy code. we've come so far.
occ has quit [Read error: Connection reset by peer]
akoana has joined #commonlisp
NicknameJohn has quit [Ping timeout: 264 seconds]
bendersteed has quit [Quit: bendersteed]
<yitzi> Someone has write the crappy code. Better machines then us. Maybe the new instructions in CS classes should be: "Consult your AI system of choice for its terrible solution. Then go make an attempt to write some good code."
lucasta has quit [Quit: Leaving]
ymir has joined #commonlisp
<ebrasca> Sometimes it gives good code
<yitzi> I am sure. Copyrights be damned. ... rant done.
<edgar-rft> I'm eagerly waiting for "SICP - chatGPT edition"
rbcarleton has left #commonlisp [ERC 5.4 (IRC client for GNU Emacs 28.2)]
<bike> in any case, it didn't write good code this time
<bike> if what you want is "is A less than B?", you should write (< a b). cleverness will lead you to perdition
tyson2 has joined #commonlisp
akoana has quit [Quit: leaving]
mathrick has joined #commonlisp
nij- has joined #commonlisp
<ebrasca> bike: It is not just that, it is more like ((int)((a)-(b)) < 0). I found it in freebsd code.
tfeb has joined #commonlisp
<bike> as was already explained, that code is either undefined or false in C. please just indicate what you actually want in human language
Odin-DECK has joined #commonlisp
occ has joined #commonlisp
dnhester` has joined #commonlisp
occ has quit [Read error: Connection reset by peer]
ymir has quit [Ping timeout: 264 seconds]
dnhester` has quit [Ping timeout: 240 seconds]
mark`` has joined #commonlisp
mark` has quit [Ping timeout: 260 seconds]
<prxq> One of the things I find hilarious about C is the existence of an unofficial standard. Stuff that is officially UB but all implementations implement in a specific way because of risk of lynching.
tfeb has quit [Quit: died]
<bike> i think that's fairly inevitable to various degrees. you can see some of that stuff for lisp in WSCL.
tyson2 has quit [Read error: Connection reset by peer]
<prxq> bike yeah but not like this :-)
<prxq> In a nutshell, if compiler writers didn't refrain from certain optimizations allowed by the standard, null pointer checks get optimized away. Leading to mayhem and hilarity.
<bike> not nearly as severe here, no
<prxq> I had a buch of blog posts bookmarked from that era. There was more strange behavior, like taking a pointer to a variable int *a = &b, writing to a, and then a and b having different values.
Odin-DECK has quit [Ping timeout: 240 seconds]
<prxq> imaging having old, mission critical code break due to a new compiler and having to find *that* after god knows how much search. And then be told: your fault, it's UB! People reacted as expected.
dnhester` has joined #commonlisp
<jmercouris> is there something like this
<ixelp> pty — Pseudo-terminal utilities — Python 3.12.2 documentation
<jmercouris> for Common Lisp?
Odin-DECK has joined #commonlisp
nij- has left #commonlisp [Using Circe, the loveliest of all IRC clients]
pranavats has left #commonlisp [Disconnected: Hibernating too long]
pranavats has joined #commonlisp
dnhester` has quit [Ping timeout: 255 seconds]
<bike> i don't know about anything exactly the same, but you can use uiop/launch-program to run a process asynchronously and grab its input and output streams. you could probably build something like this on top of that?
<jmercouris> bike: aha, that is a very logical point
<jmercouris> I don't know why that was eluding me for so long...
<jmercouris> I will try that
<younder> gcc has a -pedantic flag that warns you of undefined behavior. As long as you -Wall -Wextra -pedandic and remove all warnings you should have a good chance.
<younder> pro env's like C-Lion provide such extensive feedback that it isn't much of a problem.
alcor has quit [Ping timeout: 240 seconds]
<younder> THing is C is the devel you know. All the pitfalls are known and there are workarounds, so it works out ok anyhow
<younder> devil
<jmercouris> C is a crime against humanity
<younder> bah
<jmercouris> we would be literally living on Saturn right now if it wasn't for C
<jmercouris> I'm just joking, but seriously, it is time to stop using C
<bike> we don't need to go too far off topic.
<younder> Has all that bloated java code really made things better?
eddof13 has quit [Quit: eddof13]
alcor has joined #commonlisp
eddof13 has joined #commonlisp
rogersm_ has joined #commonlisp
jonatack has quit [Ping timeout: 256 seconds]
eddof13 has quit [Quit: eddof13]
triffid has joined #commonlisp
eddof13 has joined #commonlisp
yitzi has quit [Remote host closed the connection]
rogersm_ has quit [Quit: Leaving...]
son0p has quit [Ping timeout: 256 seconds]
ymir has joined #commonlisp
eddof13 has quit [Quit: eddof13]
traidare has quit [Ping timeout: 260 seconds]
gxt_ has quit [Remote host closed the connection]
gxt_ has joined #commonlisp
eddof13 has joined #commonlisp
shka has quit [Ping timeout: 260 seconds]
chomwitt has joined #commonlisp
<bjorkint0sh> yes younder. In terms of job security and consultant-ware, java has done wonders!
ec has quit [Remote host closed the connection]
ec has joined #commonlisp
eddof13 has quit [Quit: eddof13]
Odin-DECK has quit [Quit: No noise?]
amb007 has quit [Ping timeout: 255 seconds]
amb007 has joined #commonlisp
ymir has quit [Ping timeout: 260 seconds]
robin_ has quit [Remote host closed the connection]
robin has joined #commonlisp
triffid has quit [Remote host closed the connection]
triffid has joined #commonlisp
amb007 has quit [Ping timeout: 255 seconds]
elderK has joined #commonlisp
ebrasca has quit [Remote host closed the connection]
<younder> beach: I have prepared a preliminary plan and published it at https://jthing.github.io/cicl-hugo/posts/compiler/ so you can take a look at it at your leasure.
<ixelp> Compiler - CICL Compiler
ymir has joined #commonlisp
eddof13 has joined #commonlisp
infos has quit [Ping timeout: 256 seconds]
cmack has joined #commonlisp
dnhester` has joined #commonlisp
eddof13 has quit [Quit: eddof13]
notzmv has joined #commonlisp
<aeth> It's fun when -Wall isn't all because iirc -Werror that turns warnings into errors so then they have to add -Wextra which also probably isn't exhaustive anymore
<aeth> and then you have to run it against valgrind anyway because you need to catch things at runtime, too (and you better hope that your program still runs fast enough under valgrind)
<aeth> C cultivates an environment of extreme, extreme paranoia of unsafe behavior and yet is filled with footguns.
josrr has joined #commonlisp
dnhester` has quit [Ping timeout: 272 seconds]
jonatack has joined #commonlisp
NicknameJohn has joined #commonlisp
tyson2 has joined #commonlisp
alcor has quit [Remote host closed the connection]
mgl has quit [Ping timeout: 264 seconds]
son0p has joined #commonlisp
tedwing has joined #commonlisp
pve has quit [Remote host closed the connection]
dino_tutter has quit [Ping timeout: 255 seconds]
chomwitt has quit [Ping timeout: 264 seconds]
amb007 has joined #commonlisp
amb007 has quit [Ping timeout: 255 seconds]
donleo has quit [Ping timeout: 260 seconds]
amb007 has joined #commonlisp
ymir has quit [Ping timeout: 260 seconds]
amb007 has quit [Ping timeout: 264 seconds]