help-gnu-emacs
[Top][All Lists]
Advanced

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

Need help with defcustom keywords


From: mbork
Subject: Need help with defcustom keywords
Date: Thu, 08 May 2025 05:56:55 +0200

Hi all,

I need to set up a user option (with `defcustom') so that setting it
(via `setopt' or the Customize UI) will trigger some Elisp code.  I am
looking at the manual and I don't think I understand the difference
between :set and :initialize well.

Do I get it right that the function set in :set is called whenever the
value of the option changes (for example, with `setopt' or the Customize
UI) and the function set in :initialize is called when evaluating
`defcustom' but not when setting the variable with `setopt' or the UI?

I performed a simple experiment:

--8<---------------cut here---------------start------------->8---
(defcustom experimental-user-option 1337 "Experimental user option"
  :set (lambda (symbol value)
         (message ":set was called")
         (set-default-toplevel-value symbol value))
  :initialize (lambda (symbol value)
                (message ":initialize was called")
                (custom-initialize-reset symbol value)))

(setopt experimental-user-option 42)
--8<---------------cut here---------------end--------------->8---

and the results are a bit mysterious to me.  When I evaluate the
`setopt', only :set is called (as expected).  But when I evaluate the
`defcustom' /for the first time/, :initialize is called first and then
:set.  When I evaluate the `defcustom' again, I can see that first :set
is called, then :initialize, and then :set again.  I understand that
:initialize calls `custom-initialize-reset' which calls the :set
function, but why is :set called first?

I think I understand the use-case of :set (for an example, see below),
but what is the point of :initialize?  Why is it needed?

Another problem I have is with the :get keyword.  The manual says "You
have to really understand the workings of Customize to use ‘:get’
correctly", which is sort of scary.  Here is my use-case.  The option
I need to define is going to be a timestamp, and I want the user to set
it as an ISO-8601 string, but I prefer it to be stored as a number of
seconds since the epoch.  I can see three ways of doing this.

1. Just store the ISO timestamp and convert to Unix time every time my
code uses the option.  This wastes cycles (the conversion will be called
very often) and I want to avoid that.

2. Store the ISO timestamp and use :set to store the Unix time in some
internal variable.  Simple and no need to use :get.

3. Only store the Unix time, using :set to convert iso->unix and :get to
convert back (so that when the user uses the Customize UI, they will see
the ISO timestamp, which is way more convenient than Unix time).  If not
for that scary sentence, I would consider this the best option.  Am
I right?

TIA,

-- 
Marcin Borkowski
https://mbork.pl
https://crimsonelevendelightpetrichor.net/



reply via email to

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