unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
From: "Neil Jerram" <neiljerram@googlemail.com>
To: "Ludovic Courtès" <ludo@gnu.org>
Cc: guile-devel@gnu.org
Subject: Re: [PATCH] Avoid `SCM_VALIDATE_LIST ()'
Date: Mon, 1 Sep 2008 23:09:01 +0200	[thread overview]
Message-ID: <49dd78620809011409w8902d24q5734da921d6dfbff@mail.gmail.com> (raw)
In-Reply-To: <87hc90u9lb.fsf@gnu.org>

2008/9/1 Ludovic Courtès <ludo@gnu.org>:
> Hello,
>
> This is a followup to this discussion:
>
>  http://thread.gmane.org/gmane.lisp.guile.devel/7194
>
> The attached patch changes several list-related functions

reverse!, memq, memv, member, filter, filter!
SRFI-1: concatenate, concatenate!, member, remove, remove!

> so that they
> don't validate their input with `SCM_VALIDATE_LIST ()' since it's O(n).

I'm afraid I don't get your rationale, because all these functions are
O(n) anyway.  (For reverse*, filter* and concatenate* I believe this
is obvious.  For mem* and remove*, they should always be O(n) in
practice because it would be stupid to design a list structure where
the element being looked for or removed was not equally likely to be
anywhere along the list.)

I know you gave an example in the above-referenced thread, but IMO
that was a pathological one.  Did you find the use of
SCM_VALIDATE_LIST () causing a problem in real practical code?

> A side-effect (besides performance improvements) is that all these
> functions will now happily traverse circular lists, and will silently
> deal with dotted lists.  This is acceptable behavior IMO.

Are you sure about traversing circular lists?  From my reading of your
patch, I would expect:

(memq 'not-in-the-list some-circular-list)
=>
(don't know, still waiting...)

:-)

What do reverse* do on a circular list?  What do concatenate* do?

There are a few more specific comments below, but on balance, at the
moment, I'm seeing more disadvantages here than benefit...

Regards,
          Neil

> diff --git a/NEWS b/NEWS
> index c2bed17..cfcd43b 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -56,6 +56,13 @@ When you use GDS to evaluate Scheme code from Emacs, you can now use
>  This makes these internal functions technically not callable from
>  application code.
>
> +** Remove argument type checking with `list?' in some list-related functions

It's easy to read that as just "Remove argument type checking".  Could
we say "Improve scalability of some list-related functions" instead,
and leave the type checking detail to the following para?

> +
> +Several list-related functions (e.g., `memq', `list-copy', etc.) used
> +R5RS `list?' to validate their arguments.  However, `list?' has linear
> +complexity, so these functions have been changed to not resort to
> +`list?'.
> +
>  ** `guile-config link' now prints `-L$libdir' before `-lguile'
>  ** Fix memory corruption involving GOOPS' `class-redefinition'
>  ** Fix build issue on Tru64 and ia64-hp-hpux11.23 (`SCM_UNPACK' macro)
> diff --git a/libguile/list.c b/libguile/list.c
> index a1a79a4..8b0a2e4 100644
> --- a/libguile/list.c
> +++ b/libguile/list.c
> @@ -1,4 +1,4 @@
> -/* Copyright (C) 1995,1996,1997,2000,2001,2003,2004
> +/* Copyright (C) 1995,1996,1997,2000,2001,2003,2004,2008
>   * Free Software Foundation, Inc.
>   *
>   * This library is free software; you can redistribute it and/or
> @@ -367,15 +367,19 @@ SCM_DEFINE (scm_reverse_x, "reverse!", 1, 1, 0,
>  	    "@code{reverse!}")
>  #define FUNC_NAME s_scm_reverse_x
>  {
> -  SCM_VALIDATE_LIST (1, lst);
>    if (SCM_UNBNDP (new_tail))
>      new_tail = SCM_EOL;
>    else
> -    SCM_VALIDATE_LIST (2, new_tail);
> +    SCM_ASSERT (scm_is_pair (new_tail) || SCM_NULL_OR_NIL_P (new_tail),
> +		new_tail, 2, FUNC_NAME);

Why does new_tail need to satisfy this condition?  Please either add a
comment to explain, or just remove.

>    while (!SCM_NULL_OR_NIL_P (lst))
>      {
> -      SCM old_tail = SCM_CDR (lst);
> +      SCM old_tail;
> +
> +      SCM_VALIDATE_CONS (1, lst);
> +
> +      old_tail = SCM_CDR (lst);
>        SCM_SETCDR (lst, new_tail);
>        new_tail = lst;
>        lst = old_tail;

Note that if SCM_VALIDATE_CONS fails half way through the "list", the
input list will have been destructively modified such that it is
neither the same as when it started, nor a complete reversed list.  Is
that a concern?

> @@ -546,7 +550,8 @@ SCM_DEFINE (scm_list_copy, "list-copy", 1, 0, 0,
>    SCM * fill_here;
>    SCM from_here;
>
> -  SCM_VALIDATE_LIST (1, lst);
> +  SCM_ASSERT (scm_is_pair (lst) || SCM_NULL_OR_NIL_P (lst),
> +	      lst, 1, FUNC_NAME);

Why impose this condition specifically on the head of the provided
list?  Please either explain or remove.

>
>    newlst = SCM_EOL;
>    fill_here = &newlst;
> @@ -613,8 +618,13 @@ SCM_DEFINE (scm_memq, "memq", 2, 0, 0,
>  	    "returned.")
>  #define FUNC_NAME s_scm_memq
>  {
> -  SCM_VALIDATE_LIST (2, lst);
> -  return scm_c_memq (x, lst);
> +  for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
> +    {
> +      SCM_VALIDATE_CONS (2, lst);
> +      if (scm_is_eq (SCM_CAR (lst), x))
> +	return lst;
> +    }
> +  return SCM_BOOL_F;
>  }
>  #undef FUNC_NAME
>
> @@ -629,9 +639,9 @@ SCM_DEFINE (scm_memv, "memv", 2, 0, 0,
>  	    "returned.")
>  #define FUNC_NAME s_scm_memv
>  {
> -  SCM_VALIDATE_LIST (2, lst);
>    for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
>      {
> +      SCM_VALIDATE_CONS (2, lst);
>        if (! scm_is_false (scm_eqv_p (SCM_CAR (lst), x)))
>  	return lst;
>      }
> @@ -650,9 +660,9 @@ SCM_DEFINE (scm_member, "member", 2, 0, 0,
>  	    "empty list) is returned.")
>  #define FUNC_NAME s_scm_member
>  {
> -  SCM_VALIDATE_LIST (2, lst);
>    for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
>      {
> +      SCM_VALIDATE_CONS (2, lst);
>        if (! scm_is_false (scm_equal_p (SCM_CAR (lst), x)))
>  	return lst;
>      }
> @@ -884,9 +894,11 @@ SCM_DEFINE (scm_filter, "filter", 2, 0, 0,
>    SCM walk;
>    SCM *prev;
>    SCM res = SCM_EOL;
> +
>    SCM_ASSERT (call, pred, 1, FUNC_NAME);
> -  SCM_VALIDATE_LIST (2, list);
> -
> +  SCM_ASSERT (scm_is_pair (list) || SCM_NULL_OR_NIL_P (list),
> +	      list, 2, FUNC_NAME);

Same comment as above.

> +
>    for (prev = &res, walk = list;
>         scm_is_pair (walk);
>         walk = SCM_CDR (walk))
> @@ -910,9 +922,11 @@ SCM_DEFINE (scm_filter_x, "filter!", 2, 0, 0,
>    scm_t_trampoline_1 call = scm_trampoline_1 (pred);
>    SCM walk;
>    SCM *prev;
> +
>    SCM_ASSERT (call, pred, 1, FUNC_NAME);
> -  SCM_VALIDATE_LIST (2, list);
> -
> +  SCM_ASSERT (scm_is_pair (list) || SCM_NULL_OR_NIL_P (list),
> +	      list, 2, FUNC_NAME);

Same comment as above.

> +
>    for (prev = &list, walk = list;
>         scm_is_pair (walk);
>         walk = SCM_CDR (walk))




  parent reply	other threads:[~2008-09-01 21:09 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-08-31 22:02 [PATCH] Avoid `SCM_VALIDATE_LIST ()' Ludovic Courtès
2008-09-01  0:12 ` Han-Wen Nienhuys
2008-09-01 20:19   ` Neil Jerram
2008-09-01 20:30   ` Ludovic Courtès
2008-09-02  2:40     ` Han-Wen Nienhuys
2008-09-06 22:23       ` Neil Jerram
2008-09-06 21:36     ` Neil Jerram
2008-09-07  4:23     ` Ken Raeburn
2008-09-07 15:24       ` Neil Jerram
2008-09-07 17:30         ` Ken Raeburn
2008-09-07 19:21           ` Neil Jerram
2008-09-08 23:11         ` Neil Jerram
2008-09-09  8:28           ` Ludovic Courtès
2008-09-10 20:43             ` Neil Jerram
2008-09-04 18:24   ` Andy Wingo
2008-09-05  0:10     ` Han-Wen Nienhuys
2008-09-05  1:06       ` Andy Wingo
2008-09-06 22:45         ` Neil Jerram
2008-09-07  2:33           ` Han-Wen Nienhuys
2008-09-07 13:38             ` Neil Jerram
2008-09-07 15:00               ` Han-Wen Nienhuys
2008-09-07 16:19                 ` Neil Jerram
2008-09-07 19:25                   ` Han-Wen Nienhuys
2008-09-07 14:05             ` Andy Wingo
2008-09-07 15:38               ` development goals (was: [PATCH] Avoid `SCM_VALIDATE_LIST ()') Han-Wen Nienhuys
2008-09-07 20:03                 ` Neil Jerram
2008-09-08  4:28                   ` development goals Han-Wen Nienhuys
2008-09-08 10:16                     ` Ludovic Courtès
2008-09-08 13:57                       ` Han-Wen Nienhuys
2008-09-09  7:08                       ` Andy Wingo
2008-09-08 10:27                   ` Ludovic Courtès
2008-09-06 22:40     ` [PATCH] Avoid `SCM_VALIDATE_LIST ()' Neil Jerram
2008-09-01 21:09 ` Neil Jerram [this message]
2008-09-01 21:47   ` Ludovic Courtès
2008-09-06 22:15     ` Neil Jerram
2008-09-08  9:40       ` Ludovic Courtès
2008-09-06 23:11     ` Mikael Djurfeldt
2008-09-07  2:43       ` Han-Wen Nienhuys
2008-09-07 15:04         ` Neil Jerram
2008-09-07 13:32       ` Neil Jerram
2008-09-02  2:44   ` Han-Wen Nienhuys
2008-09-06 22:32     ` Neil Jerram
2008-09-08  3:13       ` Han-Wen Nienhuys
2008-09-08  4:42         ` Clinton Ebadi
2008-09-08  9:47           ` Ludovic Courtès

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=49dd78620809011409w8902d24q5734da921d6dfbff@mail.gmail.com \
    --to=neiljerram@googlemail.com \
    --cc=guile-devel@gnu.org \
    --cc=ludo@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).