emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [External] : Re: cond* vs pcase


From: Arthur Miller
Subject: Re: [External] : Re: cond* vs pcase
Date: Wed, 07 Feb 2024 14:14:41 +0100
User-agent: Gnus/5.13 (Gnus v5.13)

Drew Adams <drew.adams@oracle.com> writes:

>>    (pcase foo
>>      ('bar (do-some-bar-stuff))
>>      ('baz (do-some-baz-fluff)))
>> 
>> is not more awful or wonderful than:
>> 
>>    (cl-case foo
>>      (bar (do-some-bar-stuff))
>>      (baz (do-some-baz-fluff)))
>
> Exactly.  The difference is tiny when the
> two are, uh, doing the same thing.
>
> When `pcase' is used only to do what
> `cl-case' is designed for, it doesn't
> proclaim immediately to readers that
> that's all it's doing.
> ___
>
> However, our doc actually claims that a
> `pcase' version of a similar example is
> _superior_ to `cl-case' (not just-as-good).
>
> https://debbugs.gnu.org/cgi/bugreport.cgi?bug=68029
>
>  "This shows that you do need to use a `code'
>   variable (you named it `val' though), and
>   that the pcase version is indeed better."
>
> (The `pcase' example actually uses _more_
> variables than the `cl-case' example, in
> spite of the doc claiming that it's better
> because it uses fewer.)
>
> If our doc and a maintainer can mistakenly
> think `cl-case' is required to bind more
> vars in such an example, then imagine how
> mixed up a reader might be.
>
> The point about using `cl-case' (or `cond'
> or whatever else) in particular cases (vs
> rather, using `pcase' in other cases) is
> that doing so conveys the info that we're
> talking about a simple or a not-so-simple
> case.
>
> If you use `pcase' for something for which
> `cl-case' easily suffices, that can be less
> clear than reserving `pcase' for heavier
> lifting (when it's really needed).
>
> Using them both, each for what it can offer,
> can elucidate just what work is involved.
>
>> And neither of them is worse than what they expand to:
>>    (cond ((eql foo 'bar)
>>           (do-some-bar-stuff))
>>          ((eql foo 'baz)
>>           (do-some-baz-fluff)))
>> 
>> Nor is this:
>>    (pcase foo
>>      (1 'ONE)
>>      (2 'TWO)
>>      ((cl-type function) (funcall foo))
>>      (_ 'SOMETHING-ELSE))
>> 
>> any worse than what it expands to:
>>    (cond ((eql foo 1)
>>           'ONE)
>>          ((eql foo 2)
>>           'TWO)
>>          ((cl-typep foo 'function)
>>           (funcall foo))
>>          (t
>>           'SOMETHING-ELSE))
>
> Of course.  Did someone argue that `pcase'
> doesn't compile or macroexpand to efficient
> code?
>
> It's a style/messaging question.  Using
> `pcase' for what `cl-case' can't do easily
> and clearly can then say, "This here ain't
> a straightforward `cl-case' thing."
>
> You don't have to adopt such a convention.
> But you can.  Then when your readers see
> `pcase' they'll pay attention, looking for
> what _particularly called for_ using it.
>
>>    (pcase foo
>>      (1 'ONE)
>>      (2 'TWO)
>>      ((cl-type function) (funcall foo))
>>      (`(,fn . ,arg) (funcall fn arg))
>>      (_ 'SOMETHING-ELSE))
>> 
>> I cannot fathom how this optionally available
>> "power" is a problem which should consign PCASE
>> to only exceptional cases
>
> No one suggested that.  Saying that it can
> help to use `cl-case' when it perfectly fits
> the bill is not the same as saying that one
> should always use `cl-case'.
>
> The argument is against always using `pcase';
> it's not for always using `cl-case' (or `cond'
> or...).
>
> Use each for what it can do well/better.  And
> yes, it's only about coding style; it's not
> about performance differences.  (Maybe ask
> yourself why you'd think the question is about
> performance?)
>   
>> any more than Lisp's
>> power should consign it to only a few libraries, leaving the rest to be
>> implemented in lower-level languages; or any more than Emacs's power
>> should consign it to only a few use cases, leaving the the rest to be
>> implemented in utilities to be piped together in a shell.
>
> That's precisely the point.  One size might
> stretch to fit all, but it's not necessarily
> the best fit for everything.
>
> Don't use a jackhammer to drive in a carpet
> tack, if you have a tack hammer in your tool
> belt.  (But sure, you can always use the
> jackhammer if you really want.)

I think it is more important to be consistent and choose one form than many
different if possible. This is a discussion like should I choose setq vs setf.

I would agree with Norvig, check his guite to Lisp style from the PAIP book:

https://norvig.github.io/paip-lisp/#/chapter3?id=_31-a-guide-to-lisp-style

Prefering pcase over cl-case, mean you have one place to lookup the
documentation, one "special form" to learn, and so for your users too. A flora
and fauna of forms that do the very similar but slightly different is a *-case
for future bugs and problems.

I would be happy if we had only "let" with the powers of "let*" "set" with the
powers of "setf", "case" with the powers of "pcase" and so on.

Similar for del* and mem* funcitons. They are parametrized over comparison
operator, (memq, memql, member for example). It would be much better to have one
function that let us pass in comparison operator, say like this:

    (member element list &optional test-function)

I would prefer it as a keyword argument so the API is similar to hashmap to be
more consistent. Similar for delete.

I understand those came historically, either as people discovered the
usefullness of them, or because the computers from the past where not powerful
enough so choosing one that cost least in terms of CPU or RAM resources was an
neccessity. But today, I think it is more of peep-hole optimizing. I think Paul
Graham is correct when he praises high-level "rapid-prototyping" features of
Lisp (I guess he wrote it before the term "agile programming" become popular):

https://sep.turbifycdn.com/ty/cdn/paulgraham/acl1.txt?t=1688221954&;

"Signalling" something to someone by carefully crafting use of cl-case vs. pcase
sounds like a lot of cognitive load on all involved parties for very little
benefit. You are basically saying that we should use a high-level construct that
helps us structure our programs according to their implementation not for their
higher-level feature of singaling intention of our code.

As Adam point out; pcase let you specify the comparison function, is definitely
better than if we had some hypothetical caseq, caseql and case-equal.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]