emacs-devel
[Top][All Lists]
Advanced

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

RE: Eliminating a couple of independent face definitions


From: Drew Adams
Subject: RE: Eliminating a couple of independent face definitions
Date: Sat, 5 Feb 2011 14:11:44 -0800

T> One thing I would recommend doing, if possible, would be to
T> spend some time running emacs with a dark background and on a
T> tty.  This would likely reveal how bad some default face
T> definitions are and let you see how tedious it is having to
T> customize lots of individual face definitions just to get ones
T> that work.
 
I'm not sure what your disagreements are with what I said.  I
agree that poorly defined default face definitions are a real
problem.  I even suggested that they are likely _the_ real
problem here.
 
Given reasonable face defaults that work out of the box on
both dark and light backgrounds, I think many if not most
(perhaps all?) of the problems you cited go away.  With faces
that just work by default, regardless of the background, there
is no need to "customize lots of individual face definitions
just to get ones that work".
 
T> As I see it, we want to achieve four main goals. We want to
T> make it easier for developers to set appropriate defaults, we
T> want to get the best default possible for end users,
T> regardless of platform or light/dark background preferences,
T> we want to make it as easy as possible for end users to
T> customize their environment
 
Agree.
 
T> and we want to, if possible, avoid a proliferation of
T> different face definitions, especially when the definitions
T> don't really differ in anything other than name as this makes
T> customizing and theme definition more complex than it needs to
T> be.
 
Disagree, if by "don't really differ in anything other than
the name" you are referring only to the `defface' default
attribute values.
 
I am in favor of there being two faces instead of one, if
their use/meaning is different, even if their definitions
modulo the names are identical.  In particular, this
facilitates separate customization.
 
It avoids coupling that is not logical and not necessary.
Inheritance (hence coupling) based on physical attributes
(appearance) can perhaps occasionally be appropriate, but in
general it is a no-no.
 
(Names are generally indicative of meaning, but yes, there
could be two faces with different names yet identical meaning.
In that case, yes, the duplication could be eliminated.)
 
(There is an orthogonal reason to avoid using too many faces
at the same time: performance.  But that is a different story
altogether.)
 
T> It was good you pointed out that faces are not just about
T> colour.  Sometimes, I think peopoe forget this and only focus
T> on the colour aspect.  However, this is understandable as
T> colour is what distinguishes most faces from each other.
T> 
T> We need to acknowledge how difficult it is to define good
T> default faces.  Many definitions fail to do this.  While your
T> suggestion of using colour compliments can help, I'm not
T> convinced it is always that easy.  One problem is that
T> different environments have different sets of colours to work
T> with.  For example, if you work under the linux console, you
T> don't have compliments for most of the colours available under
T> other environments, such as X or (I presume) Windows/Mac.  The
T> problem is further complicated because most developers won't
T> have access to many of these environments, so can't easil test
T> and design appropriate faces even if motivated to do so. 
 
Agree.  I did not mean to raise complementing as any kind of
cure-all - far from it.  I was just mentioning that I provided
a quick-and-dirty set of default settings for dark backgrounds
for a particular library by flipping the light-background
defaults to their complements.  Obviously, any set of defaults
for either light or dark deserves to be well thought out.  And
all of the considerations you mention should be taken into
account.
 
The tty thing is a big limitation, in particular.  Designing a
set of faces for use on tty only is a different task from
designing a set for use with many colors and other attributes.
 
For a library that is intended to work with both tty and
graphic windows, either tradeoffs are called for or
essentially two modes or face schemes are needed: full and
degraded (tty).  We have constructs like `(type tty pc)' that
can help with that.
 
T> I would not argue that inheritance is an ideal solution to
T> this problem,  However, I do think it can be part of the
T> solution.  Perhaps something along the lines of
T> 
T>  * Establish guidelines on how to use inheritance i.e. how to
T>    select which face to inherit from
T>  * Define a good (not too large) set of base faces.  Existing
T>    font-lock faces may be sufficient, maybe not.  Would need
T>    review.
T>  * Require all face definitions in core emacs packages to
T>    either fully define a face (i.e. definition for dark/light,
T>    tty, X mac ms etc) OR inherit from a base face (assuming
T>    all base faces are fully defined)
T>  * Add a section to the manual encouraging developers to
T>    either provide a fully defined face or inherit from a base
T>    face, but don't just define a single (usually) light
T>    background face
T> 
T> The key here is that all faces in core emacs packages would
T> end up with a fully defined face, either explicitly or via
T> inherit.
 
Fully-defined, yes - good.  The part that I think can be
misguided is basing everything on inheritance from faces that
are not necessarily related in terms of use or meaning.

Basing a face on a related face is not bad.  Stretching things
to base all faces on some "basic" faces, no matter how
unrelated in terms of meaning or context, is not a great idea.
 
Faces, including "basic" faces, are customizable.  You don't
want a user who customizes `font-lock-doc-face' to suddenly
find that s?he has also affected a chain of unrelated faces
that inherit from it.  Customizing font-lock faces should not
affect Dired or Info or...
 
T> One of the reasons I like the use of inherit for face
T> definitions is mainly from an end user perspective. I would
T> rather have faces that are fully defined via inherit, even if
T> that inheritance seems odd, than have a partially defined face
T> which only works if you have a light background or are running
T> under a full gui environment.
 
Those are not the only two alternatives - it's not either-or.
 
I am in favor of full face definitions.  And I am not against
inheritance.  The important thing is for a face to inherit
only from a related face (in terms of use/meaning).
 
The key is whether it will generally make sense for the
inheriting face if the inherited face gets customized.  If
not, then inheritance is likely not the best way to go.
 
T> If, when I change the base face definition, it results in
T> unacceptable changes to some face which inherits from it, I
T> can customize it.
 
Sure you can, but now you're back to customizing all over the
place - and now across multiple libraries and multiple use
contexts, to boot.  The cure is at least as bad as the
disease.
 
Nothing wrong with inheritance.  But boiling everything down
to font-lock faces (or similar) is a bad idea.  Better for
face inheritance to reflect face usage/meaning: families
(inheritance hierarchies) of related faces, not just
everything inheriting from primordial faces `adam' and `eve'.
 
T> My experience has been that this does sometimes happen, but
T> not that often and it is more preferable to fix up the few
T> faces than to spend much more time configuring lots of
T> individual faces.
 
I think you are again thinking of the fact that you are
needing to configure lots of faces because they were defined
incompletely or with poor defaults.  Take away that
presupposition and where is the argument?
 
T> In fact, as the number of individual face definitions has
T> increased, I actaully think we have gone the wrong direction.
T> We have too many faces which are mostly the same.
 
They are not the same just because they have the same
_appearance_ (by _default_ no less).  This is a key element in
the confusion, I think.  It sounds like it motivated Yidong's
search for faces to eliminate "duplication" via inheritance.
 
Faces are not the same as their (attribute) values.  Faces
have identity and purpose as well as values.
 
This is essentially no different from having multiple user
options (or other variables) that have the same value: 42,
nil, t,...  You would not argue that we define a set of
"basic" user options and use inheritance to factor out any
"duplicate" options that have the same default value of 42 or
nil, would you?
 
You would not argue that we should have only one primeval user
option with a default value of 42, and inherit from it for
wildly different options with different use cases (meanings),
so that someone who customizes the "basic" option to change
the value 42 to 24 ends up changing lots and lots of
inheriting options.  Would you?  How are faces different in
this regard?
 
T> It seems now that every new package is adding its own face
T> definitions
 
Good.  That should probably happen more than it does. ;-)
 
If reasonable, related faces exist on which to base the new
face definitions, then by all means inheritance might well be
called for.  But a new package should _not_ avoid adding its
own face definitions, whether they are defined using
inheritance or not (i.e., pointer or copy).
 
On the contrary.  What should be avoided is reusing some face
that makes no sense in the current context.  What is the
_practical_ criterion?  Whether or not customizing the face
wrt its original context/purpose will have a negative effect
in the new context.  If not, then go for it (reuse/inherit).
 
T> and many of them are poorly defined.  It now takes much
T> longer for me to establish a consistent set of faces.
 
Bad - agreed.  But not a necessary consequence of having many
faces.  More likely a consequence of poor default definitions
(as you mentioned).
 
T> If we required face definitions to either be fully defined or
T> inherited from a base set that are fully defined, we would
T> likely give a much better default experience to end users.
 
Full face definitions are good, yes.
That is independent of the question of inheritance.
 
Well... indiscrimately imposing inheritance (from fully defined
faces) can ensure full definitions.  But it has a cost: it can
also introduce unnecessary and unwanted dependencies with
negative consequences.
 
T> Using inheritance also means that when we find a face
T> definition which is poor for a particular environment, we can
T> refine that base definition rather than having to find all
T> similarly poor definitions and updating them individually.
 
Yes and no.  "Fixing" it for one environment might do exactly
the wrong thing for another context, e.g. for one of its
descendents.  Inheritance needs to be used carefully, based on
intended use/meaning of the faces involved.
 
T> Using inheritance means that it is easier to make broad
T> changes to face definitions, reducing the time spent in
T> customize and lets you then tweak those specific faces which
T> don't quite work.
T>
T> So, using your example, if someone changed the base face that
T> dired+ uses, either they will find the result in dired+
T> acceptable or they can then tweak that face further.  The
T> alternative is that it would be necessary to customize both
T> faces, even when you are going to set them to the same value.
 
Maybe, maybe not.  Depends what kind of change you want/need.
 
It's true that if you want to change all occurrences of red
foreground to blue then more customization would be involved
without inheritance.  Maybe we could find a way to make such
changes easier - I don't have a problem with that.
 
But we should not be using _inheritance_ for that (in
general).  A Dired face should either not inherit or it should
inherit from a related face, not just some face whose _default
appearance_ looks good for Dired.  It makes no sense to base a
Dired face on a font-lock face, for instance.
 
Just because you might want some Dired face to have a red
foreground by default is no reason to go looking for a face
with a red foreground to inherit from.  Look instead for a
face with a related use/meaning.  If you find none, then do
not use inheritance here.  That's the guideline I'd suggest.
 
I emphasize the use/meaning of a given face: what it is for,
what it represents, what it does.  I think you are emphasizing
its default appearance - attribute values (color etc.).  To
me, a face or a variable `foo' is mainly about its use, not
its value.
 
If the opposite were true, then we would name faces and
variables after their default values, not after their uses.
Yes, I've seen some Lisp code with face names like
`underlined-bold-red-foreground-on-gray-background'.
(Mea culpa: I even wrote such code at one point.)
 
And there's not necessarily anything wrong with that; for some
contexts it might make sense.  But in that case it makes more
sense for the "face" to be a constant, not customizable.  It
would be perverse to customize a face named `red-foreground'
to have a green foreground.
 
(And in general it is more likely for single attributes to be
reuse candidates than it is for combinations of attributes.)
 
T> The reality is that there are a limited set of good faces and
T> you will usually end up with the same face definition being
T> used in multiple roles.  Frequently, those roles have nothing
T> to do with each other.  This doesn't matter as the contexts
T> are completely different.  From an end user perspective, it is
T> irrelevant that compiler messages inherit from
T> font-lock-string - all the end user sees is that compiler
T> messages use a default face that is green, which may be
T> exactly the same as strings in their code, but so what.
 
I strongly disagree here.
 
If the roles/meanings/use are unrelated, then inheritance is
usually inappropriate.  It _does_ matter whether a
compiler-messages face inherits from `font-lock-string-face' -
_if_ someone customizes that parent face.
 
If we defined a compiler-messages face to inherit from
`font-lock-string-face' _only_ because we liked the default
foreground choice of `LightSalmon', that would be misguided,
IMO.
 
If there is no existing face that is related in terms of
use/meaning, then the compiler-messages face should not
inherit; it should just be defined with a default foreground
of `LightSalmon'.  That kind of duplication is not a curse but
a blessing.
 
Then a user can customize either the compiler-messages face or
`font-lock-string-face' without affecting the other.  And that
makes sense because (by hypothesis) the two are unrelated.




reply via email to

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