Paul Sexton <
psext...@gmail.com> writes:
> Some interesting stats:
> 52 packages export 'once-only'
> 108 packages export 'with-gensyms'
> 64 packages export 'flatten'.
>
> I will post the code later.
Now, either you load all the systems and these duplications are a
possibly a problem, or you don't load all of them, but only the
required dependencies, and then these duplications mean that you prune
short the dependency branch.
That is, it is often worth copy-and-pasting a few small utility
functions in a system, to avoid a dependency to a big library.
And even if we load all the systems, we may want to have some
duplication. Eg. I'd imagine in a Lisp Machine that some duplication of
utility function may occur between "system" layers and "user" layers,
so that the user may freely patch and redefined the user version without
impacting the system version.
There's also the question of the specification of library routines.
Take for example nreconc (it occured to me in a real program so it's not
hypothetical):
nreconc reverses the order of elements in list (as if by
nreverse). It then appends (as if by nconc) the tail to that
reversed list and returns the result.
nreconc works like nreverse:
For nreverse, sequence might be destroyed and re-used to produce the
result. The result might or might not be identical to
sequence. Specifically, when sequence is a list, nreverse is
permitted to setf any part, car or cdr, of any cons that is part of
the list structure of sequence.
and nreverse gives no guarantee on how the cons cells are reused.
Therefore nreconc doesn't either.
Now even if nreconc is implemented as you'd expect it to be implemented,
ie.:
(defun nreconc (list tail)
(do ((1st (cdr list) (if (atom 1st) 1st (cdr 1st)))
(2nd list 1st)
(3rd tail 2nd))
((atom 2nd) 3rd)
(rplacd 2nd 3rd)))
you would still have to duplicate this code in your library if you
required this behavior with respect to the cons cells. (That's the
problem with documenting functions: you cannot rely on the code anymore,
the documentation specifies the contract). But the point is that some
code duplication may be due to the fact that the different copies
promise different contracts, even if they have the same name or even the
same implementation (and let's not even consider performance).
Also, duplication of functions (foremost such "utility" functions), may
denote a duplication of library, but can we really reduce or merge
libraries? There are the problems of sets of utility provided (do we
have even one library that's a strict subset of another?), and of
licensing. It would be useless to go fetch a function in another
library (thus adding a new dependency), if we cannot free ourself from
the dependency of the original library: this would just add a new
dependency. A body of code B depending on a library L may depend to a
set of functions that is not a subset of the functions provided by any
other library. Therefore it not be easy to just replace one library by
another.
But your statistics are quite interesting, and there's probably
something to be done here. But we cannot blindly remove those
duplicates and add dependencies. We'd have to color the dependency
graph by license. (see
http://fossil.nasium-lse.ogamita.com/nasium-lse/artifact/ca229c462dcf420c4497020b3d4b795f0c0e4efb
for some code collecting the licenses from asdf systems). We'd have to
compare the various occurences of the "same" function or macro: are they
really identical (eg. my own with-gensyms is different from the
"canonical" one), or do they have specification or efficiency
differences (cf. nreconc)?