Unknown's avatar

About wjduquette

Author, software engineer, and Lay Dominican.

iGloo: Delayed Creation

One of the particular problems that’s been bugging me is the issue of creating megawidgets in iGloo. A megawidget, of course, is simply an object that acts and looks like a widget; and for an object to act like a widget, it has to have a real Tk widget at its core. The process goes something like this:

First, you decide what to call your widget, remembering that there are definite constraints on what a widget can be called. For the sake of argument we’ll create a widget called .text.

Next, you create a real Tk widget with that name, to serve as the hull of your megawidget:

text .text

Next, you rename the real widget something else:

rename .text _.text

Next, you create your own command called .text. This command should pass most of its subcommands to the hull (_.text), and define any new or modified subcommands it chooses.

proc .text {method args} {
    .
    .
    .
    _.text $method {expand} $args
    .
    .
    .
}

You’ve now got a megawidget, more or less. (As always, the devil is in the details.) I call this process of replacing the widget’s command with my own command hijacking the widget command.

The question is, how can one write a TIP 257 object that does this? It’s a little bit more involved, because you already have a command name when you enter the constructor. Consider the following code snippet, which is part of some code to create a read-only text (rotext) widget:

    constructor {args} {
        my variable hull

        # FIRST, rename [self] to something else, temporarily
        set self [self]
        rename [self] ::_temp$self

        # NEXT, create the Tk widget (remove the ::)
        text [namespace tail $self] {expand}$args

        # NEXT, rename the Tk widget
        set hull ::_$self
        rename $self $hull

        # NEXT, put self back
        rename ::_temp$self $self
    }

As you can see, you need to move your chosen window name out of the way, then create the Tk widget, then move it out of the way, and then put your own command back again. This code works, but it has two problems: first, it doesn’t allow you to hijack a previously existing widget, which is sometimes handy. And second, look what happens when you create your widget:

% rotext .text
::.text
%

Whoops! When you create a TIP 257 object, you get a fully-qualified command name! But when you create a Tk widget, you get back the window name. It’s true that .text and ::.text name the same command; but the first is a window name and the second isn’t.

The problem here is that by the time we enter the constructor the object has already been created. What we’d like is the chance to do a little work before the object is created. And the way you do that is by redefining the rotext class’s create method:

    self.method create {win args} {
        # FIRST, create a text widget with the desired name.
        # (We could also hijack a widget that had already been
        # created.)
        text $win

        # NEXT, rename it to something else.
        set hull ::_$win
        rename $win $hull

        # NEXT, create a new object with the original name, 
        # passing the new name to the constructor.  Note that
        # we add the "::" to make sure the command is created in
        # the global scope.
        next ::$win $hull {expand}$args

        # NEXT, return the bare window name
        return $win
    }

    constructor {theHull args} {
        my variable hull

        # FIRST, save the hull
        set hull $theHull

        # NEXT, pass the options to the hull
        $hull configure {expand}$args
    }

First, we use self.method to define a new create method for our class. We create a text widget, and rename it. Then we use the next command to invoke the superclass’s create method; this will create the object and call its constructor. We insert the Tk widget’s new name into the argument list. The constructor then grabs the Tk widget’s new name and saves it in the instance variable hull, and passes the widget’s options to it.

It remains to redefine the insert and delete methods, and forward the other methods to the real text widget. Here’s the complete example: rotext.tcl.

iGloo: The “mymethod” command

The Problem

It’s common for Snit objects to register callbacks with other objects. For example, a snit::widget might create a Tk button; when the button is pressed, the callback should call one of the widget’s methods. The naive way to do this in the widget’s constructor would be this:

$button configure -command [list $self ButtonPress]

Here, $self is the name of the widget, and so the widget’s ButtonPress method will be called whenever the $button is pressed by the user.

Now, this code will work fine–right up until the moment the programmer decides to rename the widget, as might happen if the programmer applies a snit::widgetadaptor to it. Consequently, Snit provides a way to build callback commands that will continue to call the correct Snit object even if the object’s name changes. The mechanism is the mymethod command:

$button configure -command [mymethod ButtonPress]

mymethod takes the method name, and any additional arguments the programmer cares to provide, and returns a command that’s insensitive to name changes. I won’t go into how the trick is done; it’s ugly (and, by the way, thanks to Andreas Kupries for getting it working right). The question is, what’s the easiest way to do this in the TIP 257 environment?

The “my” Command

In Snit, an object calls its methods via its $self variable, which contains the current name of the object. TIP 257 provides the my command instead. my can be thought of as an alias to the object’s command, an alias that’s always available and never changes its name. That’s not completely true, but it’s good enough for now. Now, every object has a Tcl namespace associated with it; and it happens that my appears as a command in that namespace. By fully qualifying my with its namespace, we gain a command that references the object, whose name won’t ever be changed, and that can be called from outside code. Thus, the following code would do the trick:

$button configure \
    -command [list [self namespace]::my ButtonPress]

We can wrap this in a proc, like so; this will work just fine provided that the proc is visible to the object’s code:

proc mymethod {args} {
    linsert $args 0 [uplevel 1 [list self namespace]]::my
}

And then, there are any number of ways we can make it visible. One slightly tacky method is to put it in the ::oo::Helpers namespace; this namespace is made visible (by namespace path) to all TIP 257 objects. (I call it slightly tacky because it effects all objects, and because the existence of the ::oo::Helpers namespace isn’t part of the TIP 257 spec, at least at the moment.)

A Bonus

There’s a bonus to using this method. In Snit, there’s no real distinction between private and public methods, i.e., methods defined for use solely by the object itself for its own internal processing, and methods that form part of the object’s public interface. TIP 257, however, has the notion of “exported” and “unexported” methods; the latter can only be called using the my command, and hence are reasonably private. But since mymethod as defined above makes use of my, this means that an object’s callbacks can call the object’s unexported, i.e., private methods–which is usually exactly what you want.

iGloo: A Different Kind of Snit

I recently was able to get a hold of a build of Donal Fellow’s Object-Oriented Programming extension for Tcl, familiarly known as “TIP 257“. I helped come up with the spec for TIP 257 last year, but just as no battle plan survives first contact with the enemy, so no software design spec survives implementation unchanged. Consequently I’ve been spending the last few days getting familiar with the revised spec.

The primary goal of TIP 257 is to provide a fast, minimal OOP implementation for the Tcl language which can be used directly and which can also serve as a foundation for significantly less minimal frameworks. One of those less minimal frameworks is my own Snit package, which is available as part of Tcllib. Currently, Snit is doesn’t depend on TIP 257; there are two reasons for making it do so, speed and functionality. Snit is highly optimized, but there are some things that are just slow. TIP 257 does considerably more in C, and consequently should be faster at these things. Second, as object systems go Snit provides the bare bones; for example, it doesn’t allow inheritance (which would be seriously nice to have on occasion). Snit-on-257 might really be Snit-on-steroids.

Now, I’m confident that I can build a Snit-workalike on top of Donal’s API (after all, I can build it without Donal’s API). But there are a number of questions whose answers I need to discover. What compromises and workarounds am I going to have to make to duplicate Snit’s precise syntax and semantics? If I end up with something that has no additional speed and no additional features, there’s no point in it. If I aim at something Snit-like but not precisely identical, can I do significantly better? Are there holes in 257 where a little more functionality would be a really big help? Are there aspects of 257 that cause me serious problems?

To answer these questions, I’m embarking on a project called iGloo, a name I came up with a couple of years ago when Snit was gaining in popularity and I had begun to wish I’d called it something else. If I decide that it’s worth doing a perfect clone of Snit on top of 257, iGloo might just be a research project. If I decide that perfect compatibility with Snit is too constraining, iGloo might go on to be Snit’s replacement. Either way, it should be fun.

The 50 Most Significant SF&F Books

Michael came across this list of the 50 most significant SF&F books of the last 50 years at this website here; apparently the list came from somewhere else, though it’s not clear to me where. The books are listed in order; I’ve bold-faced the ones I’ve read, and added some comments. I’ve put “+++” by the ones I’ve read multiple times, “—” by the ones I’ve read but didn’t much like, and “000” by the ones I’ve read that I can’t remember anything about. As you’ll see, I’ve read 40 of the 50, and at least tried to read most of the others.

  1. +++ The Lord of the Rings, J.R.R. Tolkien.
  2. +++ The Foundation Trilogy, Isaac Asimov.
  3. +++ Dune, Frank Herbert.
  4. +++ Stranger in a Strange Land, Robert A. Heinlein.
  5. +++ A Wizard of Earthsea, Ursula K. Le Guin.
  6. Neuromancer, William Gibson. I started this one, and hated it,
    and never finished it. This almost never happens.
  7. +++ Childhood’s End, Arthur C. Clarke.
  8. Do Androids Dream of Electric Sheep?, Philip K. Dick. I’ve
    read a little of Dick’s work, and didn’t like it, so I never tried
    this one.
  9. The Mists of Avalon, Marion Zimmer Bradley. I’ve read a fair
    amount of Bradley’s “Darkover” series; I’m not sure why I’ve never
    read this one. It seems to be targetted more at women than men, though.
  10. Fahrenheit 451, Ray Bradbury.
  11. +++ The Book of the New Sun, Gene Wolfe.
  12. +++ A Canticle for Leibowitz, Walter M. Miller, Jr..
  13. The Caves of Steel, Isaac Asimov.
  14. Children of the Atom, Wilmar Shiras Never heard of this one.
  15. +++ Cities in Flight, James Blish.
  16. +++ The Colour of Magic, Terry Pratchett. Though this is hardly the best of the series.
  17. Dangerous Visions, edited by Harlan Ellison.
  18. Deathbird Stories, Harlan Ellison.
  19. +++ The Demolished Man, Alfred Bester.
  20. Dhalgren, Samuel R. Delany. Couldn’t get through this one, either.
  21. +++ Dragonflight, Anne McCaffrey.
  22. Ender’s Game, Orson Scott Card. The short story is better.
  23. +++ The First Chronicles of Thomas Covenant the Unbeliever, Stephen R. Donaldson.
  24. 000 The Forever War, Joe Haldeman.
  25. Gateway, Frederik Pohl. I’ve never read anything by Pohl that
    I cordially liked.
  26. +++ Harry Potter and the Philosopher’s Stone, J.K. Rowling.
  27. +++ The Hitchhiker’s Guide to the Galaxy, Douglas Adams.
  28. I Am Legend, Richard Matheson.
  29. — Interview with the Vampire, Anne Rice.
  30. +++ The Left Hand of Darkness, Ursula K. Le Guin.
  31. Little, Big, John Crowley. I’ve tried to re-read this several times, and never gotten very far. Interesting, but I don’t think I ever really understood what was going on.
  32. +++ Lord of Light, Roger Zelazny.
  33. The Man in the High Castle, Philip K. Dick. See above.
  34. Mission of Gravity, Hal Clement.
  35. More Than Human, Theodore Sturgeon. I don’t remember whether
    I’ve read this one or not.
  36. +++ The Rediscovery of Man, Cordwainer Smith.
  37. On the Beach, Nevil Shute. Oddly, I’ve not read this one; I
    tried it when I was far too young, and didn’t like it. I ought to
    give it another try.
  38. +++ Rendezvous with Rama, Arthur C. Clarke.
  39. +++ Ringworld, Larry Niven.
  40. 000 Rogue Moon, Algis Budrys.
  41. +++ The Silmarillion, J.R.R. Tolkien.
  42. 000 Slaughterhouse-5, Kurt Vonnegut.
  43. Snow Crash, Neal Stephenson.
  44. +++ Stand on Zanzibar, John Brunner.
  45. The Stars My Destination, Alfred Bester.
  46. +++ Starship Troopers, Robert A. Heinlein.
  47. +++ Stormbringer, Michael Moorcock.
  48. — The Sword of Shannara, Terry Brooks.
  49. Timescape, Gregory Benford. Like Pohl, Benford does nothing
    for me.
  50. — To Your Scattered Bodies Go, Philip Jose Farmer.

Something Rotten, by Jasper Fforde

This is the latest of Fforde’s very funny “Thursday Next” series, which also includes The Eyre Affair, Lost in a Good Book, and The Well of Lost Plots. In this book, Thursday returns to the Real World after an absence of two-and-a-half years. She’s got Hamlet, Prince of Denmark in tow; it seems that he and Ophelia have had a falling out, and Ophelia needs a little space. Meanwhile, page-runner Yorrick Kaine is trying to take over England with the help of the Goliath Corporation, and Thursday’s time-hopping father needs her help to prevent the resulting world cataclysm. In short, it’s a typical Thursday Next book.

The first of the series was outstanding; the second was also quite good; the third had its problems; and this one does too. In particular, it starts slowly–say that again, even more slowly–so slowly that it took me several weeks to get through it. The ending was OK, and I’m curious to see what comes next; but action-wise, this book is clearly the low point in the series to date.

Fun With Perspective

Ted the Test Lead has impressed on me that it’s very hard to take good architectural pictures with a standard camera (unless you buy a really expensive perspective-correcting lens). Here’s an example of what he’s talking about.

20061018-165655.jpg

I took this picture from across the street. Note that the left-hand side of the building and the flag pole are both vertical in this picture, as they should be….but the rest of the building looks remarkably funny.

Dust Bunnies, or, Draining the Mote

So yesterday I got a second lens for my DSLR, a Nikon 50mm F/1.8. I got this lens for a number of reasons. First, it’s a prime rather than zoom, i.e., it has only one focal length. I wanted to try living with a single focal length for a while; lots of people have recommended this as a good way to get a feel for what different focal lengths can do for you. Second, it’s much “faster”, i.e., it has a wider maximum aperture, than my other lens. Third, I’ve heard extremely good things about it; optically, it’s considered to be very good. Fourth, for a lens it’s dirt cheap, which means that I could squeak it into my budget.

So today I took it out shooting. And I happened to take this picture of some power towers on the ridge line, and I happened to take it at F/22 (minimum aperture) just to see what would happen:

20061022-160159.jpg

And what happened, I’m afraid, was Dust Bunnies. See those black spots in the sky? The two most noticeable are on the left side. Here’s a close-up, just for smiles:

20061022-160159_crop.jpg

Can you see them now? What those are, is dust particles on the camera’s sensor. See, the sensor gets electro-statically charged, and that attracts dust. And since you can swap lenses, dust can get in. So you get dust on the sensor. I don’t know if this dust was there when I bought the camera, or whether it moved in afterwards; but I’ve not removed the lens all that often, so I suspect it was there to begin with. It’s just hard to see except against a bright, plain background with a small aperture, and I’ve not taken many pictures like that to date…that came out, anyway (you remember, I had this problem with my lens diaphragm….).

Anyway, so what to do? It’s possible to remove these with the Clone Tool in Photoshop Elements…ugh. I can send the camera in to be cleaned; I gather that it’s not uncommon for new cameras to have dirty sensors, and that Nikon will clean it once for free; after that it’s $40. Plus shipping. Plus two weeks travel time. Ugh. My sources indicate that this will be a recurring problem; it’s something I’m simply going to have to deal with.

There are ways to clean the sensor yourself, and I’ve been looking into those. The best articles I’ve seen have been at The Luminous Landscape, a photography site run by landscape photographer Michael Reichmann. He discusses a couple of methods that I’m going to have to look into, given that my house is a dust magnet.

Epiphany

I’m used to looking at the pictures I take one at a time, rather than side-by-side. Whilst at soccer practice this evening, I took a bunch of photos of the sunset and of things lit by the sunset. Later I looked at them several times–one at a time–and as usual had trouble deciding which I liked best. Some were, as usual, clearly not so good; but also as usual, some were close enough that I just wasn’t sure. After a while, though, I managed to weed most of them out.

Then I went into LightZone to edit one of them. By default, LightZone shows you a set of large thumbnails of the photos in the directory. Suddenly I could see all of them side-by-side. And I was amazed at how a few of the twelve pictures I’d kept simply jumped out at me. They were clearly better than the others.

I’m going to have spend more time looking my virtual contact sheets on a virtual light table.

(Oh, here’s the picture I wanted to fix up.)

20061019-174340_web.jpg