freenode/#lisp - IRC Chatlog
Search
3:18:47
Josh_2
I have a slynk server that was working but now whenever I try to connect my emacs just freezes, any ideas?
7:09:26
jackdaniel
so what was the yesterday's conclusion? undefined beahvior, use do or something more sophisticated? :)
7:11:24
jackdaniel
heh, I now see mail from gitlab.cl.net that phoe proposes to disable tests as undefined behavior
7:11:27
beach
For WSCL, I am debating whether to explicitly specify that the behavior is undefined or whether to define the behavior. And if the latter, what alternative to opt for.
7:12:05
ck_
I couldn't attend the debate, is there a short summary of the behavior in question, other than "loop" ?
7:16:27
jackdaniel
beach: if it were a vote for a preferred alternative I'd say that "6" is more useful; it makes the mental model of what's going on easier: increment always goes after the iteration and finally goes after all iterations
7:17:35
aeth
(loop for i of-type (integer 0 5) from 0 to 5 do (print i)) ; should this give a type-error when 6 is reached even though 6 is only used in terminating the loop?
7:18:35
jackdaniel
right, I've left it out because of-type seems to have clear semantics: if we choose to increment x to 6 that should signal a condition, if we choose not to increment to 6 then it will meet criteria
7:22:49
aeth
jackdaniel: well, I had to bring it up because if it's unspecified then maybe some implementations would choose both interpretations, i.e. unless the varaible is referred to in a finally (in its final, one above, form) do not have the type-error
7:52:56
fiddlerwoaroof
It's always interesting to see how many different interpretations of a specification arise
7:54:38
fiddlerwoaroof
I encounter this semi-regularly at work, where we plan out a project and then, when implementation-time comes around, the team implementing often realize that there still remain at least two interpretations of the plan
8:29:55
pjb
beach: didn't you argue at els 2016 that MIT loop was bugged on this point? That it should print 5?
8:32:27
pjb
I would note that this is related to C for(unsigned char i=0;i<=MAX_UCHAR;i++), which if not compiled carefully, can be an infinite loop…
8:51:36
beach
pjb: Yes, that sounds plausible, and that's how I implemented it for SICL LOOP, like I said.
10:29:43
phoe
Yesterday I was trying to figure out how to treat the LOOP issue for a long while and it left me kinda exhausted
10:30:00
phoe
I was hopeful that the conclusion of "let's treat it as undefined" would be decent enough
10:31:24
pjb
phoe: well, since all implementation are not conforming on this point, as a programmer you need to consider it as undefined, until they're all corrected. Ie. do not use the loop variables in the finally clause! But as an implementer, you need to correct it.
10:43:12
phoe
my question is, if it's practically impossible to agree what should the answer be than should we agree on an ANSI-TEST that tests this at all
10:45:02
White_Flame
its your very own "is the dress white and gold, or blue and black". Congratulations
10:47:32
pjb
Perhaps we'd need a comitee of implementers to decide these matters. At least a mail-list. But where all implementers, free and commercial would participate.
10:50:54
phoe
if we are down to implementations, is anyone around with a working cl-all? I'd need to see what cl-all says on the issue
10:51:24
pjb
phoe: 6 for sbcl ccl abcl ecl, which are the implementations I have currently running on macOS.
10:52:19
pjb
phoe: now, we may consider that, in a way, the implementation is free to set the loop variable to "anything" it wants in the finally, and that the bug is in the user giving a wrong type.
10:53:12
pjb
phoe: I wonder why the implementation don't set it to NIL for finally. for x to 10 finally (return x) could return 20, or 12, if the implementation thinks it's efficient to add more than the by, and to remove some before next loop…
10:53:45
Shinmera
phoe: how would it know better if the bounds are dynamic (but only static within a user-known range)
10:53:52
pjb
that's basically my point, with respect to type declarations! The implementation knows better!
10:54:23
phoe
Shinmera: the implementation can compute it - from 1 to 10 by 5 can be at most (integer 1 14)
10:55:01
pjb
(loop for i to (foo z)) the implementation can compute the type of (foo z), and know if it's bound or not.
10:55:53
phoe
it could in theory do a dispatch based on the compiled versions of the code it prepared aheat of time
10:56:34
phoe
but then if the user does OF-TYPE but passes values not of that type it's not the problem of the implementation
10:57:39
Shinmera
if it can set it to literally whatever, then of-type is entirely useless because you could never pass a type that is correct other than T
11:04:53
phoe
So what is the user supposed to do in case of (loop for x of-type fixnum from 0 to most-positive-fixnum)
11:07:12
phoe
because if the answer to the original question is 6 then the above code does not allow X to be a fixnum which makes it non-conforming with ANSI CL
11:09:21
pjb
phoe: the question is more general: what use does the implementation make of type declarations. If it uses them to effectly allocate low-level memory for untagged/unboxed data, then the secondary question is what happens when you (incf x) to go beyond most-positive-fixnum (or any other internal maximum of the data type used): does it do checks? If yes, then what optimization is that? If the check fails, it has to allocate new mem
11:09:21
pjb
store the result or what? Or does it blindly use modulo arithmetic and fail lamentably?
11:10:22
pjb
In any case, it sounds very silly to do such a thing (allocate memory for unboxed data).
11:13:44
phoe
(lambda () (loop for x of-type fixnum from (1- most-positive-fixnum) to most-positive-fixnum do (progn) finally (print x)))
11:15:41
pjb
(let ((x (1- most-positive-fixnum))) (if (< x (1- most-positive-fixnum)) (incf x) 'done)) #| --> done |#
11:16:17
pjb
But of course, this is less optimized, since you have a test, a subtraction and an addition, instead of an addition and a test that fails…
11:17:18
phoe
(declaim (optimize (safety 0))) (lambda () (loop for x of-type fixnum from (1- most-positive-fixnum) to most-positive-fixnum do (progn) finally (print x)))
11:22:52
pjb
The thing is that the optimization works 1152921504606846974/1152921504606846975 of the time…
11:25:33
pjb
If the implementation can optimize some specific integer ranges (eg. 0..255, or -128..127, or etc), then it can do it, but it needs to be able to determine the type specified by the user, and process the last element of the range specially.
11:26:50
pjb
:of-type (integer 0 5) should not pose any problem, since 3 bits can store up to 7. So internally x can be 6, and the user blamed for specifying the wrong type, or the final value be adjusted.
11:27:19
pjb
:of-type (unsigned-byte 1) :to 255 and similar should be processed specially, for the last iteration.
11:28:35
pjb
phoe: yes. Which is why I don't think that x=6 is a good thing for :to. But since x can go way beyond with (loop for x by 3 to 10 finally (return x)) #| --> 12 |# perhaps we should allow final x > max. and the user :of-type is wrong.
11:30:43
phoe
if the implementation needs to make X any type it requires to then it should be impossible to provide OF-TYPE to that variable
11:31:12
phoe
because what if the implementation requires it to be a bignum but the user tells it to be a fixnum
11:31:56
pjb
phoe: it may be because the programs runs on a different implementation with a different most-positive-fixnum. Then the implementation must signal the type error.
11:32:58
pjb
And if the bound are variable, either you know they're within most-positive-fixnum or you don't. If you don't, don't declare it fixnum…
11:33:12
phoe
(loop for x of-type fixnum from (1- most-positive-fixnum) to most-positive-fixnum do (progn) finally (print x)) is theoretically within fixnum
11:34:05
pjb
but what about (loop for x of-type fixnum from (1- most-positive-fixnum) by 3 to most-positive-fixnum do (progn) finally (print x)) ?
11:34:33
phoe
in that case it looks like it would have to be (1- most-positive-fixnum) by the same logic
11:34:35
pjb
The last iteration is with (1- most-positive-fixnum) so in finally x = (1- most-positive-fixnum) is consistent.
11:35:39
phoe
but it makes no sense from the optimization point of view if the implementation has a temp variable of type integer
11:36:15
phoe
since we do bignum arithmetic anyway then we could drop the fixnum variable altogether and ignore the OF-TYPE
11:39:06
phoe
or do we just close our eyes and pretend not to notice that we are doing the same shit as C when it comes to edge cases
11:41:04
phoe
this means that setting X to 6 in the original question is incorrect in general and all implementations known to me right now are buggy
11:42:51
pjb
phoe: more specifically, I could not find in clhs the specification of what value should be bound to the loop variables in the finally clause.
11:44:11
phoe
pjb: neither could I. The above conclusion comes from the fact that it cannot be safely bound to 1+ most-positive-fixnum if it is declared to be a fixnum and, from the user point of view, it looks like it's a fixnum all the time.
11:44:26
pjb
phoe: so we must decide. If we decide on the value of the last iteration, then things are clear. If not, then it will be mostly implementation dependent. (Again, setting it to NIL would be a valid choice. For example, the variables can be bound to NIL before the loop starts…
11:51:06
phoe
"A loop macro form expands into a form containing one or more binding forms (that establish bindings of loop variables) and a block and a tagbody (that express a looping control structure). The variables established in loop are bound as if by let or lambda. "
11:51:19
phoe
this means that everything inside LOOP (prologue, body, epilogue) is in scope of the bindings
12:23:20
pfdietz
(mapcar #'funcall (loop for x from 1 to 5 collect (lambda () x))) ==> (5 5 5 5 5) ;; maybe?