unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Re: space leak from `values'
       [not found]         ` <jwvu0vs9gjz.fsf-monnier+emacs@gnu.org>
@ 2004-07-28 23:13           ` Kim F. Storm
  2004-07-29  7:50             ` Miles Bader
  0 siblings, 1 reply; 10+ messages in thread
From: Kim F. Storm @ 2004-07-28 23:13 UTC (permalink / raw)
  Cc: Dave Love, emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> > I bet most people don't know that `values' even exists, let alone what
> > conses onto it!
> 
> Completely agreed.

I know it -- I just fail to see why it is useful.

> 
> > It seems basically unclean to let something like that grow
> > unboundedly, even if it doesn't keep a significant part of the heap
> > live, and especially as it's pretty obscure.
> 
> I'd vote for removing it, but IIRC some people argued for keeping it last
> time this came up.  So I suggest we replace the lisp with a ring.


Here is a patch which reduces the values list to max 10 elements (not
configurable -- should it be?)

The major part of the patch is the addition of a new C-level function
`setnthcdr' which is used by other C and lisp level code to truncate
the `values' list.

This function seems generally useful so I think we should add it 
in any case...

> Still, it should have a different name to avoid surprises (like
> `values-of-last-interactive-evaluations').

Or `last-eval-results'.  However, I didn't change that.


Index: src/fns.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/fns.c,v
retrieving revision 1.372
diff -c -r1.372 fns.c
*** src/fns.c	6 Jul 2004 19:36:56 -0000	1.372
--- src/fns.c	28 Jul 2004 23:02:02 -0000
***************
*** 1415,1420 ****
--- 1415,1447 ----
    return Fcar (Fnthcdr (n, list));
  }
  
+ DEFUN ("setnthcdr", Fsetnthcdr, Ssetnthcdr, 2, 3, 0,
+        doc: /* Set cdr of Nth element of LIST to VALUE (nil if omitted), returns the result.
+ If N is negative, count from end of LIST.
+ If list has less than N elements, do not modify list.  */)
+   (n, list, value)
+      Lisp_Object n, list, value;
+ {
+   register Lisp_Object elt;
+   register int num;
+   CHECK_NUMBER (n);
+   num = XINT (n);
+   if (num < 0)
+     num += XFASTINT (Flength (list));
+   if (num <= 0)
+     return Qnil;
+   for (elt = list; --num > 0 && !NILP (elt);)
+     {
+       QUIT;
+       if (! CONSP (elt))
+ 	wrong_type_argument (Qlistp, elt);
+       elt = XCDR (elt);
+     }
+   if (CONSP (elt))
+     XSETCDR (elt, value);
+   return list;
+ }
+ 
  DEFUN ("elt", Felt, Selt, 2, 2, 0,
         doc: /* Return element of SEQUENCE at index N.  */)
       (sequence, n)
***************
*** 5715,5720 ****
--- 5742,5748 ----
    defsubr (&Ssubstring_no_properties);
    defsubr (&Snthcdr);
    defsubr (&Snth);
+   defsubr (&Ssetnthcdr);
    defsubr (&Selt);
    defsubr (&Smember);
    defsubr (&Smemq);
Index: src/lisp.h
===================================================================
RCS file: /cvsroot/emacs/emacs/src/lisp.h,v
retrieving revision 1.501
diff -c -r1.501 lisp.h
*** src/lisp.h	30 Jun 2004 13:09:05 -0000	1.501
--- src/lisp.h	28 Jul 2004 23:02:04 -0000
***************
*** 2271,2276 ****
--- 2271,2277 ----
  extern Lisp_Object substring_both P_ ((Lisp_Object, int, int, int, int));
  EXFUN (Fnth, 2);
  EXFUN (Fnthcdr, 2);
+ EXFUN (Fsetnthcdr, 3);
  EXFUN (Fmemq, 2);
  EXFUN (Fassq, 2);
  EXFUN (Fassoc, 2);
Index: src/lread.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/lread.c,v
retrieving revision 1.322
diff -c -r1.322 lread.c
*** src/lread.c	26 Apr 2004 21:28:40 -0000	1.322
--- src/lread.c	28 Jul 2004 23:02:03 -0000
***************
*** 1377,1383 ****
  
        if (printflag)
  	{
! 	  Vvalues = Fcons (val, Vvalues);
  	  if (EQ (Vstandard_output, Qt))
  	    Fprin1 (val, Qnil);
  	  else
--- 1377,1384 ----
  
        if (printflag)
  	{
! 	  Vvalues = Fsetnthcdr (make_number (10),
! 				Fcons (val, Vvalues), Qnil);
  	  if (EQ (Vstandard_output, Qt))
  	    Fprin1 (val, Qnil);
  	  else
Index: lisp/simple.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/simple.el,v
retrieving revision 1.651
diff -c -r1.651 simple.el
*** lisp/simple.el	23 Jul 2004 11:52:03 -0000	1.651
--- lisp/simple.el	28 Jul 2004 23:02:05 -0000
***************
*** 825,836 ****
  	 current-prefix-arg))
  
    (if (null eval-expression-debug-on-error)
!       (setq values (cons (eval eval-expression-arg) values))
      (let ((old-value (make-symbol "t")) new-value)
        ;; Bind debug-on-error to something unique so that we can
        ;; detect when evaled code changes it.
        (let ((debug-on-error old-value))
! 	(setq values (cons (eval eval-expression-arg) values))
  	(setq new-value debug-on-error))
        ;; If evaled code has changed the value of debug-on-error,
        ;; propagate that change to the global binding.
--- 825,836 ----
  	 current-prefix-arg))
  
    (if (null eval-expression-debug-on-error)
!       (setq values (setnthcdr 10 (cons (eval eval-expression-arg) values)))
      (let ((old-value (make-symbol "t")) new-value)
        ;; Bind debug-on-error to something unique so that we can
        ;; detect when evaled code changes it.
        (let ((debug-on-error old-value))
! 	(setq values (setnthcdr 10 (cons (eval eval-expression-arg) values)))
  	(setq new-value debug-on-error))
        ;; If evaled code has changed the value of debug-on-error,
        ;; propagate that change to the global binding.
Index: lisp/emacs-lisp/edebug.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/emacs-lisp/edebug.el,v
retrieving revision 3.69
diff -c -r3.69 edebug.el
*** lisp/emacs-lisp/edebug.el	10 Jun 2004 04:18:04 -0000	3.69
--- lisp/emacs-lisp/edebug.el	28 Jul 2004 23:02:07 -0000
***************
*** 3716,3722 ****
  		      'read-expression-history)))
    (princ
     (edebug-outside-excursion
!     (setq values (cons (edebug-eval edebug-expr) values))
      (concat (edebug-safe-prin1-to-string (car values))
              (eval-expression-print-format (car values))))))
  
--- 3716,3722 ----
  		      'read-expression-history)))
    (princ
     (edebug-outside-excursion
!     (setq values (setnthcdr 10 (cons (edebug-eval edebug-expr) values)))
      (concat (edebug-safe-prin1-to-string (car values))
              (eval-expression-print-format (car values))))))
  
Index: lisp/emacs-lisp/pp.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/emacs-lisp/pp.el,v
retrieving revision 1.23
diff -c -r1.23 pp.el
*** lisp/emacs-lisp/pp.el	28 Jun 2004 23:08:31 -0000	1.23
--- lisp/emacs-lisp/pp.el	28 Jul 2004 23:02:07 -0000
***************
*** 100,106 ****
  instead.  The value is also consed onto the front of the list
  in the variable `values'."
    (interactive "xPp-eval: ")
!   (setq values (cons (eval expression) values))
    (let* ((old-show-function temp-buffer-show-function)
  	 ;; Use this function to display the buffer.
  	 ;; This function either decides not to display it at all
--- 100,106 ----
  instead.  The value is also consed onto the front of the list
  in the variable `values'."
    (interactive "xPp-eval: ")
!   (setq values (setnthcdr 10 (cons (eval expression) values)))
    (let* ((old-show-function temp-buffer-show-function)
  	 ;; Use this function to display the buffer.
  	 ;; This function either decides not to display it at all


-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: space leak from `values'
  2004-07-28 23:13           ` space leak from `values' Kim F. Storm
@ 2004-07-29  7:50             ` Miles Bader
  2004-07-29  8:41               ` Kim F. Storm
  0 siblings, 1 reply; 10+ messages in thread
From: Miles Bader @ 2004-07-29  7:50 UTC (permalink / raw)
  Cc: emacs-devel, Stefan Monnier, Dave Love

storm@cua.dk (Kim F. Storm) writes:
> + DEFUN ("setnthcdr", Fsetnthcdr, Ssetnthcdr, 2, 3, 0,
> +        doc: /* Set cdr of Nth element of LIST to VALUE (nil if omitted), returns the result.

What's wrong with (setcdr (nthcdr (1- N) LIST) VALUE) ?

-Miles
-- 
.Numeric stability is probably not all that important when you're guessing.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: space leak from `values'
  2004-07-29  7:50             ` Miles Bader
@ 2004-07-29  8:41               ` Kim F. Storm
  2004-07-29  8:50                 ` David Kastrup
                                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Kim F. Storm @ 2004-07-29  8:41 UTC (permalink / raw)
  Cc: emacs-devel, Stefan Monnier, Dave Love

Miles Bader <miles@lsi.nec.co.jp> writes:

> storm@cua.dk (Kim F. Storm) writes:
> > + DEFUN ("setnthcdr", Fsetnthcdr, Ssetnthcdr, 2, 3, 0,
> > +        doc: /* Set cdr of Nth element of LIST to VALUE (nil if omitted), returns the result.
> 
> What's wrong with (setcdr (nthcdr (1- N) LIST) VALUE) ?

Read the third line of the doc string:

> If list has less than N elements, do not modify list.

Your suggestion fails if N is less than the length of the list:

(let ((list '(1 2 3 4))
      (n 10)     
      (value nil))
  (setcdr (nthcdr (1- n) list) value))

With (my version of) setnthcdr you replace
    (if (> (length kill-ring) kill-ring-max)
	(setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
by
    (setnthcdr kill-ring-max kill-ring)

And besides, I need this at the C level (but I can of course
write the necessary code in-line).


BTW, my first idea was to call this function `chop' so that (chop N
LIST) would simply truncate LIST to a maximum of N elements -- but
then I realized that setnthcdr with the optional VALUE arg would be
more generic (and potentially more useful).

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: space leak from `values'
  2004-07-29  8:41               ` Kim F. Storm
@ 2004-07-29  8:50                 ` David Kastrup
  2004-07-29  9:06                 ` Miles Bader
  2004-07-30  4:54                 ` Richard Stallman
  2 siblings, 0 replies; 10+ messages in thread
From: David Kastrup @ 2004-07-29  8:50 UTC (permalink / raw)
  Cc: Dave Love, emacs-devel, Stefan Monnier, Miles Bader

storm@cua.dk (Kim F. Storm) writes:

> Miles Bader <miles@lsi.nec.co.jp> writes:
> 
> > storm@cua.dk (Kim F. Storm) writes:
> > > + DEFUN ("setnthcdr", Fsetnthcdr, Ssetnthcdr, 2, 3, 0,
> > > +        doc: /* Set cdr of Nth element of LIST to VALUE (nil if omitted), returns the result.
> > 
> > What's wrong with (setcdr (nthcdr (1- N) LIST) VALUE) ?
> 
> Read the third line of the doc string:
> 
> > If list has less than N elements, do not modify list.
> 
> Your suggestion fails if N is less than the length of the list:
> 
> (let ((list '(1 2 3 4))
>       (n 10)     
>       (value nil))
>   (setcdr (nthcdr (1- n) list) value))
> 
> With (my version of) setnthcdr you replace
>     (if (> (length kill-ring) kill-ring-max)
> 	(setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
> by
>     (setnthcdr kill-ring-max kill-ring)

It must also be noted that length requires a lot of prerequisites:
that the list is not circular, ends with a cons, and so on.  For
example, (length '(3 4 5 . 6)) throws an exception.

One could write this as

(setcdr (or (nthcdr (1- n) list) (cons nil nil)) value)

or as

(let ((tail (nthcdr (1- n) list)))
  (and (consp tail)
       (setcdr tail value)))

or something to avoid the length call, however.

-- 
David Kastrup, Kriemhildstr. 15, 44793 Bochum

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: space leak from `values'
  2004-07-29  8:41               ` Kim F. Storm
  2004-07-29  8:50                 ` David Kastrup
@ 2004-07-29  9:06                 ` Miles Bader
  2004-07-29 12:00                   ` Kim F. Storm
  2004-07-30  4:54                 ` Richard Stallman
  2 siblings, 1 reply; 10+ messages in thread
From: Miles Bader @ 2004-07-29  9:06 UTC (permalink / raw)
  Cc: Dave Love, Stefan Monnier, emacs-devel

storm@cua.dk (Kim F. Storm) writes:
>> What's wrong with (setcdr (nthcdr (1- N) LIST) VALUE) ?
>
> Read the third line of the doc string:
>
>> If list has less than N elements, do not modify list.
>
> Your suggestion fails if N is less than the length of the list:

It's trivial to handle though that -- just see if the result of `nthcdr'
is nil, and only do the `setcdr' if not.  Adding a C function for this
rather rare operation just seems kinda like pointless bloat...

-Miles
-- 
Run away!  Run away!

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: space leak from `values'
  2004-07-29  9:06                 ` Miles Bader
@ 2004-07-29 12:00                   ` Kim F. Storm
  2004-07-30 16:16                     ` Richard Stallman
  0 siblings, 1 reply; 10+ messages in thread
From: Kim F. Storm @ 2004-07-29 12:00 UTC (permalink / raw)
  Cc: Dave Love, Stefan Monnier, emacs-devel

Miles Bader <miles@lsi.nec.co.jp> writes:

> storm@cua.dk (Kim F. Storm) writes:
> >> What's wrong with (setcdr (nthcdr (1- N) LIST) VALUE) ?
> >
> > Read the third line of the doc string:
> >
> >> If list has less than N elements, do not modify list.
> >
> > Your suggestion fails if N is less than the length of the list:
> 
> It's trivial to handle though that -- just see if the result of `nthcdr'
> is nil, and only do the `setcdr' if not.  Adding a C function for this
> rather rare operation just seems kinda like pointless bloat...

Rare ?  Pointless ?

Truncating a list to a specific maximum is quite common if you ask me.

ido.el:    (if (> (length ido-work-directory-list) ido-max-work-directory-list)
ido.el:    (if (> (length ido-work-file-list) ido-max-work-file-list)
ido.el:	  (if (> (length ido-dir-file-cache) ido-max-dir-file-cache)
isearch.el:	    (if (> (length regexp-search-ring) regexp-search-ring-max)
isearch.el:	  (if (> (length search-ring) search-ring-max)
menu-bar.el:  (if (> (length (cdr yank-menu)) kill-ring-max)
menu-bar.el:	     (if (> (length buffers) buffers-menu-max-size)
simple.el:    (if (> (length kill-ring) kill-ring-max)
calc/calc-aent.el:	(when (> (length kill-ring) kill-ring-max)
calendar/calendar.el:          (if (> (length calendar-mark-ring) (1+ mark-ring-max))
emulation/cua-rect.el:    (if (> (length cua--undo-list) cua-undo-max)
emulation/viper-cmd.el:  (if (> (length kill-ring) kill-ring-max)
net/eudc.el:	     (> (length servers) eudc-max-servers-to-query))
progmodes/ada-xref.el:  (if (> (length ada-xref-pos-ring) ada-xref-pos-ring-max)
progmodes/xscheme.el:  (if (> (length xscheme-expressions-ring) xscheme-expressions-ring-max)
textmodes/bibtex.el:      (if (> (length bibtex-field-kill-ring) bibtex-field-kill-ring-max)
textmodes/bibtex.el:      (if (> (length bibtex-entry-kill-ring) bibtex-entry-kill-ring-max)

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: space leak from `values'
  2004-07-29  8:41               ` Kim F. Storm
  2004-07-29  8:50                 ` David Kastrup
  2004-07-29  9:06                 ` Miles Bader
@ 2004-07-30  4:54                 ` Richard Stallman
  2 siblings, 0 replies; 10+ messages in thread
From: Richard Stallman @ 2004-07-30  4:54 UTC (permalink / raw)
  Cc: d.love, emacs-devel, monnier, miles

    And besides, I need this at the C level (but I can of course
    write the necessary code in-line).

Unless we see broader need for this, please do write it in line.
That way we save the hassle of documenting it in the manual, etc.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: space leak from `values'
  2004-07-29 12:00                   ` Kim F. Storm
@ 2004-07-30 16:16                     ` Richard Stallman
  2004-08-20 12:51                       ` Kim F. Storm
  0 siblings, 1 reply; 10+ messages in thread
From: Richard Stallman @ 2004-07-30 16:16 UTC (permalink / raw)
  Cc: emacs-devel, d.love, monnier, miles

I did not realize there were so many places where this was done.
However, (setcdr (or (nthcdr N LIST) (list nil)) nil) is pretty
simple.  I am not sure we need a new function to replace that
even if that is done 20 times in Emacs.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: space leak from `values'
  2004-07-30 16:16                     ` Richard Stallman
@ 2004-08-20 12:51                       ` Kim F. Storm
  2004-08-21 16:49                         ` Richard Stallman
  0 siblings, 1 reply; 10+ messages in thread
From: Kim F. Storm @ 2004-08-20 12:51 UTC (permalink / raw)
  Cc: emacs-devel, d.love, monnier, miles


Referring to my proposal for adding setnthcdr, and the number of
places where a list is currently truncated in the lisp files,

Richard Stallman <rms@gnu.org> writes:

> I did not realize there were so many places where this was done.
> However, (setcdr (or (nthcdr N LIST) (list nil)) nil) is pretty
> simple.  I am not sure we need a new function to replace that
> even if that is done 20 times in Emacs.

Since the only practical use of the "setnthcdr" function is to simply
truncate a list to a specific length, I suggest a new function
truncate-list (to be defined in subr.el):

(defun truncate-list (list n)
  "Truncate list LIST to have a maximum of N elements.
If LIST has less than N element, do nothing."
   (if (setq list (nthcdr (1- n) list))
       (setcdr list nil)))

Using that function is both clearer and more efficient than
how it's done currently.

e.g. instead of

    (setq kill-ring (cons string kill-ring))
    (if (> (length kill-ring) kill-ring-max)
	(setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))

just write

    (truncate-list (setq kill-ring (cons string kill-ring))
                   kill-ring-max)


Also, it is much simpler to document truncate-list than the more
generic setnthcdr.

--
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: space leak from `values'
  2004-08-20 12:51                       ` Kim F. Storm
@ 2004-08-21 16:49                         ` Richard Stallman
  0 siblings, 0 replies; 10+ messages in thread
From: Richard Stallman @ 2004-08-21 16:49 UTC (permalink / raw)
  Cc: miles, d.love, monnier, emacs-devel

I just don't see enough need for truncate-list
to justify the new feature.  The code used now is simple
enough.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2004-08-21 16:49 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <rzqzn5qehby.fsf@albion.dl.ac.uk>
     [not found] ` <E1BoSQg-0001Br-II@fencepost.gnu.org>
     [not found]   ` <rzq3c3eex5r.fsf@albion.dl.ac.uk>
     [not found]     ` <E1Bp9wv-0004v0-Ts@fencepost.gnu.org>
     [not found]       ` <rzqllh4m4yi.fsf@albion.dl.ac.uk>
     [not found]         ` <jwvu0vs9gjz.fsf-monnier+emacs@gnu.org>
2004-07-28 23:13           ` space leak from `values' Kim F. Storm
2004-07-29  7:50             ` Miles Bader
2004-07-29  8:41               ` Kim F. Storm
2004-07-29  8:50                 ` David Kastrup
2004-07-29  9:06                 ` Miles Bader
2004-07-29 12:00                   ` Kim F. Storm
2004-07-30 16:16                     ` Richard Stallman
2004-08-20 12:51                       ` Kim F. Storm
2004-08-21 16:49                         ` Richard Stallman
2004-07-30  4:54                 ` Richard Stallman

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).