Subject: bug#26910: 26.0.50; Enhancement request: type-checking in customize-set-variable

From: Drew Adams <[email-masked]>
Date: Sat, 13 May 2017 10:50:44 -0700 (PDT)

> I request the addition of an optional argument to
> customize-set-variable, so that, e.g.,
> (customize-set-variable OPTION VALUE "This is a comment." t)
> generates an error if VALUE is not of the type specified by
> (defcustom OPTION ...),

+1

Should it raise an error or just show a message and be ignored
(not set the value)?

How about having the new optional argument specify the behavior?

Non-nil means type-check.  The particular non-nil value:

 * `no-error' means if type-check fails just show a message (and
   do not set value).
 * any other non-nil value means raise an error

(defun customize-set-variable (variable value &optional comment type-checking)
  "...
Non-nil optional arg TYPE-CHECKING means type-check VALUE and
set the option value only if the type is appropriate.

If TYPE-CHECKING is `no-error' then display a message about the
incorrect type, but do not raise an error.  Any other non-nil
value means raise an error."

...)

> and otherwise does everything that
> (customize-set-variable OPTION VALUE "This is a comment.")
> does now.

Sounds good to me.

> I also request a similar addition to `custom-set-variables'.

I think this one is impossible, since `custom-set-variables' has
only an &rest parameter: the args are not wrapped in an explicit
list.  We cannot add an optional parameter after the &rest parameter.

In addition, `custom-set-variables' accepts an _expression_,
without evaluating it (by default) for each variable.  Unless
the optional NOW element is present - in that case we could
type-check the resulting value.

This also means that we would need to provide such control
separately for each variable passed to `custom-set-variables'.
We could do that by allowing NOW to take one or more special
non-nil values, to mean type-check after evaluating.  Probably
we would want to allow two such special type-checking values:

 If NOW is present and non-nil, then also evaluate EXP and set
 the default value for the SYMBOL to the value of EXP.  If NOW
 is the symbol `type-check' then raise an error if the result of
 evaluating EXP is not of an appropriate type.  If NOW is the
 symbol `type-check-no-error' then type-check the value of EXP
 but just show a message, instead of raising an error, when the
 value has an inappropriate type.

What about also having another function, similar to
`custom-set-variables', but which accepts an explicit list of
(SYMBOL EXP [NOW [REQUEST [COMMENT]]]) entries plus an optional
TYPE-CHECKING arg that has the effect of providing a default
type-checking behavior for all entries that have non-nil NOW.

Without non-nil arg TYPE-CHECKING it would behave just like
(apply 'custom-set-variables VARLIST), where VARLIST is the
explicit list of variable specs.

Maybe something like this:

(defun custom-set-varlist (varlist &optional type-checking)
  "Invoke `custom-set-variables' on the settings in list VARLIST.
Each such setting has the form of an argument acceptable to
`custom-set-variables'.

Non-nil optional arg TYPE-CHECKING means type-check each VARLIST
entry that has a non-nil NOW element, and set the option value
only if the type is appropriate.

The value of TYPE-CHECKING determines the default type-checking
behavior: a value of `no-error' means display messages about the
incorrect types, but do not raise an error.  Any other non-nil
value means raise an error.

The default type-checking behavior can be overridden for any
given variable by its NOW element.  If NOW is `type-check' or
`type-check-no-error' then it overrides the value of arg
TYPE-CHECKING for that variable.  If NOW is any other non-nil
value then the value of TYPE-CHECKING determines the behavior."

...)