all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* optional argument defaults in `cl-defun' vs old way - warning, discrepancy!
@ 2023-10-06  2:30 Emanuel Berg
  2023-10-06  9:36 ` Adam Porter
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Emanuel Berg @ 2023-10-06  2:30 UTC (permalink / raw)
  To: emacs-devel

The other day I said the CL way, as implemented in Elisp in
cl-lib, was superior for setting the defaults for
optional arguments, which is done with `cl-defun', as opposed
to the old way, using `defun' and then `or', `unless', or
`let' with a check for a nil value.

That comment refered to the cl-defun syntax which, by all
means, is more neat and compact. But it turns out, those
methods are not equivalent - check out the code below!

After changing 60 defun to cl-defun, maybe I have to change it
all back since the Elisp way of thinking - where nil means
"unset", i.e. use the default - that was the way I was
thinking when I wrote the code, and it has worked ever since.
And just now I run into an error which brought this all to
my attention.

But in a way the CL way is better even here, since explicit
nil really means nil, so one could use that as an optional
argument value.

But then, how would that mix with other code, evaluating to
nil and then being sent as argument. Is that an unset optional
argument which should get a default value, or is it a
set value, just as an explicit nil, only this time not written
by a programmer, but computed by a program, written by
a programmer?

Bottom line, the Elisp way is preferable since it is
consistent - see the three (1 2) results below, compared to
the CL ditto, with one (1 2) and two (nil nil).

;;; -*- lexical-binding: t -*-
;;
;; this file:
;;   https://dataswamp.org/~incal/emacs-init/geh.el

(require 'cl-lib)

(cl-defun test-opt-args-cl (&optional (one 1) (two 2))
  (interactive (list nil nil))
  (message "%s" (list one two)) )

;; (test-opt-args-cl)                      ; (1 2)
;; (test-opt-args-cl nil nil)              ; (nil nil)
;; (call-interactively #'test-opt-args-cl) ; (nil nil)

(defun test-opt-args (&optional one two)
  (interactive (list nil nil))
  (or one (setq one 1))
  (or two (setq two 2))
  (message "%s" (list one two)) )

;; (test-opt-args)                      ; (1 2)
;; (test-opt-args nil nil)              ; (1 2)
;; (call-interactively #'test-opt-args) ; (1 2)

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: optional argument defaults in `cl-defun' vs old way - warning, discrepancy!
  2023-10-06  2:30 optional argument defaults in `cl-defun' vs old way - warning, discrepancy! Emanuel Berg
@ 2023-10-06  9:36 ` Adam Porter
  2023-10-07 13:01   ` Emanuel Berg
  2023-10-06 13:54 ` [External] : " Drew Adams
  2023-10-06 21:37 ` Richard Stallman
  2 siblings, 1 reply; 6+ messages in thread
From: Adam Porter @ 2023-10-06  9:36 UTC (permalink / raw)
  To: incal; +Cc: emacs-devel

Hi Emanuel,

Yes, this is how CL optional and keyword arguments work.  See (info 
"(cl) Argument Lists") and search for "SVAR".  It does require a bit 
more diligence in some cases, but it also provides more flexibility. 
And FWIW, I think I actually have to check the SVAR something like 1% of 
the time I use CL argument lists, or maybe less.  So that "gotcha" 
rarely "gets you" in practice.  :)

--Adam



^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [External] : optional argument defaults in `cl-defun' vs old way - warning, discrepancy!
  2023-10-06  2:30 optional argument defaults in `cl-defun' vs old way - warning, discrepancy! Emanuel Berg
  2023-10-06  9:36 ` Adam Porter
@ 2023-10-06 13:54 ` Drew Adams
  2023-10-07 13:12   ` Emanuel Berg
  2023-10-06 21:37 ` Richard Stallman
  2 siblings, 1 reply; 6+ messages in thread
From: Drew Adams @ 2023-10-06 13:54 UTC (permalink / raw)
  To: Emanuel Berg, emacs-devel@gnu.org

> After changing 60 defun to cl-defun, maybe I have to change it
> all back since the Elisp way of thinking - where nil means
> "unset", i.e. use the default - that was the way I was
> thinking when I wrote the code, and it has worked ever since.
> And just now I run into an error which brought this all to
> my attention.
> 
> But in a way the CL way is better even here, since explicit
> nil really means nil, so one could use that as an optional
> argument value.
> 
> But then, how would that mix with other code, evaluating to
> nil and then being sent as argument. Is that an unset optional
> argument which should get a default value, or is it a
> set value, just as an explicit nil, only this time not written
> by a programmer, but computed by a program, written by
> a programmer?
> 
> Bottom line, the Elisp way is preferable since it is
> consistent - see the three (1 2) results below, compared to
> the CL ditto, with one (1 2) and two (nil nil).

I think what you really mean to say is that
`&optional foo' can convey something a bit
different to human readers, in terms of intent
than does `&optional (foo nil)`.

That's true.

But I wouldn't call the latter "the CL way" and the
former "the Elisp way".  The real CL way is to let
you use either/both.  From CLTL:

(lambda ({var}*
         [&optional {var | (var [initform [svar]])}*]
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         [&rest var]
         [&key {var | ({var | (keyword var)} [initform [svar]])}*
                [&allow-other-keys]]
         [&aux {var | (var [initform])}*)]
   [[{declaration}* | documentation-string]]
   {form}*)

https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node64.html#SECTION00922000000000000000

E.g., &optional foo (bar nil),
      &optional (bar nil) foo,
      &optional foo (bar foo)

(I'm sure you realize this.  Just a nit about the
labeling as "the XXX way".)

And in fact the hint to humans mentioned above,
that arg presence might make a difference, is
less clear than making the possibility explicit.

As Adam pointed out, with CL you can provide an
SVAR for a VAR that has an explicit INITFORM, to
let both the body code and humans know whether
the optional arg was actually passed.  Just the
presence of an SVAR can give you a heads-up that
presence/absence might actually matter to the
behavior (body).



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: optional argument defaults in `cl-defun' vs old way - warning, discrepancy!
  2023-10-06  2:30 optional argument defaults in `cl-defun' vs old way - warning, discrepancy! Emanuel Berg
  2023-10-06  9:36 ` Adam Porter
  2023-10-06 13:54 ` [External] : " Drew Adams
@ 2023-10-06 21:37 ` Richard Stallman
  2 siblings, 0 replies; 6+ messages in thread
From: Richard Stallman @ 2023-10-06 21:37 UTC (permalink / raw)
  To: Emanuel Berg; +Cc: emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

Please stop arguing on emacs-devel for that change.  The repeated
pressure starts to be annoying.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: optional argument defaults in `cl-defun' vs old way - warning, discrepancy!
  2023-10-06  9:36 ` Adam Porter
@ 2023-10-07 13:01   ` Emanuel Berg
  0 siblings, 0 replies; 6+ messages in thread
From: Emanuel Berg @ 2023-10-07 13:01 UTC (permalink / raw)
  To: emacs-devel

Adam Porter wrote:

> Yes, this is how CL optional and keyword arguments work.
> See (info "(cl) Argument Lists") and search for "SVAR".
> It does require a bit more diligence in some cases, but it
> also provides more flexibility. And FWIW, I think I actually
> have to check the SVAR something like 1% of the time [...]

Okay, but how does one know when that has to be checked?
Because after writing the `cl-defun', certain use which one
didn't plan for, still cannot be allowed to break it. And if
one has to check SVAR for every cl-defun, I don't see the
advantage with the &optional arg default syntax being big
enough to prefer cl-defun to `defun' for the use case of
optional args.

At least with `defun' and &optional, nil always means the
default has to be used - even if nil was submitted explicitely
by a programmer or a program - or rather, that doesn't exist
as a special case so one doesn't have to care about it.

In practice, with defun, it would me to always check if
&optional args ar set, and if not, set each of them to
a default value. But not having to do that with `cl-defun' is
not a clear advantage anymore, since one sometimes (or
always?) has to check SVAR instead.

Note that this, i.e. having to check for nils with defun,
doesn't mean nil can't be used as the default. It would only
amount to

  (or arg (setq arg nil))

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [External] : optional argument defaults in `cl-defun' vs old way - warning, discrepancy!
  2023-10-06 13:54 ` [External] : " Drew Adams
@ 2023-10-07 13:12   ` Emanuel Berg
  0 siblings, 0 replies; 6+ messages in thread
From: Emanuel Berg @ 2023-10-07 13:12 UTC (permalink / raw)
  To: emacs-devel

Drew Adams wrote:

> I think what you really mean to say is that `&optional foo'
> can convey something a bit different to human readers, in
> terms of intent than does `&optional (foo nil)`.
>
> That's true.
>
> But I wouldn't call the latter "the CL way" and the former
> "the Elisp way". The real CL way is to let you use
> either/both.

Call it the `defun' way vs the `cl-defun' way then.

I used to perceive the situation like this:

- with defun you have to always check the optional args for
  nil and, if so, set them to a default value

- with cl-defun, you don't have to do that because you can
  use the syntax to do that

However now it turns out that syntax isn't equivalent to the
defun way, so sometimes you have to check for SVAR.

So the advantages with cl-defun in this case - i.e.
optional args - which was a more compact syntax - is dubious
since it is not exhaustive, and sometimes (when?) you have to
check for SVAR. So defun is more clear (nil always means use
the default) and you also always have to check and set this,
compared to cl-defun when you sometimes has to do something
and you have to actively figure out when.

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-10-07 13:12 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-06  2:30 optional argument defaults in `cl-defun' vs old way - warning, discrepancy! Emanuel Berg
2023-10-06  9:36 ` Adam Porter
2023-10-07 13:01   ` Emanuel Berg
2023-10-06 13:54 ` [External] : " Drew Adams
2023-10-07 13:12   ` Emanuel Berg
2023-10-06 21:37 ` Richard Stallman

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.