Subject: bug#56521: Add 'take' list operation [PATCH]

From: Mattias Engdegård <[email-masked]>
Date: Wed, 13 Jul 2022 15:18:41 +0200

13 juli 2022 kl. 00.51 skrev Lars Ingebrigtsen <[email-masked]>:

> I'm not against adding this, but I'm not sure of the utility.  That is,
> if you have performance critical code, you don't use `take', because it
> generates much garbage -- instead you loop over a list, taking the
> elements a few at a time explicitly.  And if you don't have performance
> critical code, then why not use `seq-take'?

Thank you, but it is definitely not the case that performance is either of utmost importance or not at all. In fact, most code falls between those extremes. In particular, for elaborate packages such as Magit, Org, Calc, the byte compiler, many programming modes etc, managing complexity and correctness matter most but performance isn't unimportant.

Another way of looking at it is that we add `take` for convenience, and implement it in C for performance.

And don't underestimate the utility of `take` itself -- it's far from always possible or desired to do immediate work on the extracted prefix. I keep seeing it reimplemented (badly) and have done so several times myself (also badly).

It's also useful in conjunction with drop (nthcdr) since (append (take N L) (drop N L)) = L for all N and L.
For example, (take N (drop M L)) returns a sublist; (append (take N L) (drop M L)) removes a sublist. The primitives are easy to reason about.

> But as you
> say, the Lisp version of ntake may well be faster than the C version, so
> perhaps just stick it in subr.el instead?

After a more careful look, that anomaly was probably just a measurement fluke. On the whole the C implementation is reliably faster, although naturally the difference isn't nearly as big as for `take`.

> But I'm not sure about the `ntake' name.

It follows an established convention and makes it easy for the user to see the relationship with `take` as well as understand how they differ.
(We have practically no list primitive starting with 'list-'; those are commands that list something.)

If you prefer we could name it `destructive-take` or `take-destructively` but these are annoyingly long, lack precedence, and are not really better.

Attached is a more complete patch, now with tests and documentation updates.