From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Drew Adams Newsgroups: gmane.emacs.devel Subject: defcustom keyword :require Date: Fri, 31 Aug 2018 10:09:51 -0700 (PDT) Message-ID: <7b2c2497-f93d-4415-905d-e2e4370086f7@default> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable X-Trace: blaine.gmane.org 1535736192 22026 195.159.176.226 (31 Aug 2018 17:23:12 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Fri, 31 Aug 2018 17:23:12 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Fri Aug 31 19:23:08 2018 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1fvn8T-0005Yt-6q for ged-emacs-devel@m.gmane.org; Fri, 31 Aug 2018 19:23:05 +0200 Original-Received: from localhost ([::1]:55378 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fvnAZ-0007Fs-86 for ged-emacs-devel@m.gmane.org; Fri, 31 Aug 2018 13:25:15 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:55866) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fvnAF-0006s0-3T for emacs-devel@gnu.org; Fri, 31 Aug 2018 13:25:00 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fvmvk-0005zN-FA for emacs-devel@gnu.org; Fri, 31 Aug 2018 13:09:59 -0400 Original-Received: from aserp2120.oracle.com ([141.146.126.78]:38964) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fvmvk-0005zB-6d for emacs-devel@gnu.org; Fri, 31 Aug 2018 13:09:56 -0400 Original-Received: from pps.filterd (aserp2120.oracle.com [127.0.0.1]) by aserp2120.oracle.com (8.16.0.22/8.16.0.22) with SMTP id w7VH9TC6026807 for ; Fri, 31 Aug 2018 17:09:54 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=mime-version : message-id : date : from : sender : to : subject : content-type : content-transfer-encoding; s=corp-2018-07-02; bh=SC68h3CGu8XdS71MdmecJFSwJnIrMDHZ+8OP9StZRhI=; b=CIGfha0b6+donsJDL0sDSGRfIPQSfBLzfJmN1QQbQwvO6TYn8xNd1cHoI3RAZ5pJTpjS qgKkfIPBwGxy8+io/Cy+6vNxbX4RhPBvPZnUajx+T3BQ4yWBKO8Wi0LSGO1Kld8MZKCn hWkPh4TZHwDWBXy2owcGlG77ijP+z3tMuqRx1r+4GEgwqyO+tHGKTQBcgEy5k5J5nzzg S1DKuM6JraZ3p67UZzWyHKTGLZJ7qrSBx0TsyFzXcyia5zWkWgo3IlWLZB78O+h3LPVw OwfiKl63NqP0hI/fIQf5f2cuacA8ZgZWSzmUHv6Kv96+wZUH8ybIdOKt/Vp3lCBi0Kqr hA== Original-Received: from userv0021.oracle.com (userv0021.oracle.com [156.151.31.71]) by aserp2120.oracle.com with ESMTP id 2m2y2q4m1q-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 31 Aug 2018 17:09:53 +0000 Original-Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by userv0021.oracle.com (8.14.4/8.14.4) with ESMTP id w7VH9qsV023385 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 31 Aug 2018 17:09:53 GMT Original-Received: from abhmp0009.oracle.com (abhmp0009.oracle.com [141.146.116.15]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id w7VH9qFk013806 for ; Fri, 31 Aug 2018 17:09:52 GMT X-Priority: 3 X-Mailer: Oracle Beehive Extensions for Outlook 2.0.1.9.1 (1003210) [OL 16.0.4732.0 (x86)] X-Proofpoint-Virus-Version: vendor=nai engine=5900 definitions=9001 signatures=668708 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=1 malwarescore=0 phishscore=0 bulkscore=0 spamscore=0 mlxscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1807170000 definitions=main-1808310174 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] X-Received-From: 141.146.126.78 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:229141 Archived-At: `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.)