On 03/03/2015 01:03 PM, Daniel Colascione wrote: > On 03/03/2015 11:35 AM, Stefan Monnier wrote: >>>> Do we want to document it as a function? Maybe it would be better to >>>> document it as an "object" of unspecified implementation (i.e. calling >>>> it via funcall rather than via iter-next is unsupported). >> >>> The iterator is an opaque object; a generator (of which an iterator is >>> an instance) is always a function. How can I make that clear? >> >> As I mentioned a bit further, the explanation about the difference >> between an iterator and a generator clarifies this, but comes >> a bit late. > > Right. I'm not sure that level of detail is appropriate for the chapter > introduction though. > >>>> To get back to iter-close, this seems to be a tricky aspect of the >>>> implementation. Could you give me more details, such as an example >>>> problematic case where calling iter-close makes a difference? >>>> I guess this has to do with those finalizers, so if you could explain >>>> how/why these are used, I'd really appreciate it. >> >>> In conventional Emacs Lisp, we're able to use unwind-protect to clean up >>> resources. I'd like generator functions to be as similar to regular Lisp >>> code as possible, and without support for closing iterators, preferably >>> automatically after GC, we'll violate this user expectation. Sure, it's >>> probably possible to work around the absence in specific cases, but >>> having to very careful will lead to leaks. The Python people had to add >>> a very similar feature in PEP 342 for much the same reason. >> >> I'm inclined to believe you that it's needed, but I'd really like to see >> some good explanation for why, probably with a motivating example. >> Ideally in a comment somewhere. > > I don't have one yet, and that's mostly because the higher-level > facilities I want to build on top of generators don't exist yet. In > particularly, I'd like to build something that makes process filters > easier to write, that would allow you to write something like > > (let ((line (iter-yield-from (easy-filter-read-line-async mumble))) > ;; Emacs runs while we're reading the line! > (do-something line)) > > I don't want to iter-close later: if we add it, we'll change the > semantics of existing unwind-protect blocks. It feels better to do it > right from the start. I can think a few possible resources we might want > to clean up: what if we want to unload a module when it's no longer > needed? Kill a hidden buffer? Remove overlays? Kill a subprocess? Delete > a file? > >>>>> + (let* ((state (cl-gensym (format "cps-state-%s-" kind)))) >>>> ^^^^^^^^^ >>>> Elisp prefers make-symbol. >> >>> cl-gensym makes it possible to actually read the code the macro >>> produces. A wrapper that conditionally calls make-symbol should suffice. >> >> A wrapper is not worth the trouble. > > I added one already. Mind leaving it there? > >> As for making `make-symbol' code readable, I use (setq print-gensym t) >> and/or (setq print-circle t). >> >>> Yes, we probably should --- but if we do that, we should impose some >>> kind of sane time limit on unwind-protect unwindforms in order to avoid >>> freezing Emacs. That is, we should be able to recover from >>> (unwind-protect nil (while t)) without having to attach a debugger or >>> send a signal. >> >> We should be able to recover from an inf-loop inside inhibit-quit in any >> case, yes. Normally C-g C-g C-g does it, but it kind of defeats the >> purpose in this case since users my lean on C-g without realizing that >> it has a different meaning. >> >>>> `(iter--blabla ,value (lambda (x) (iter-yield x))) >>> What do you mean? >> >> Move the unwind-protect and the loop into a separate higher-order function. > > I'm not sure that would help. We need to keep the `iter-yield' in the > body of the calling function in order to be correct. > >>> Fixed in a subsequent commit. Manually, though: maybe >>> macroexp-parse-body is the right thing. >> >> Yes, it's the new thing recently introduced, so that it handle "all" the >> special declaration-like thingies (docstrings, declare, cl-declare, you >> name it). > > Neat. Fixed. It's a shame we can't use it in `defmacro'. It's buggy for empty functions: ELISP> (macroexp-parse-body '("foo" (declare indent 5))) (("foo") (declare indent 5)) ELISP> (macroexp-parse-body '("foo" (declare indent 5) nil)) (("foo" (declare indent 5)) nil)