Discussion:
Question about defcustom and :set-after
(too old to reply)
Eric Abrahamsen
2018-05-01 00:00:28 UTC
Permalink
I've been trying to do some fairly deep refactoring to Gnus, and have
been frustrated by the fact that it's very difficult to set up a clean
test environment for Gnus that also has some data in it to work with.

So I started writing support for a Gnus mock environment: you call
`gnus-mock' and it starts up a Gnus session completely independent of
your own Gnus customizations, that has some dummy data in it that gets
flushed and restored each time you restart the mock session.

That involves saving all relevant customizations (and some defvars) and
putting them aside, then setting all customization options (and some
defvars) back to their default values, and starting Gnus.

It isn't working quite right for me, I think because some customization
options depend on other customization options, and if they're set in the
wrong order, things don't get overwritten cleanly.

In particular I'm looking at options like this one:

(defcustom gnus-directory (or (getenv "SAVEDIR")
(nnheader-concat gnus-home-directory "News/"))
"Directory variable from which all other Gnus file variables are derived.

Note that Gnus is mostly loaded when the `.gnus.el' file is read.
This means that other directory variables that are initialized from
this variable won't be set properly if you set this variable in `.gnus.el'.
Set this variable in `.emacs' instead."
:group 'gnus-files
:type 'directory)

`gnus-home-directory' is also an option. Shouldn't this option declare a
:set-after dependency on `gnus-home-directory'? There have also been bug
reports over the years about weirdness in this area, and I wonder if it
isn't all related.

Is this what :set-after is for, and would it make sense to add that
property to all Gnus options that depend on other options?

Eric
Stefan Monnier
2018-05-01 00:37:07 UTC
Permalink
Post by Eric Abrahamsen
So I started writing support for a Gnus mock environment: you call
`gnus-mock' and it starts up a Gnus session completely independent of
your own Gnus customizations, that has some dummy data in it that gets
flushed and restored each time you restart the mock session.
Sounds really useful.
Post by Eric Abrahamsen
That involves saving all relevant customizations (and some defvars) and
putting them aside, then setting all customization options (and some
defvars) back to their default values, and starting Gnus.
Are you intending this mock environment to be used from a running Emacs
session or from "emacs -Q"?


Stefan
Eric Abrahamsen
2018-05-01 01:33:00 UTC
Permalink
Post by Stefan Monnier
Post by Eric Abrahamsen
So I started writing support for a Gnus mock environment: you call
`gnus-mock' and it starts up a Gnus session completely independent of
your own Gnus customizations, that has some dummy data in it that gets
flushed and restored each time you restart the mock session.
Sounds really useful.
Post by Eric Abrahamsen
That involves saving all relevant customizations (and some defvars) and
putting them aside, then setting all customization options (and some
defvars) back to their default values, and starting Gnus.
Are you intending this mock environment to be used from a running Emacs
session or from "emacs -Q"?
Being entirely too lazy, I intended it to be run from a running Emacs
session. I was imagining it as sort of a "gnus -Q", as in "please submit
a repro starting with `gnus-mock'".

But realistically that's a dumb idea, and it should be made to be used
from "emacs -Q". That would completely obviate the need for all this
custom-variable tomfoolery. Maybe that stuff could be quietly added but
not encouraged.

The question remains, though: I think several of Gnus' defcustom's might
need :set-after clauses.

Eric
Stefan Monnier
2018-05-01 03:54:15 UTC
Permalink
Post by Eric Abrahamsen
Being entirely too lazy, I intended it to be run from a running Emacs
session.
I understand the lazy guy wants to run it from within its session, *but*
the lazy guy wants to implement it such that it works from "emacs -Q".

So as the guy who's trying to implement it, your laziness argument
seems counterintuitive.
Post by Eric Abrahamsen
The question remains, though: I think several of Gnus' defcustom's might
need :set-after clauses.
Notice that the order in which to evaluate those settings depends on the
settings themselves, so the issue is non-trivial.

Also :set-after doesn't do what you want here: it only affects the order
in which customized vars are customized, but it doesn't cause vars to be
re-evaluated. It's for use for example when variable B should be set
after A because setting B causes something to happen (e.g. it's a minor
mode so setting it causes the mode to be loaded and enabled, so if
B affects this minor mode, we want to set it before the mode is enabled).

What you describe is currently simply not supported by Custom :-(
You can approximate it by adding :setter functions, but it's messy,
fragile, and only solves some use cases.


Stefan
Eric Abrahamsen
2018-05-01 16:20:11 UTC
Permalink
Post by Stefan Monnier
Post by Eric Abrahamsen
Being entirely too lazy, I intended it to be run from a running Emacs
session.
I understand the lazy guy wants to run it from within its session, *but*
the lazy guy wants to implement it such that it works from "emacs -Q".
So as the guy who's trying to implement it, your laziness argument
seems counterintuitive.
I thought working very hard in the pursuit of ultimately laziness was
the essence of programming :)

I'll just do an "emacs -Q" version for now, and leave the excessive
cleverness for later. Once I've got a basic working version, I'll put up
a bug report.
Post by Stefan Monnier
Post by Eric Abrahamsen
The question remains, though: I think several of Gnus' defcustom's might
need :set-after clauses.
Notice that the order in which to evaluate those settings depends on the
settings themselves, so the issue is non-trivial.
Also :set-after doesn't do what you want here: it only affects the order
in which customized vars are customized, but it doesn't cause vars to be
re-evaluated. It's for use for example when variable B should be set
after A because setting B causes something to happen (e.g. it's a minor
mode so setting it causes the mode to be loaded and enabled, so if
B affects this minor mode, we want to set it before the mode is enabled).
What you describe is currently simply not supported by Custom :-(
You can approximate it by adding :setter functions, but it's messy,
fragile, and only solves some use cases.
That's too bad. At least in this case, if I'm not trying to make Gnus
mock shadow an existing Gnus setup, this won't be a problem.

Thanks,
Eric

Loading...