Account: (login)

More Channels


Are you the publisher? Claim this channel

Search in 110,818,677 RSS articles:

Channel Description:

Simon Tatham - LiveJournal.com

Latest Articles in this Channel:

  • 11/01/10--01:10: Sometimes I want a portable QI klaxon (chan 1676087)
  • I'm in work an hour early today, as partial compensation for the fact that I have to leave two hours early to go home and wait for a boiler engineer.

    Of course, it so happens that that's also the time I'd have shown up if I'd failed to notice that the clocks had changed. Naturally this occurred to me; naturally I suspected that somebody would make that assumption; and naturally, as I was sitting down at my desk, someone did indeed ask ‘You know the time changed, didn't you?’.

    In such situations I can think of no better response than the QI alarm sound. (Though Stephen Fry pulling a foolish face is optional.)

  • 11/02/10--11:42: That's going to take a little getting used to (chan 1676087)
  • As of yesterday, apparently, I am now Uncle Simon.

  • 11/26/10--01:34: A foolish thought from the pub (chan 1676087)
  • Everybody knows what wisdom teeth are. But under the influence of booze it occurred to me to take the concept in an unusual direction.

    Strength teeth must surely be the molars; the sheer leverage available to them allows them to effortlessly crush things that the front teeth would have a hard time getting into.

    Dexterity teeth are the canines: they grip on to things to allow them to be manipulated.

    Charisma teeth, as [info]ptc24 pointed out, are the incisors right at the front, which are conveniently placed to (if properly cleaned and polished) catch the light photogenically when you smile.

    What I'm not so sure about is where intelligence teeth and constitution teeth come in. Premolars are still to be assigned, but I can't make a good case for them being either of those…

  • 12/09/10--05:56: Intellectual weaknesses (chan 1676087)
  • For a while now I've been trying to think a bit about the way I think. When I get something wrong, fail to solve a problem, misunderstand something, or whatever, I try to look back on what went wrong, and I try to notice if it's the same thing that went wrong on other occasions. I now think I'm in a position to write down some of my most noticeable intellectual weaknesses. (At least, most noticeable to me. I expect other people probably notice different weaknesses about me from the ones I notice about myself.)

    Neophobia. I often find that I'm extremely reluctant to get into a new piece of thought: picking up a new problem, or starting to learn about a new thing. Typically once I finally do get over that activation-energy barrier, I find it's not at all as difficult as I'd imagined it would be, but for some reason I still don't remember that the next time I'm having the same problem.

    Too uninterested in the actual compared to the possible. To some extent this almost isn't a weakness – my feeling is that there's plenty of room in the world for on the one hand people who look at things that are possible and go and do them, and on the other hand people who have a good working knowledge of all the stuff that's already been done and can get it to where it's needed. But even the former kind of person needs to have some awareness of what's already been done, to avoid repeatedly reinventing wheels and wasting effort, and I think I err just a little too far in the direction of lacking that awareness: I'm reluctant to spend brain-space on holding a mental catalogue of stuff that already exists when I could instead spend it on knowing how to make new stuff.

    Difficulty keeping track of many things. I much prefer to have a small number of problems to work on, each of which is complicated and fiddly, than a large number of problems each of which is in itself simple. I can handle complicated problems fine (or rather, I have at least as much of a fighting chance with them as anyone else), but keeping track of lots and lots of things without forgetting about one of them is much harder for me. Of course I can and do compensate by constant list-making, but as soon as I have to manage without a list it all goes pear-shaped.

    Compartmentalisation. When I learn a fact in one context, I often find I've failed to apply it in another context, or failed to relate it to a fact I learned in another context which in combination with the first one would have told me something really useful. I seem to have a few mental compartments for thinking about different kinds of thing, and sometimes those compartments don't link up and talk to each other when they really ought to.

    Insufficiently bold imagination. Quite a few times in the past couple of years I've tried to solve a problem by considering a lot of candidate solutions and then judging which of them are sensible or workable or likely. Often I've failed to solve the problem, and found out afterwards that this was because the real answer was completely outside the space of possibilities I'd considered – either because it was totally different from any idea I'd had at all, or (perhaps more embarrassingly) because it was an idea I had had but hadn't taken far enough. It typically seemed to me afterwards that my judgment was not obviously at fault at any point – all the solutions I dismissed as wrong were indeed wrong for pretty much the same reasons I thought – but in each case my imagination let me down by not coming up with a wide enough range of possibilities to submit to my judgment.

    I wonder what can be done about these. One feels that the neophobia ought to be dealable-with just by more forcibly reminding myself that it's never as bad as I expect, but it probably isn't that easy in practice, and with the rest of them it's not even clear what I might be able to do to stop it…

  • 12/11/10--00:50: Trust (chan 1676087)
  • When I was a child, I remember that I used to have a peculiar problem whenever I replaced my watch. For days or weeks after strapping the new one on to my wrist, I'd wonder what the time was, look at my watch … and then feel unsatisfied, as if somehow I still didn't actually know what the time was in spite of having just read it off. I'd feel a strong urge to go and find another clock and look at that. It's as if I didn't trust the new watch.

    I suppose it's possible that this was my subconscious reminding me of the practical consideration that I didn't yet have a feel for how accurate the new watch was, but that seems far-fetched to me. I think it was just a nonspecific feeling of ‘this thing is newfangled, it has to prove itself’.

    I haven't replaced my watch in well over a decade, so until today I had no idea whether I would still have this odd feeling. But just now …

    I've recently acquired an iPad, and also I've finally got round to setting up wireless networking at home to use it with. So today I thought I'd do my morning spod – check email, LJ, news, etc – before getting out of bed. (Just to prove I could, and also because it's warmer.)

    So I did that; but as soon as I got up, I felt a strong visceral urge to make for the nearest ‘real’ computer and reassure myself that there weren't any urgent emails waiting for me. But I just looked! Arrgh!

    (This is even less rational than the one about the watch. A new watch might have turned out to be hopelessly inaccurate compared to the old one, but I check my email over SSH, which is really, really not going to present me with wrong answers depending on where I connect from. If it gives me any recognisable answer at all, it'll be the right one.)

  • 12/18/10--15:36: Truly this is the age of the Internet (chan 1676087)
  • Brushing the loose snow off the roof of my car, I found that the layer of more solid ice underneath had a message engraved in it. Some passing scamp had presumably written with their finger in the initial layer of snow, and when that solidified under the next layer the message was preserved.

    The message just read ‘LOL’.

  • 01/09/11--01:57: A foolish thought (chan 1676087)
  • If somebody had been programming exclusively in FORTH and PostScript for years on end, they'd probably think a change would be inorder.

  • 02/01/11--01:14: The Moment of Jinx (chan 1676087)
  • There's something about screwing the lid back on to a computer's case that seems to act as a magnet for bad luck. Especially if the same machine has been running just fine for weeks or months with the lid off; you finally decide that's cause to declare it working, so you put the lid back on and do up the screws … and the tightening of the final screw, symbolic of your overconfident belief that the job is at last done, is the cue for every intermittent fault, every surprising and hitherto unmanifested bug, every glitch and gremlin and gribbly to come out of the woodwork and make itself known.

    Just occasionally there's a causally valid reason for this – the machine actually won't run with the lid on because its CPU fan is dead, or the act of putting the lid back on disturbed a loose connection that would have preferred to be left alone – but usually, it seems to me, it's just Murphy's Law.

    (Preliminary indications suggest that the one of these that happened to me last night was not even a fault in the computer in question, but I'm half expecting further nasty surprises…)

  • 03/14/11--07:32: Placing a foot into the other camp (chan 1676087)
  • More migration seems to be occurring, so it's probably about time I got round to doing this: I'm now simont.dreamwidth.org as well as simont.livejournal.com. I have no plans to deactivate my LJ or stop reading stuff via it; I expect to cross-post everything and accept comments anywhere people feel like posting them.

    There will doubtless be annoying teething problems as I sort out this dual presence and integrate it with the rest of my setup. In fact I've already made one cock-up just in the last half hour, by pasting the wrong list of usernames over from my previous OpenID-based presence on Dreamwidth and then hastily correcting. People who've unexpectedly found I subscribed to them and then unsubscribed again immediately: it was part of a mass update gone wrong, no personal insult was intended, and I'm very sorry.

  • 03/16/11--04:36: Layer-free shell syntax (chan 1676087)
  • Here's a question I've been pondering for a while, to which I don't have any good answer.

    I often find myself answering questions from Unix users who are having a little trouble working out how to get some complicated piece of shell syntax to work. The impression I'm left with is that a major source of confusion is the fact that the POSIX shell syntax as a whole – defined as the entire sequence of steps that get from a single input string (typed on the command line or read from a script) to the decisions of individual programs about what to do – is composed of a great many layers, and it doesn't take all that unusual a situation before it becomes important to understand what happens in which layer in order to debug your problem.

    Examples of gotchas arising from this, many of which you need to develop quite a deep understanding to sort out, include:

    • searching for a string starting with a minus sign using a command along the lines of ‘grep \-10 file.txt’. (‘The backslash causes other characters to be treated literally rather than specially, so why not this one?’)
    • expecting ‘~’ and ‘~user’ to still be expanded after a colon (‘PATH=/here:~/there:$PATH’).
    • getting subtly wrong results when adding a prefix to an existing command line, if the latter had redirections. (E.g. prefixing ‘sudo’ or ‘gdb --args’, and finding that in the former case the file is not opened with root privilege and in the latter case all of gdb's interactive output gets lost.)
    • almost anything involving multiple layers of escaping. (The typical example being regular expressions, where you have to first escape special characters to stop them being special to the shell, and then escape them a second time to stop them being special to the application. And don't forget to shell-escape the extra characters you used for the second job, of course.)
    • when a one-character option takes an argument either with or without a separating space, and you want to pass an empty string as argument, omitting the space before the quoted empty string. (‘If ‘-s foo’ and ‘-sfoo’ and ‘-s ""’ all do what I expect, why on earth would ‘-s""’ not?’)

    Some of these even catch me out on occasion, and I know perfectly well why they don't work. Typically I realise my mistake as soon as I see the error message or odd behaviour – but it's telling that I nonetheless still get it wrong some of the time, because the real rules of how this stuff works are just too cumbersome to think through from first principles for every command I type, and so I use a simpler intuitive model most of the time and only resort to applying my full understanding when that can't cope.

    And that's the point, really. The system is just too complicated to manage sensibly. So: if we were designing a shell syntax from scratch, would it be possible to arrange it in such a way that you don't ever have to reason about layers? The ground rule would be: the system is permitted to divide labour between multiple processes or pieces of code, as long as that division is its problem rather than the user's, and (barring the diagnosis of actual bugs) a user never has to keep in mind the divisions between those components just to figure out what a given command will do or what command they need to do a given task.

    But the catch is that you aren't allowed to solve the problem by reducing the expressive power of the syntax. If you do, application authors will take up the slack by implementing all the things you didn't, and they'll all do it differently from each other, or not do it at all, and nobody will be better off. (See, for example, the haphazard state of wildcard support in Windows command-line programs.)

    Here's a simple example of the sort of thing I'm thinking of. In a summer job when I was a student, I had occasion to write a tool that presented an internal command line, and I got to make up the syntax used on that command line. Basically on a whim, I set it up as follows: spaces were special (they separated words), double quotes were special (they stopped spaces from separating words), and the only other special things were braces, which were used to enclose special tag names. Initially, when starting to scan a command line and looking for the actual command word, the only things you were allowed to do with braces was to use them to escape the existing special characters, so that {{} and {}} and {"} translated into the literal characters {, } and ". But the main command processor only parsed the input line as far as was necessary to find the command name – and parsing the rest of the line was deferred until that command had had a chance to add extra sequences to the list of braced escapes. So, for instance, if a command had decided to treat the minus sign specially, that command could also have added support for an escaped version {-} which was not treated specially; so a user would not have had to draw the mental distinction between characters treated specially by the ‘shell’ and by one particular subcommand, and would have been able to work on the much simpler principle that all special characters were defusable by bracing them. (Or, perhaps better still, the subcommands could all have adopted the principle that everything not braced was treated literally, and invented braced tags to do everything special they might need.)

    Of course it was easy for me to do something like that in a small language supporting only a few commands, particularly when there was no division into subprocesses (each of my commands was just a procedure within the same source file). And even so, my design wasn't perfect (e.g. it would still have suffered from the ‘-s""’ flaw in my above list). And it had very simple functionality by comparison to the full scope of real shell syntax. And, of course, I wouldn't even dare to imagine that any replacement shell syntax design would be realistically adoptable at this stage, what with a huge established source base.

    But it illustrates the sort of idea I'm thinking of. So, just as an exercise for curiosity's sake … could the entire edifice of shell design be reworked, in principle, by means such as the above or by totally different means, so as to avoid the need to have users keep track of the multiple layers of code involved?



    Also at Dreamwidth. ( comment count unavailable comments | Leave a comment )

  • 03/17/11--03:23: C abuse of the week (chan 1676087)
  • A while back I wanted to write some C code that looped over every element in a collection. But I wanted the code to be parametrisable in the face of different implementations of that collection, because it might have to link against several other pieces of code which might all store the things in question in a different format.

    So I thought I'd do this:

        LOOP_OVER_ALL_ELEPHANTS(elephant) {
    /* loop body executed once for each elephant */
    }

    And then each implementation would define the macro LOOP_OVER_ALL_ELEPHANTS appropriately for how it happened to be storing its elephants. If it was an array, the macro would expand to

        for (elephant = array; elephant < array + len; elephant++)

    and if it was a linked list, it would expand to

        for (elephant = head; elephant != NULL; elephant = elephant->next)

    and I presumed that any more complicated thing like a C++ STL collection would have some kind of similar idiom available.

    Unfortunately, the very first implementation I tried to test against turned out to be storing its elephants in a circularly linked list – and you can't iterate over that in a for statement, because the start condition is the same as the end condition. If you write the apparently obvious adaptation of the linear-list code,

        for (elephant = head; elephant != head; elephant = elephant->next)

    then the loop terminates after zero iterations and you look foolish.

    I solved the problem by rewriting my loop in the form

        LOOP_OVER_ALL_ELEPHANTS(elephant) {
    /* loop body executed once for each elephant */
    } END_LOOP_OVER_ALL_ELEPHANTS(elephant)

    which permitted the porting code to define a pair of macros containing the two ends of a do-while, so as to defer the first loop termination test until after the first run of the loop body. This felt inelegant and cumbersome, and I found myself wishing for a more metaprogrammable language to work in.

    But this morning, I do believe I've solved it. You can iterate over a circularly linked list using a construction that can be encapsulated into my original macro, requiring no loop machinery after the single closing brace. It's strictly legal standard C as far as I can see, and it goes like this:

        switch (elephant = head, 0)
    while (elephant = elephant->next, elephant != head)
    case 0:

    Then you can follow that with a single braced block (or even an unbraced statement), and everything works – including continue. So I could have put that lot into my macro, and it would have been fine!

    More generally, this construction permits a sort of variant form of the for statement, which does its test after the loop body rather than before. You could almost define it as a macro in its own right:

    #define for_after(init, condition, increment) \
    switch(init, 0) while (increment, condition) case 0:

    Of course that isn't quite syntactically right, because the three clauses of the for are separated by commas rather than semicolons, and can't contain initialisers in the way that a proper for can. Also there's the unusual constraint that the body of such a statement cannot contain case statements intended to bind to switches outside the loop (so you can't combine a loop of this form with Duff's Device).

    But it's closer than I thought I'd be able to get!

    eta: there's a bug in the switch-based solution above. See my follow-up post for details.

    Also at Dreamwidth. ( comment count unavailable comments | Leave a comment )

  • 03/18/11--06:33: Errata (chan 1676087)
  • Ahem. In yesterday's post about iterating over a circularly linked list, I made a mistake. The construction I exhibited, because it completely skips any test at the start of the loop, will crash if the list is empty and hence its head pointer is NULL.

    Fortunately, this is fixable by putting an additional test in the switch statement:

        switch ((elephant = head) == NULL)
    while (elephant = elephant->next, elephant != head)
    case 0:

    Then if the head pointer is NULL, the switch's input value will be 1, so it won't execute anything in its body at all.

    However, I now also realise that there's a better answer in the first place. One commenter yesterday observed (and I had also thought myself) that the problem would be easy if only you could declare an extra flag variable and use it to suppress the first loop test. You can't, under the constraints of C90 syntax, because there's nowhere to put the declaration that doesn't cause further syntactic problems. But actually, I just realised, you don't need an extra variable at all – all you need is an extra value for the loop variable you've already got, and we already have a good special value for pointer variables in the form of NULL. So you can just do this:

        for (elephant = NULL;
    elephant ? elephant != head : (elephant = head) != NULL;
    elephant = elephant->next)

    So if elephant is NULL on entry to the loop test clause, that's the signal that it's the very first iteration, and we reassign elephant to the loop head pointer (and terminate if even that is NULL). Otherwise, it's a non-initial test, and we do the obvious thing of checking whether we've arrived back at head.

    This is a cleaner solution than the switch-based one, because it doesn't interfere with case statements inside the user-provided loop body. It's far less exciting, but there we go.

    Also at Dreamwidth. ( comment count unavailable comments | Leave a comment )

  • 03/22/11--04:26: Gadgets I would like to exist (chan 1676087)
  • I've occasionally thought it would be nice to have a coffee mug with a built-in heater, so it keeps the coffee from getting completely cold. But this is an obviously impractical idea: heating costs serious energy, so you'd have to have a stand to supply the power, which is inconvenient; also there are probably some exciting failure modes.

    This morning it occurs to me that there's a much smaller, simpler and more realistic coffee-related gadget that would deliver a similar benefit: a thermometer you could attach to the outside of the mug which would go beep when the temperature dropped to a predefined threshold, signalling ‘last chance to drink up your coffee before it gets unpleasantly cold’. That could much more easily be a standalone device running off a battery.

    I suppose you'd also want it to notice if you'd already finished the coffee, and not go beep just because an empty mug had cooled past the threshold. Hmm. Must be something clever you can do about that…

    Also at Dreamwidth. ( comment count unavailable comments | Leave a comment )

  • 04/05/11--16:24: Exploding toothpaste (chan 1676087)
  • Warrgh, that was unexpected. I picked up my toothpaste tube, squeezed it gently until toothpaste began to emerge from the nozzle … and there was a sudden pop, a fingertip-sized blob of toothpaste flew out of the tube and landed in the basin, and I was hit in the eye by a sharp puff of minty air.

    There must have been a big bubble of air in the tube due to a manufacturing defect of some sort, and the instant there was no longer enough toothpaste blocking the nozzle to impede its bid for freedom, off it went.

    But for all that the cause is comprehensible after the fact … I've never had a tube of toothpaste explode in my face before!

    Also at Dreamwidth. ( comment count unavailable comments | Leave a comment )

  • 04/14/11--09:15: Machine translation gets it spectacularly right (chan 1676087)
  • In a debate at work about development workflow, I somewhat whimsically responded to a suggestion by writing ‘Jira issues non sunt multiplicanda praeter necessitatem’. (For those lucky enough not to have encountered it, ‘Jira’ is the name of a bug tracker.) I wondered briefly whether that would be too incomprehensible to post (but decided not, and posted it anyway).

    Chris had the obvious idea that if someone didn't understand it, they might try pasting it into Google Translate, and tried it. Google Translate renders the sentence into English as ‘Jira issues must not be multiplied beyond necessity’. Very good; I'd have preferred should, but must is acceptable.

    But what's impressive is that if you switch the target language to something else, it turns out that it's not (as I initially assumed) identifying the language as Latin, applying a Latin-to-English translation step, and giving up on the English fragment and passing it through unchanged. No: it actually managed to translate the English part from English, and the Latin part from Latin, both into the specified target language, and as far as I could tell it even got the two fragments in their correct grammatical relationship. I may be out of date with the state of the art, but I was impressed by that!

    Also at Dreamwidth. ( comment count unavailable comments | Leave a comment )

  • 05/03/11--10:28: Murphy strikes again (chan 1676087)
  • When wielding a Stanley knife, I concentrate extremely hard on not cutting myself with the Stanley knife.

    So hard, in fact, that I manage to completely overlook the possibility of cutting a finger on the thumbnail of my other hand. Sigh.

    Also at Dreamwidth. ( comments | Leave a comment )

  • 05/09/11--01:49: Medical farce (chan 1676087)
  • Two weeks ago I tried to make an appointment with my GP. Since it was tedious administrative routine (renewing my prescription for gluten-free pasta, which I still can't bring myself to believe is worth wasting a medical professional's time for in the first place), I didn't think it was worth booking an urgent same-day appointment, and instead tried to book in advance. It turned out they didn't have any advance appointments earlier than a week later – you can have today, or next week, and nothing in between.

    When I arrived for my appointment they said I didn't have one.

    I was not best pleased, but the receptionist was utterly unwilling to do anything to compensate, so the best I could do was to walk away with an appointment card promising me an appointment in another week's time.

    This morning I turned up for that one, and this time I got to see a doctor. However, I still didn't walk away with a prescription in my hand – because all their printers, or at least all the ones they tried, were broken!

    Also at Dreamwidth. ( comments | Leave a comment )

  • 05/11/11--10:15: You couldn't make it up (chan 1676087)
  • Oh, good grief.

    My missing prescription from Monday turned up in the post yesterday, after the surgery got their printers working again.

    I took it to a pharmacy just now – who refused to fill it, because the doctor had (presumably due to the unusual circumstances) forgotten to sign it.

    Also at Dreamwidth. ( comments | Leave a comment )

  • 06/16/11--16:01: Pub poetry (chan 1676087)
  • Crashety-bashety
    Microsoft Windows is
    badly in need of a
    UI that's nice.

    Some feature filed under
    ‘Accessibility’
    makes it superb – but you
    can't find it twice.

    (Brought to you by several pints of Kopparberg and [info]fanf praising the ‘mouse trails’ feature in Windows.)

    Also at Dreamwidth. ( comments | Leave a comment )

  • 06/30/11--12:32: Bah (chan 1676087)
  • A pleasant evening; a good book, a silly iPad game, a nice bowl of soup almost ready to eat, and then the prospect of the pub.

    One ill-judged arm movement later: a fiddly and unpleasant job of cleaning up soup from all over what seems like 3/4 of the kitchen, half my clothes thrown in the wash, a sudden need to find emergency backup dinner, and no realistic prospect of getting to the pub at all. Bah.

    That last point is probably just as well today, I suppose. If I can make this much mess in ten seconds while sober

    Also at Dreamwidth. ( comments | Leave a comment )

  • 07/12/11--13:13: Signs of life (chan 1676087)
  • After over four years, a PuTTY release sees the light!

    But good grief, I had forgotten how much hassle the release process was. I remember having a long and clearly worded checklist to help me through it – and yet I could swear the checklist has somehow bit-rotted over time, so that now it seemed opaque and fiddly.

    (Or perhaps it's just my brain that's rotted.)

    Suddenly I feel a surge of sympathy for the people at work who have to actually ship software to customers.

    Also at Dreamwidth. ( comments | Leave a comment )

  • 09/26/11--05:47: Unexpectedly handy (chan 1676087)
  • Over the last couple of weeks I've been trying to arrange to get a proper lock fitted on my back gate at home: one that you can conveniently open with a key from either side, instead of having to reach through the gate to a fiddly padlock and risk dropping your entire keyring on the wrong side of a gate you can't get through.

    I found an online recommendation for a handyman, and since he had an email contact address listed, I thought I'd do the initial feasibility discussion by email in the hope that it would be less hassle than faffing about with telephones. This turned out to work very well: he was able to send me a URL showing the precise type of lock he suggested would be best, and in return I sent him a URL to a photo I'd just taken of my gate so he could judge whether it was suitable to take that lock without actually having to come and look at it, and then he sent me an official quote for the job as a PDF.

    What I wasn't expecting was that an hour ago, when I was in the Tesco near work buying my lunch, a guy I'd never seen before stopped me in an aisle and asked ‘Are you Simon?’ – and when I spotted the logo on his jacket, I realised he was the handyman himself! He'd found my picture on my website somehow (my guess is by trimming the URL of the photo I'd sent and following links back to my home page, though I suppose it's also possible he might just have googled me), and remembered it well enough to recognise me in passing.

    Also at Dreamwidth. ( comment count unavailable comments | Leave a comment )

  • 10/06/11--11:13: Sometimes I have an idea and then just wish I hadn't (chan 1676087)
  • Many Unix programmers will be familiar with the utility variously called strace, truss, ktrace, dtrace and probably other names too, which logs all communication between a process and the kernel across the system call interface.

    A couple of years ago I wrote an analogous program called xtruss, which produces similar logging but operates at the interface between an X11 client program and the X server. (Of course, that wasn't a new idea; I just liked my version's design better than prior ones, mostly because it behaves more like strace.)

    A related piece of software to strace is Subterfugue, which intercepts system calls using the same underlying technology that strace does, but instead of passively monitoring them, is able to modify the results as it sees fit. The result is a user-scriptable system that allows you to subject a process to all sorts of subtle and not-so-subtle illusions or behaviour modifications; it can be quite tricky to do anything that's both useful and robust with it, but it's potentially pretty powerful. (It's also not been maintained for ages, but that's not relevant to my current train of thought.)

    Today I had the idea: why not fill in the blank in that table, and write the thing that is to xtruss what Subterfugue is to strace? Reuse xtruss's framework for conveniently setting up one-off X11 proxies between a specific application and the X server, and then implement a marshalling and demarshalling layer which translates between wire-encoded X11 messages and an unpacked format that can be accessed by a popular scripting language. Then you could arrange both large and small special effects on X programs, and in particular you could cause them to happen on a per-client basis rather than uniformly across the whole server.

    But that wasn't the idea I started off with. I was actually wondering about a much more specific problem: remapping – and occasional complete destruction – of X keystroke events on a per-application basis, for applications with inadequate built-in keymap configurability. (For instance, I keep accidentally hitting a key combination in my work email client which causes half-composed messages to be sent without confirmation, but I'm unwilling to just define that key combination to be a window-manager hot key for ‘do nothing’ in case I turn out to need it in some totally different application.)

    And since I already have the X proxy framework from xtruss, the thought occurred that I could enhance it just a little to let it rewrite or squash X events, and then I'd have a proxy that would do the thing I wanted; and although this would certainly be a disproportionate effort for the result if I were writing that X proxy from scratch, doing it by slightly modifying code I've already got seemed almost practical by comparison.

    But of course once I'd thought of doing this job by proxying an X connection and rewriting pieces of it, I realised that that certainly wouldn't be the only use for such technology, which led immediately to the idea of a Subterfugue-like general framework.

    And on the one hand that does sound like quite a fun piece of software … and yet, we're now back to it being a huge amount of work to go to for the sake of the one specific application I actually wanted it for, and I'm pretty sure I can't be bothered. But on the other hand, now I've imagined the generic version, I also wouldn't feel right about writing just the one-off utility that only does key mapping (or, worse still, only the specific key mapping I wanted). Bah.

    (There seems a good chance that at least one reader will point out some totally different way in which I could impose keystroke-mangling of my choice on an uncooperative X client. I will be grateful for that, but it won't affect the main point, which is that sometimes having an apparently cool and generalising and elegant idea makes me less happy, and furthermore, bah.)

    Also at Dreamwidth. ( comment count unavailable comments | Leave a comment )

  • 12/07/11--07:45: RepugNaNt (chan 1676087)
  • I had a disgusting thought just now. I needed to have some Python code check whether a dictionary contains a particular key/value pair. The obvious approach,

    if dictionary[key] == value:

    isn't sufficient, because I need to not throw an exception if the dictionary doesn't contain any mapping for that key at all.

    An obvious way is to use a second clause to handle the latter case, so you end up writing

    if key in dictionary and dictionary[key] == value:

    But that's unpleasantly verbose, and also undesirable if dictionary or key is a complicated expression or one with side effects. So I wondered if we could do better.

    Another possibility is to use the get() method of Python dictionaries, which lets you specify a default return value if the dictionary hasn't got the key in question. So you might say, for instance,

    if dictionary.get(key, None) == value:

    But in order to be able to do that, you have to be able to think of a default that will guarantee to compare unequal to value; for instance here, what if the value is None? If you know something about value (e.g. its type) then this is probably feasible one way or another, but one can imagine more general situations in which that wouldn't be the case.

    I think the right answer, in fact, is to write

    if (key, value) in dictionary.viewitems():

    where viewitems() is a standard method which presents the dictionary as if it were a set of ordered pairs. (You could also use dictionary.items(), which would be semantically equivalent, but much slower due to constructing an explicit list and then iterating along it.)

    But before I found the viewitems() method, I thought a bit harder about the get() approach. Perhaps, I thought, I could define a class with a comparison method that always returned false, so that an instance of that class would compare unequal to anything, including itself.

    And then, as I thought the phrase ‘compare unequal to anything, including itself’, a stray neuron fired in my head. I think this would work pretty reliably:

    if dictionary.get(key, float('nan')) == value:

    and its only downside is that it is the most disgusting thing ever! :-)

    Also at Dreamwidth. ( comment count unavailable comments | Leave a comment )

  • 01/03/12--01:38: Forgot my password! (chan 1676087)
  • I got into the office today after a relaxing holiday of three weeks (plus yesterday) and found, embarrassingly, that I couldn't remember my work password any more. I could remember a password, but I was pretty sure it was the one from before my most recent change, and it certainly didn't work when I tried it.

    I can't believe that. First password I've forgotten in over a decade, surely. I had to go and queue outside the IT helpdesk room like a gormless student.

    I had a brief moment of hope when I got back to my desk and found the new password didn't work either. ‘Aha!’ I thought, ‘perhaps the password I'd remembered was right after all, and it's just my desktop computer that's confused.’ But no; after some more faffing, it turned out that password changes are just propagating slowly this morning and I had forgotten my original password after all.

    It's at moments like this I feel that companies ought to have a mechanism whereby you can turn round and go home and back to bed, on the basis that you're likely to do more harm than good if you continue trying to do work.

    Also at Dreamwidth. ( comment count unavailable comments | Leave a comment )