Extensible programs & defaults: the Gosling Emacs experience

So, I happened to be reading a PhD thesis on exokernels, when I came across a reference. The context was that an exokernel is a maximally minimalistic operating system kernel; the kernel solely divides up resources among running programs. The programs get all other abstractions and standard OS services by linking in customized libraries, 'libOSes' as the developers put it. The point was that while an exokernel is designed so that any program can customize the operating system as much as possible, the defaults are still profoundly important, and the authors mentioned an Emacs retrospective which covered that. "UNIX Emacs: A Retrospective. Lessons for Flexible System Design" (by Gosling & Borenstein). I managed to get a copy, and I found some of it very instructive reading. Indeed, I find it instructive to look at various xmonad.hses after reading some excerpts: "The one point on which nearly everyone seems to agree is that the best thing about UNIX Emacs is that mlisp exists. No one even suggested that Emacs would be better without the powerful facility for extension and customization, although it is clear that such facilities, if abused, can create an environment that changes so radically from day to day as to be unusable for most people." "The integration of powerful editing facilities with a full-fledged programming language seems unquestionably useful, though it remains a matter of some debate whether this combination is best achieved by an extension language for a text editor or by implementing the text editor as a subroutine library in an existing programming language." "The key principle is that there is *simple syntax for simple operations*. This does not mean that a more complex syntax should not be available for more complex operations, only that the complexity should not be forced on the programmer in a simple context." "It didn't have to be that way. In the development of Emacs, it was far too easy to say that, since the support for the kind of basic interface was entirely customizable, it wasn't important to devote a lot of attention to getting the default interface to be correct. After all, anyone who didn't like the interface could change it. What this attitude ignored, however, was the old rule our mothers used to teach us about the lasting value of first impressions. Many people tried Emacs, couldn't stand the basic interface, and went back to their old standard editors, such as the vi editor on UNIX." "It is worth noting that this happened despite the fact that several people, independently, implemented more or less complete vi emulation packages for Emacs in mlisp. It seems that even if a package existed that was an absolutely perfect simulation of vi, most of the people who prefer vi to Emacs would stick with the clearly less powerful vi. While this is in part due to the smaller size of vi, it is also attributable to the unacceptable difficulty, in the minds of such people, of having to learn how to turn the vi emulation package on in the first place." "The clear lesson to be learned from this is that, while flexibility in such a system is indeed essential, great care must be paid to get the default behaviours to be simple and natural, and to provide very clear and simple ways to use a carefully chosen small set of the most commonly desired customizations. It may be, organizationally, that the people who build the flexible tools are not necessarily the right people to figure out which are the correct defaults and 'standard options'. The process of making such choices probably requires serious observation of users, or even controlled experiments, to compare possible system configurations." ----- I'm not sure how well XMonad works on the above criteria. It seems to me that there are a number of things which could be improved. For example, one of the most common changes is to switch the modifier from Alt to Win, for the simple reason that stealing Alt renders many programs nearly unusable. The arguments I've seen is that we should follow dwm tradition, and that we have no guarantee that Win is mapped to a real key, but is it really impossible for us to, say, autodetect whether Win is usable and only fallback to Alt? Or perhaps on running XMonad the first time with a xmonad.hs, there could be a prompt. Or... there are many ways we could tackle this issue. Another example: some function usages are copied all over the place. How many configurations have a line that looks like:
, keys = \c -> myKeys c `M.union` keys defaultConfig c
Yes, it's neat that we can use basic Data.Map functions to union the default and custom keymaps (with the implication we can be flexible and combine them any other way we like), but it strikes me as wrong to have a relatively opaque task repeated time and again. Why don't we have a helper function such that we could write instead:
, keys = overrideDefaultWith myKeys
Or if one is setting ManageHooks. Sure, one *could* write
, className =? "Firefox" --> doF (W.shift "web")
2, 3, 4, 6, or however many different entries one has in one's ManageHooks. But wouldn't a helper function be warranted so one could write:
, shiftClassToWS "Firefox" "web"
For that matter, am I the only one who wants to be able to unfloat windows in ManageHook? Leaving aside how there is no actual unfloat function, I was eventually able, thanks to #xmonad, to write in my xmonad.hs:
className =? "defcon.bin.x86" --> ask >>= doF . W.sink
But heck, do I understand that? Would someone else have any idea what that means? I mean, we're got 4 operators in there, 3 unusual functions (ask isn't even an xmonad function, it's from the State monad. I think. It seems a little much to expect customizers to understand monads, and the State monad, just to do a basic thing like 'unfloat an application when it opens'). ------ In short, perhaps a goal for 0.9 could be to make customizing XMonad easier on the xmonad.hs level. I think a second goal would be to change defaults in the XMonad core, and to perhaps add in some extensions by default - but that's an entirely other discussion. I'm not sure how people would react if I suggested making SmartBorders the default for the fullscreen layout. :) -- gwern Echelon Herald Islamic VHF CTP BATF POCSAG MDA USCG burhop

On Wed, Jul 30, 2008 at 11:24:31PM -0400, Gwern Branwen wrote:
So, I happened to be reading a PhD thesis on exokernels, when I came across a reference. <snip>
Thanks for that. Fun read.
"The key principle is that there is *simple syntax for simple operations*. This does not mean that a more complex syntax should not be available for more complex operations, only that the complexity should not be forced on the programmer in a simple context."
Or, in Perl terms, make easy things easy, and hard things possible.
"The clear lesson to be learned from this is that, while flexibility in such a system is indeed essential, great care must be paid to get the default behaviours to be simple and natural, and to provide very clear and simple ways to use a carefully chosen small set of the most commonly desired customizations.
Certainly, I agree. What customizations do you find common among xmonad.hses (a. applicable to xmonad-core, and b. from xmonad-contrib)?
to a real key, but is it really impossible for us to, say, autodetect whether Win is usable and only fallback to Alt? Or perhaps on running
Hrm, as I entered xmonad-land via Mac, I definitely would want the autodetect to work. I would have been pissed if xmonad started and wouldn't accept any keys. And learning how to change modMask was a nice feet-wet exercise. (Of course, this was back in the days of Config.hs, when it was, well, blatantly obvious.)
, keys = \c -> myKeys c `M.union` keys defaultConfig c
*gasp* shut your mouth! EZConfig has ears, you know.
Or if one is setting ManageHooks. Sure, one *could* write
, className =? "Firefox" --> doF (W.shift "web") But wouldn't a helper function be warranted so one could write: , shiftClassToWS "Firefox" "web"
Hrm, I'm not sure I buy that one. You'd have to create n*m functions, rather than n+m. Perhaps alias =? to for, then that reads:
, for className "Firefox" --> doShift "web" or let for a b c = a =? b --> c, so: , for className "Firefox" (doShift "web")
In short, perhaps a goal for 0.9 could be to make customizing XMonad easier on the xmonad.hs level.
Agreed. Mind you, there have been some fronts on this. One is PlainConfig, which will eventually autotranslate .conf to .hs. I've tried my hand at a couple of ways that didn't require you to mess with the config record directly, i.e.:
main = run $ do addTo manageHook blah addTo keys [blah blah] set modMask blah
(No need for weird defaultConfig { foo = newfoo + foo defaultConfig }. Just say addTo foo newfoo.) But I was butting heads with the parameterized Config type (and/or the existential Layout type) and gave my mind a rest. Plus, it got lukewarm reception here. Perhaps I'll give it another shot...
I think a second goal would be to change defaults in the XMonad core, and to perhaps add in some extensions by default - but that's an entirely other discussion.
I'm quite happy with xmonad being entirely minimalistic to start with. I would even love to see ManageHooks as a contrib, as I don't use it. :) On the other hand, I think perhaps a comparable analogy would be vim. On Windows, for us dumb folk, it auto-installs a .vimrc (in the right place, which is a bit of a mystery) that sources mswin.vim among other things, and makes it act fairly civil. (For instance, when you hit Ctrl-C/V, it cut/pastes with the windows clipboard. I didn't have to hunt through the manual for "*.) Had I started out on a minimalistic vim, (like the default 'compatible' on unices), well, I probably would have stopped fairly soon. Likewise, mutt was fairly painful until I got some reasonable .muttrc settings. Not sure what the right answer is, though. We've got tons of example configs floating around on the wiki or in XMonad.Config. Should we pick one to auto-install in the user's .xmonad?

On Thu, Jul 31, 2008 at 12:59 AM, Devin Mullins
On Wed, Jul 30, 2008 at 11:24:31PM -0400, Gwern Branwen wrote:
So, I happened to be reading a PhD thesis on exokernels, when I came across a reference. <snip>
Thanks for that. Fun read.
"The key principle is that there is *simple syntax for simple operations*. This does not mean that a more complex syntax should not be available for more complex operations, only that the complexity should not be forced on the programmer in a simple context."
Or, in Perl terms, make easy things easy, and hard things possible.
Yes, that's a good analogy. I hope we'll be able to do things in a more principled & cleaner way than Perl seems to do things though!
Certainly, I agree. What customizations do you find common among xmonad.hses (a. applicable to xmonad-core, and b. from xmonad-contrib)?
I've listed a few already, but I'm sure that I've missed many. For example, I'm sure that some modules are always used together and so one should export the other, but I have no way of analyzing this really. I do invite everyone to pitch on this though! This is precisely why I've constantly touted uploading one's config to the wiki, and why I took the time to write an automated downloader of the xmonad configs at http://haskell.org/haskellwiki/Config_archive#Downloading
to a real key, but is it really impossible for us to, say, autodetect whether Win is usable and only fallback to Alt? Or perhaps on running
Hrm, as I entered xmonad-land via Mac, I definitely would want the autodetect to work. I would have been pissed if xmonad started and wouldn't accept any keys. And learning how to change modMask was a nice feet-wet exercise. (Of course, this was back in the days of Config.hs, when it was, well, blatantly obvious.)
It may be a nice exercise, but *so* many people do it! In my config archive (populated by the aforementioned downloader), I can run 'grep -l mod4Mask *|sort|uniq|wc' and do you know how many configs set the mask to mod4Mask? *40*! There are only 51 configs! So 78% of the known configs do this one setting. I think that's a lot. I understand maybe we can't simply switch bindings, but we need to do something about that, I think.
, keys = \c -> myKeys c `M.union` keys defaultConfig c
*gasp* shut your mouth! EZConfig has ears, you know.
Well, the way forward here is to revamp the key binding system entirely. Spencer has an experimental monoid-based branch of xmonad which I tried, at http://code.haskell.org/~sjanssen/xmonad-newconfig , and it's definitely a cleaner way of doing things. I don't know know how mature or ready for inclusion it is, though.
Or if one is setting ManageHooks. Sure, one *could* write
, className =? "Firefox" --> doF (W.shift "web") But wouldn't a helper function be warranted so one could write: , shiftClassToWS "Firefox" "web"
Hrm, I'm not sure I buy that one. You'd have to create n*m functions, rather than n+m. Perhaps alias =? to for, then that reads:
, for className "Firefox" --> doShift "web" or let for a b c = a =? b --> c, so: , for className "Firefox" (doShift "web")
I have 2 thoughts about this one. The first is that n*m isn't too bad - we match on just class and title, right? So that's just *2. My second is that perhaps everyone should be matching on either class or title. So we have 'match a b = className a =? b || title a =? b'. This is probably just as likely to work - I don't think I've ever seen or heard of two apps where A has B's classname, and B A's title - and more likely to just work (without the user having to deal with finicky details of whether it was classname or title). With 'match', we then need just one function - matchToWorkspace - and we cover a large swathe of functionality. (Grepping through, I think we could cover just about all uses with 5 match* functions: one each for 'doF (W.shift', 'doFloat', 'moveTo', 'doIgnore', and 'doCenterFloat')
In short, perhaps a goal for 0.9 could be to make customizing XMonad easier on the xmonad.hs level.
Agreed. Mind you, there have been some fronts on this. One is PlainConfig, which will eventually autotranslate .conf to .hs. I've tried my hand at a couple of ways that didn't require you to mess with the config record directly, i.e.:
main = run $ do addTo manageHook blah addTo keys [blah blah] set modMask blah
(No need for weird defaultConfig { foo = newfoo + foo defaultConfig }. Just say addTo foo newfoo.)
But I was butting heads with the parameterized Config type (and/or the existential Layout type) and gave my mind a rest. Plus, it got lukewarm reception here. Perhaps I'll give it another shot...
I think a second goal would be to change defaults in the XMonad core, and to perhaps add in some extensions by default - but that's an entirely other discussion.
I'm quite happy with xmonad being entirely minimalistic to start with. I would even love to see ManageHooks as a contrib, as I don't use it. :)
On the other hand, I think perhaps a comparable analogy would be vim. On Windows, for us dumb folk, it auto-installs a .vimrc (in the right place, which is a bit of a mystery) that sources mswin.vim among other things, and makes it act fairly civil. (For instance, when you hit Ctrl-C/V, it cut/pastes with the windows clipboard. I didn't have to hunt through the manual for "*.)
Had I started out on a minimalistic vim, (like the default 'compatible' on unices), well, I probably would have stopped fairly soon. Likewise, mutt was fairly painful until I got some reasonable .muttrc settings.
Not sure what the right answer is, though. We've got tons of example configs floating around on the wiki or in XMonad.Config. Should we pick one to auto-install in the user's .xmonad?
Yes, what's the right thing to do here? I'm not really sure. I think we can get a lot of mileage out of just improving the defaults and adding some intelligence (auto-detection of mod4Mask being my favorite example). Random suggestion: work up a list of xmonad 'paradigms', create a xmonad.hs that implements purely that paradigm, and copy them to ~/.xmonad on startup? -- gwern

That was an interesting read, indeed. Certainly the xmonad faithful agree that one of its greatest strengths is the power of Haskell configuration. I suspect I wouldn't want to use most of your personal xmonads, because everyone's is tuned to their machine, distro, usage and aesthetic. On one hand, PlainConfig as the standard configuration for newcomers accomplishes a lot of the simplification side. The move to having an xmonad.hs will still be a sharp change, but we're throwing new users straight into that already, so this is hardly worse. But simplifying the early configuration process and removing the GHC dependency are only part of the puzzle. The idea of getting our defaults right and providing a strong first impression is important too. The point where this is most obvious comes to mind from #xmonad support patterns: ManageDocks! Practically everybody uses them, and there is occasionally confusion about how to set it up. It could be far simpler. Granted, it will be so with PlainConfig, should be as simple as adding "avoidStatusBars = 1" or some similar syntax. But I imagine the experience of pasting configs and needing so much help from #xmonad just to do such an apparently simple and common thing isn't the best first experience. Though it does highlight the politeness and competence of #xmonad, which is a positive, it should still be easier for newcomers to manage that one, ideally on their own. If it weren't already abundantly clear from my championing of PlainConfig, I definitely support the idea of making xmonad more accessible to the new user, though of course without sacrificing the high-end flexibility we know and love. I have nightly builds of core and contrib working. I'll create a modified version of the scripts that combines them into a single bundle, that will install a complete ~/.xmonad/xmonad.conf, with every setting there, commented, and set to the default, for maximum ease of use. Then the next quick project is adding more modules (ManageDocks, EwmhDesktops, and some other favourites) into PlainConfig's repertoire. Finally the xmonad.conf -> xmonad.hs compiler is the last step toward a complete system on that front. Hopefully this doesn't seem like hijacking the thread. It's all in the vein of making xmonad the best experience possible, for new and old users. Braden Shepherdson shepheb
participants (3)
-
Braden Shepherdson
-
Devin Mullins
-
Gwern Branwen