emacs-devel
[Top][All Lists]
Advanced

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

Re: defcustom keyword :require


From: Stefan Monnier
Subject: Re: defcustom keyword :require
Date: Fri, 31 Aug 2018 13:35:02 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux)

FWIW, I also dislike this option.


        Stefan


Drew Adams <address@hidden> writes:

> `defcustom' keyword `:require' has the effect of invoking `require'
> for the defining library whenever `custom-set-variables' sets the
> option value.  The `require' is invoked before setting the option.
>
> This can be bothersome when a `custom-set-variables' sexp is inserted
> automatically in an init file or `custom-file' by an Emacs session
> where the option is defined, and the init file or `custom-file' is
> subsequently used by an Emacs session where that library is not
> available (e.g., cannot or should not be available).  A user might not
> want Emacs to raise an error in such a case.
>
> Example in Emacs 26.1: I save bookmarks, some of which are to remote
> files.  This causes my `custom-set-variables' to be updated to include
> the following entries, because (only for Emacs 26.1) the defcustoms
> for `tramp-default-method' and `tramp-verbose' use `:require 'tramp':
>
>  '(tramp-default-method "ftp" nil (tramp)) ; Require Tramp first
>  '(tramp-verbose 9 nil (tramp))            ; Require Tramp first
>
> Prior to and after Emacs 26.1 those entries are just the following, so
> no attempt is made to load Tramp when processing the
> `custom-set-variables':
>
>  '(tramp-default-method "ftp")
>  '(tramp-verbose 9)
>
> Using an Emacs release that does not include Tramp aborts
> initialization when it encounters the requirement to load Tramp.  So
> in a session with an old Emacs release those require-Tramp settings
> can raise this error:
>
> Signaling: (file-error "Cannot open load file" "tramp")
>   require(tramp)
>   mapcar(require (tramp))
>   custom-set-variables(...)
>
> The option setting hard-requires Tramp. It would be OK here if the
> meaning of the REQUEST part of the `custom-set-variables' settings
> were to just soft-require the library, i.e., if the REQUEST arg meant
> (require 'tramp nil t) instead of (require 'tramp).
>
> OK, the Tramp example is problematic only for quite old Emacs releases
> - but the point is general.
>
> FWIW, this is how I now work around the problem in my init file, but
> it is not a good solution (better solutions are welcome):
>
>  (unless (require 'tramp nil t) (provide 'tramp))
>  (load-file custom-file) ; Load only after faking providing Tramp
>
> For Emacs 26.2 and later I guess either it was realized that Tramp
> need not really be loaded prior to setting these options or some
> change was made to the Tramp code to obviate the load.
>
> The rationale given in the Elisp manual for :require is this:
>
>   The most common reason to use `:require' is when a variable enables
>   a feature such as a minor mode, and just setting the variable won't
>   have any effect unless the code which implements the mode is
>   loaded.
>
> Seems like that common reason doesn't really call for a hard require
> in general - a soft require might be sufficient.  The customized value
> would not have the desired effect perhaps, but the world would not
> end.
>
> We already point out, for `define-minor-mode', that "Except in unusual
> circumstances" the mode variable "must" be initialized to `nil':
>
>   The initial value must be `nil' except in cases where (1) the mode
>   is preloaded in Emacs, or (2) it is painless for loading to enable
>   the mode even though the user did not request it.  For instance, if
>   the mode has no effect unless something else is enabled, and will
>   always be loaded by that time, enabling it by default is harmless.
>   But these are unusual circumstances.  Normally, the initial value
>   must be `nil'.
>
> The Elisp manual also says this about :require (in node `Defining
> Minor Modes'):
>
>   One of the effects of making a minor mode global is that the MODE
>   variable becomes a customization variable.  Toggling it through the
>   Customize interface turns the mode on and off, and its value can be
>   saved for future Emacs sessions (see (emacs)Saving Customizations).
>   For the saved variable to work, you should ensure that the
>   `define-minor-mode' form is evaluated each time Emacs starts; for
>   packages that are not part of Emacs, the easiest way to do this is
>   to specify a `:require' keyword.
>
> This also suggests that (1) :require is for minor-mode MODE variables,
> and (2) it is for packages that are not part of Emacs.  Those things
> are not made clear in the part of the manual where :require is
> introduced, which is maybe why those Tramp variables obtained :require
> for Emacs 26.1.  The description of :require should probably make
> clear that its intended use is particularly narrow.
>
> Are there other, UNcommon reasons to use defcustom keyword :require?
>
> If `custom-set-variables' raises an error for this in an init file it
> stops everything.  In such a case (the common use case for :require)
> wouldn't a warning be more appropriate?
>
> Shouldn't :require really lead to a soft require and a warning, not a
> hard require and an error?  Or should we perhaps add a :soft-require
> keyword and promote its use (generally) over the use of :require?
>
> Should the doc also point out this potential problem with (hard)
> :require?  Should it tell `defcustom' writers that user customization
> when using an Emacs session where the option exists will lead to
> failure-to-launch in a session where the option's library is not
> available?
>
> FWIW, I have never run into this problem before - probably because (1)
> few defcustoms actually use :require and (2) I always have the library
> available, for any that do use :require.
>
> Seems like defcustom :require doesn't really fit too well with
> automatic writing of `custom-set-variables' to a user's init file or
> `custom-file' (the most common use of `custom-set-variables'.  That
> code is typically used for Emacs sessions of all kinds (e.g. different
> releases, different contexts).
>
> Maybe soft-requiring can handle its most common use cases?  Maybe
> issuing a warning instead of erroring-out is generally more
> appropriate?
>
> And perhaps there could be a user option that lets you override
> :require, to make it act always like :soft-require?  That is, even if
> a library chooses (hard) :require, maybe users need a way to override
> that.
>
> What do you think?  I expect that few have actually run into this
> problem, but I also expect that that is only because of the reasons
> stated above: (1) :require is seldom used and (2) libraries that use
> it are typically available across Emacs sessions.  (Most users
> probably use only one Emacs release and use it with the same context
> for each session.)




reply via email to

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