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))
next prev 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).