August 29, 2003

Declarative Semantics

This post came out of the Blue Sky discussion. The disclaimer for that discussion applies here as well. I expect you to roll your eyes at how impractical it is.

Suppose I write "get http://www.kimbly.com/" in a program, exactly as shown. It won't compile in nearly any programming language. I have to write something more like this:

    url = new URL("http://www.kimbly.com/")
    url.get()

Having a reusable URL class is a lot better than having to work with sockets, but there's still a lot of noise there. From the user's perspective, I have to "quote" the url to turn it into a "string", and then I have to "pass" that string to the "constructor" of a "class". Then I "call" a "method" on the "object" that the constructor "returned". And so on. This is the price of modeling.

Application programmers shouldn't have to do modelling. Once a concept has been added to a library, the programmer should be able to talk about things directly, without having to use programming-language abstractions. This is Blue Sky.

Unfortunately I don't know of any good ways to express the semantics of "get http://www.kimbly.com/". I could make a macro that would let the literal code compile into something, but what should it evaluate as? An anonymous function? A string containing the html source? A structured object that lets me request the title and so on? Any decision would be premature, because URLs in themselves are not about executable code. They're not an algorithm, or a data structure. They're just a concept.

We don't have any well-known techniques for working with abstract concepts like this -- instead, the macro writer is forced to decide on a single executable "meaning". They decide whether "get <url>" should mean eagerly fetching the url or looking it up in a cache, whether it should mean parsing the result or just leaving it as a string, and whether the whole thing should be stored in memory or written to disk.

There is no way for me to write a declarative description of what a URL really is in a way that a programming language could understand. I want to be able to explain that it's not only a string of letters, but that it can be meaningfully broken into pieces (protocol, host, port, path) that may or may not be relevant. I want to be able to explain its relationship with the HTTP protocol. And I want to explain these things in a declarative way -- more like a knowledge base than a code library.

In fact, I want even more than that. I want other people to be able to add to, refine, or even override the statements that I made about URLs. You have to stop modeling at some point or else you'll never get anything done -- but maybe my model of URLs stopped too soon for some purposes. Perhaps I didn't care to mention 404s, or character set encoding. Someone else should be able to add declarative statements to my description, without requiring my cooperation, and without having to completely recreate my model. RDF is kind of like this, in that it lets people add new predicates and new statements, without having to coordinate with each other.

Currently, programming languages map concrete syntax into abstract programming-language concepts, which then get mapped into machine code. Application programmers never work with their problems directly -- instead, they work indirectly, by referring to and manipulating programming-language concepts like functions, objects, and types. At no point do they ever actually refer to the problem domain itself. I want to change this so that syntax instead maps to problem domain concepts, which then map to programming-domain concepts and so on to machine code. And I want to keep all the mappings separate.

I don't know exactly how to implement this idea (it is Blue Sky, after all), but I do have an intuitive feeling that it doesn't have to be as hard as we might think -- especially if you allow models to be incomplete, over-simplified, and even wrong sometimes.

Posted by kimbly at 03:00 PM | Comments (7) | TrackBack

August 28, 2003

Async Methods in .NET

Yesterday I had to rewrite some C# code at work. We were trying to send a message to a webserver without waiting for a response, but for some reason it would hang after only sending a couple messages. I ended up rewriting it to use asynchronous sockets instead of the WebRequest class.

After I had it working, I realized that while the Begin/End pattern that .NET uses for asynchronous operations is better than not having any asychronous ability at all, it would be even better if it had some kind of syntactic support for this, instead of using callback methods.

Here's the code I ended up writing, using callbacks:

    public void log (LogEntry entry) {
        string logString = logEntryToString(entry);
        try {
            Socket s = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);
            IPAddress ipAddr = Dns.Resolve(m_host).AddressList[0];
            s.BeginConnect(new IPEndPoint(ipAddr, m_port),
                new AsyncCallback(this.finishAsyncLog),
                new Pair(s, logString));
        }
        catch (Exception e) {
            throw new LogException("Problem connecting to log server: "+
                e.Message + " (Log entry: " + logString + ")");
        }
    }

    private void finishAsyncLog(IAsyncResult result) {
        Pair state = (Pair)result.AsyncState;
        Socket s = (Socket)state.First;
        string logString = (string)state.Second;

        try {
            s.EndConnect(result);

            string encodedString = "/log?pairs=" +
                System.Web.HttpUtility.UrlEncode(logString,
                new UTF8Encoding(false));

            string httpRequest = "GET /log?" + logString + "\r\n\r\n";
            Byte[] ByteGet = Encoding.ASCII.GetBytes(httpRequest);
            s.Send(ByteGet, ByteGet.Length, SocketFlags.None);

            s.Close();
        }
        catch (Exception e) {
            Console.WriteLine("Problem connecting to log server: "+
                e.Message + " (Log entry: " + logString + ")");
        }
    }

Notice how I had to break the log() method into two pieces -- one to start the asynchronous operation, and one to finish it. I also had to bundle up a couple local variables into a Pair object, so that I could pass both of them to the callback method (which only takes one state object). If C# and .NET had been designed with some kind of fork or coroutine or continuation facility, the code might have looked more like this:

    public void log (LogEntry entry) {
        string logString = logEntryToString(entry);
        try {
            Socket s = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);
            IPAddress ipAddr = Dns.Resolve(m_host).AddressList[0];
            IPEndPoint ep = new IPEndPoint(ipAddr, m_port);
            callAsync(s.Connect(ep)) {
                string encodedString = "/log?pairs=" +
                    System.Web.HttpUtility.UrlEncode(logString,
                    new UTF8Encoding(false));
                string httpRequest = "GET " + encodedString + "\r\n\r\n";
                Byte[] ByteGet = Encoding.ASCII.GetBytes(httpRequest);
                s.Send(ByteGet, ByteGet.Length, SocketFlags.None);

                s.Close();
            }
        }
        catch (Exception e) {
            throw new LogException("Problem connecting to log server: "+
                e.Message + " (Log entry: " + logString + ")");
        }
    }

This would be much cleaner -- it's only one method instead of two and I don't have to do any games to package up my local variables. But it does have the drawback of not making it clear that after the socket is connected, the code will be running in a different thread than it started in. It's also not clear whether the catch should apply to the asynchronous code or not. So I suppose it was the right decision for the designers of .NET to use callbacks, but it's still unfortunate that we couldn't have had a more sophisticated solution.

Posted by kimbly at 10:50 AM | Comments (5) | TrackBack

August 25, 2003

La Favola d'Orfeo

While reading my history book a couple weeks ago, I came across a mention of Monteverdi's opera, La favola d'Orfeo (The Fable of Orpheus) as being the first "real" opera. I mentioned it to someone at work who's into opera, and he replied that he happened to have a CD of it right there with him. He offered to let me listen to it, and since then I've been listening and re-listening to it several times a day. I never knew that I could like opera -- I haven't really liked any other opera that I've heard so far. I think I like it because the instrumental parts are of an earlier style than most operas.

I want to share a snippet of it, so that you know what it sounds like. This part doesn't have any actual singing (it's just instrumentals) but it's one of my favorite parts. You have to listen to the whole thing -- it repeats, and has a fuller, richer tone the second time around. I assume that quoting just 80 seconds of a recording falls under fair use, and so I can share it with you without violating copyright. If you enjoy it, I encourage you to buy the CD.

Listen and enjoy. (Note: if you hear a background hissing in the recording, try saving it to disk first).

Posted by kimbly at 06:54 PM | Comments (1) | TrackBack

Reducing Bug Counts

Jason Marshall has a good point:

Let us conjecture that 2 bugs take as many man-hours to fix as implementing the feature did. That's only 2 units of effort expended toward new development for every 5 available. If you could eliminate one bug per feature, that would mean 2 units out of every 4 go to new features. That's a 25% gain in productivity, and that's not counting the psychological benefits of spending less time cleaning up old code, and the political capital of appearing more professional to the rest of the organization.

Unfortunately, I find that my bugs usually only take about a tenth as much time to fix as implementing the actual features. This could mean several things. Maybe I have already achieved low bug counts. Or maybe I just spend way too long implementing features.

It's still a good point, though.

Posted by kimbly at 03:59 PM | Comments (0) | TrackBack

August 24, 2003

Coding

My mom is a doctor. I was talking to her the other day, and I casually mentioned that I had done some coding on the weekend. She looked at me in horror, and it took her a few seconds to understand what I meant.

To her, "coding" means having a heart attack.

Posted by kimbly at 06:27 PM | Comments (1) | TrackBack

August 22, 2003

Reader Feedback

I recently passed the 100-post threshold, so now it's feedback time, y'all. Why do you read my blog? What's good, what's bad, what would be better? I know from the referrer logs that I have about 15 regular readers (depending on your definition of "regular"), but I want to connect humans to IP addresses. So now's the time to introduce yourself, and provide that meta-level commentary that you've been storing up. Talk amongst yourselves :)

Posted by kimbly at 07:26 PM | Comments (9) | TrackBack

Wiki Diamond Posts

I've made an index of all the wiki diamond project posts.

Posted by kimbly at 07:13 PM | Comments (0) | TrackBack

Job Market Sucks

Anecdotal evidence that the US job market sucks for techies right now. No mention of where in the country this anecdote comes from, though.

Posted by kimbly at 09:57 AM | Comments (0) | TrackBack

August 21, 2003

Put it in the Syntax

I just came across this musing by Graydon Hoare:

I have an ongoing thesis at the moment which I'm exploring in the programming language literature, which is that programming language features do well (all other things being equal) when they eliminate either distant or dynamic state and replace it with either close or lexical state. the underlying point being that we may favour language features that facilitate copying and modifying small bits of code -- fragments which work in their new context -- as a fundamental programming activity.

Yeah, what he said! I'm now going to ramble through some less-than-half-baked ideas that have been going through my head recently. I hope you'll take what you can, and forgive the rest.

Just a couple days ago at work, inspired by the Objects Have Failed paper by Richard Gabriel, and the C History paper by Dennis Ritchie, I was blue-skying about how one could create a radically simpler programming language. I wrote the following on my whiteboard:

  • avoid computation
  • avoid state
  • avoid indirection

At work about a year ago, I designed a language for coordinating clusters of computers in production, which has been moderately successful. That language was designed to be obvious to non-programmers, and so it has no state, no computation, and only grudgingly allows indirection (although it's surprising how close you can get to simulating computation if all you're given is indirection).

Note that all data structures are a form of indirection, even if they're immutable, like in functional languages. As soon as the data structure forgets where it came from (i.e. where it was created), it has become indirect. In fact, I could go even further: as soon as an immediate, direct concept like a person gets abstracted into a non-immediate concept like a social security number, you've paid the price of indirection. Really indirection is just one form of abstraction, although it's an especially confusing one. Abstraction is confusing.

My blue-sky language had a couple other points on the whiteboard besides the "avoid"s above:

  • handle hierarchy
  • handle associations
  • handle collections

  • prefer isomorphisms to transforms

By hierarchy, I was thinking of things like XML and XPath. By associations, I was thinking of things like containment relationships (e.g. between objects and their members), bidirectional relationships (e.g. tables in a relational database), and meta relationships (e.g. RDF). I think you know what I meant by collections.

I think the "isomorphisms vs transforms" part might be incomprehensible without explanation. By "transforms", I meant things like XSL stylesheets which cannot be undone once they're applied, or taking data from a database and presenting it in a UI without without keeping track of where that data came from.

An isomorphism, in contrast to a transform, is reversible. If I have a UI presenting a list of things that came from a database table, then an isomorphism will preserve that relationship, so that when I click on an item in the list, I can immediately traverse back to the database row that the item came from. Since they're isomorphic, you can actually think of them as the "same thing", just with two different representations.

In most modern languages, if I want to traverse from a UI element back to a database element, I'm forced to store some kind of primary key along with the UI elements. If I'm lucky I can use a language that lets me store this extra info as an extra member variable on the UI element -- otherwise I need to create a parallel array to hold the extra info. But it would be more intuitive if I didn't have to forsake the immediately-obvious idea of a "record" and exchange it for the weak, abstract concept of a "record id".

[Aside: This ties in with my belief that an ideal language would not use plain integers to index into lists -- instead it would use a type that is clearly tied to the list that it is an index into. I hardly ever want to do arithmetic on list indices (other than incrementing them to get the next item). So treating list indices as plain old integers is as primitive and brutal as the way that C treats pointers like plain old integers.]

What's the big deal about using isomorphisms as opposed to transforms? I think they help you avoid indirection. And I think indirection is the root of all complexity.

It's interesting that programming-language afficionados, especially the elite ones (i.e. the ones that like functional languages) tend to love adding new features to their languages, but that they do this by increasing indirection and abstraction. Parameterized types, virtual methods, function pointers, closures, continuations, etc. All of these things make programs harder to understand. Yes, they add a lot of power, but I think we should focus on making programs more powerful without having to resort to more abstractions to do it. We should be gaining power by removing layers of abstraction, rather than by adding more layers to cope with the inadequacies of the existing layers.

Amusingly, a lot of programmers hate lisp-style macros because they think they make programs harder to read. I completely disagree. I think macros decrease the level of abstraction in a program. They make the syntax more directly-meaningful, closer to the problem domain. Which brings us back to the quote by Graydon I started this post with.

Posted by kimbly at 07:44 PM | Comments (15) | TrackBack

August 20, 2003

Bayesian Categorization

Another idea for the wiki diamond project. Use bayesian filters to automatically suggest how to classify new entries, given a set of existing documents that have already been classified. This would presumably be more reliable than auto-classification techniques, since auto-classification schemes usually don't have any specific knowledge about your particular set of documents.

Or perhaps a clustering algorithm would be more useful -- so that after I've written, say, five entries on the wiki diamond project, it suggests creating a category for them all.

Once you have bayesian filters, it might be interesting to occasionally rerun them on older documents, in case the categorization taxonomy has changed enough that the old documents should be recategorized. Perhaps the old documents were simply classified under "programming languages" even though you've since split that category into "Java", "Perl", etc.

A list of articles related to this one is here.

Posted by kimbly at 06:31 PM | Comments (0) | TrackBack

August 18, 2003

Alternative Currencies

Via Oblomovka, here's an interview with Bernard Lietaer, on how the current money system isn't working and is causing a lot of political destabilization in third-world countries. He gives examples of how alternate currencies can solve social problems (e.g. care of the elderly), and bootstrap economies where regular money is scarce (e.g. ghettos and student communities).

There is typically a reluctance among friends to pay for help provided by using national currency. If a friend is helping you move or paint and you pay him with national currency, it just doesn't feel right... It turns out that dollar exchanges tend to be incompatible with a gift economy. Complementary currencies are.

This line of thought seems very relevant to the Open Source and Free Sofware communities. The idea is that conventional currencies encourage competition, while time-dollar currencies can encourage cooperation.

Posted by kimbly at 03:40 PM | Comments (1) | TrackBack

Economics

Brad DeLong has had a series of interesting blog posts recently.

First, he links to a PhD thesis by Petra Moser, which claims that patent protection causes investors to direct more investment to industries covered by patents than in other industries.

Inventors in countries without patent laws concentrated in industries where secrecy was effective relative to patents, e.g., food processing and scientific instruments. These results suggest that introducing strong and effective patent laws in countries without patents may have stronger effects on changing the direction of innovative activity than on raising the number of innovations.

Next, he provides a pointer to a discussion on the need for both heders (producers and consumers) and speculators (traders) in markets. Hedgers have tacit knowledge of the underlying commodity, while speculators provide liquidity. Successful markets must have both. The argument claims that the terrorism market probably wouldn't have worked because there would have been no hedgers to act as producers of terrorism (terrorists themselves wouldn't have participated).

He then goes on to discuss the "Exhorbitant Priviledges" that the U.S. enjoys because it provides the key international currency. One priviledge is that because the world economy is growing, we can simply print money to pay for our debts, without incurring as much inflation as other countries would. Another priviledge is that because we're politically stable, rich people in other countries invest in the dollar as a hedge against instability in their own government, thereby increasing demand. In effect, we're "exporting" political stability as well as worldwide growth potential, and these exports can compensate for some of our trade imbalance.

And finally, he wraps up with his recurring theme about productivity. Productivity is growing so fast these days that the US economy will have to grow at least 4% a year just to hold on to the jobs it already has. Lots of of interesting historical charts to gaze upon. Apparently we're in a very odd time, where productivity is growing even though employment is decreasing.

Posted by kimbly at 01:54 PM | Comments (0) | TrackBack

August 15, 2003

RDF/XML is Readable

Here's an interesting discussion of whether RDF/XML is readable, compared to a custom-made XML syntax for Atom.

My first reaction to this discussion was that when I looked through the example RDF/XML on that page, it seemed pretty straightforward, assuming you're familiar with namespaces. I like how it's able to combine vocabularies from multiple standards (e.g. Dublin Core, FOAF, and XML itself).

My second reaction was that the debate over whether to use RDF or not is very similar to the static- versus dynamic-typing debate. RDF is the equivalent of static typing, and plain-old-XML is the equivalent of dynamic typing. It all comes down to how much the computer is able to understand about what the code/content is supposed to mean. It's interesting to note that most static-typing afficionados these days prefer type inference to explicit type declarations, but RDF/XML is still at the explicit declaration stage. It might be interesting to follow this train of thought further.

My third reaction was that those who are complaining about how RDF isn't as readable as the plain-old-XML syntax should really wake up and realize that even their simpler format is still XML. XML is not readable, people! Give it up!

Also, Bill de hÓra makes a good point that the syntax used to represent RDF is, in a way, more important than the semantics, when it comes to actually writing software that uses RDF.

Posted by kimbly at 11:34 AM | Comments (0) | TrackBack

August 14, 2003

Movable Type Busted

Ugh, my Movable Type database seems to have gotten corrupted. You might notice that there are three posts from April at the bottom of the front-page right now. I haven't gotten any help from the support forums yet. I'll probably have to end up reinstalling Movable Type from scratch -- fortunately it's still able to limp along enough to export all my entries, although I had to comment out some error handling in the perl code in order to coax it into rebuilding my index pages.

If I were to do this again, I think I would use a simpler system. Preferably one that allows me to regenerate everything from plain old files. I don't mind databases as long as they're not where the source code is kept. I'll keep this in mind if I ever get around to writing a new bliki system...

Posted by kimbly at 04:59 PM | Comments (0) | TrackBack

RDF and Diamond Wiki

I've started learning RDF, and I think it's a pretty good match for my bliki-with-refinements idea. Of course this only makes sense, since refinements thrive on metadata, and RDF is a generic mechanism for encoding metadata. But there are some non-obvious observations that make RDF especially interesting.

First, you have to remember that the kind of site I'm envisioning is based on a front page that consists simply of a collection of items -- e.g. all the blog posts you've ever made. Refinements are simply hyperlinks that restrict your view to a subset of these items -- for example, all the posts made in August. In RDF terms, you're restricting yourself to the set of posts which are the subject of a "Month Posted" predicate whose object is "August".

You can group refinements by the name of the predicate. E.g. you could have a group called "Month Posted", with values for "August", "July", "June", etc. This provides the kind of grouping that you can see in the Tower Records example (where they group by genre, composer, media, price, etc).

You can also use RDF to specify hierarchy. For example, that "August 14, 2003" should be subordinate to "August 2003", which is subordinate to "2003".

But the coolest thing about using RDF is that it's not limited to predicates whose objects are simple values. You can also have objects that are themselves subjects of other predicates. This would let you create predicates like "Next" and "Previous", which link one post to another. This is one area where the company I work at is a bit weak -- once you get to a particular item (post), you're all on your own, with no metadata other than the data about that particular post. There's no inter-item metadata at all.

Lastly, RDF provides a great way for the site to expose the metadata it's using back to the world. It could embed the RDF about items right into the page, so that the world at large could use that metadata as well. Bring on the Semantic Web, hey?

A list of articles related to this one is here.

Posted by kimbly at 04:50 PM | Comments (0) | TrackBack

August 12, 2003

N3

N3 is a notation designed to make writing RDF easier. (For those who don't know offhand, RDF is a standard for encoding predicate data in XML).

N3 has some interesting features. For example, it views the "." operator in OO languages as a graph traversal operator, and then promptly provides a "^" operator that traverses the graph in the opposite direction -- something that OO languages cannot do because of the underlying memory model of references and pointers.

Perhaps the most interesting thing about N3 is that it's a notation for a predicate-based data store, designed by someone whose apparent background is closer to C++ and Lisp than to Prolog. As such, it takes concepts from C++ and Lisp and mutates them in ways that force the programmer to think of those concepts in a very different light.

Posted by kimbly at 08:40 PM | Comments (0) | TrackBack

August 10, 2003

Adaptive Navigation

Nova Spivack has a worthy goal:

... a self-organizing blog/wiki. You just type stuff and it congeals around the main topics. Call it "Adaptive Navigation" -- The navigational structure changes to reflect what you are interested in and how those interests change over time.

This is the same problem that I faced when thinking about my history project idea, although I was willing to expend some organizational effort in order to create potential navigational structures. My ramblings about refinements are just one possible technique for heading in this direction.

Nova's article is short on constructive proposals, but as a long-term goal it's right on target.

I'm in work-crunch mode for the next couple weeks, but maybe after that I'll have some time to play with these ideas.

Posted by kimbly at 09:50 PM | Comments (0) | TrackBack

August 08, 2003

CSS Zen Garden

The CSS Zen Garden is really excellent. I feel a sense of peace coming over me -- good design refreshes like nothing else.

If you haven't seen it, go now. Click. Enjoy. Breathe.

Posted by kimbly at 07:50 PM | Comments (1) | TrackBack

Motivation

Today's lesson: if you never make an effort to do anything, you'll get bored out of your mind. A life of leisure is neither fun nor rewarding.

If you're bored and unmotivated at work, and you've been spending your time surfing the web looking desperately for something more interesting, you may be stuck in a vicious circle. If you're bored with work and try to avoid doing it, you will become even more bored. That sense of boredom will permeate the work you're not doing, making you feel like the work itself is boring, which makes you try even harder to avoid doing it. (There's a chicken and egg problem here -- does the boredom come first, or the avoidance?)

If you find yourself needing, desperately, to work on something more interesting, then you may be stuck in this trap. If you begin to feel like your skills are atrophying due to lack of challenge, then you may be stuck in this trap. If you resent every little difficulty you encounter while working, because it means you actually have to pay attention to what you're doing, then you are probably stuck in this trap.

The only way to get out of this is to realize two things: 1) that moods are largely self-reinforcing, and 2) that if you don't actually put effort into doing something -- anything -- then you will be bored. Follow the chain of cause and effect backwards, and realize that it's your own damn fault you're going crazy.

Paying attention to something boring is like doing exercise -- at first, you hate it and you'd really rather go back to sleep. But eventually the endorphin high will hit you, and maybe it'll get you high enough to get out of your funk. After all, there's a reason you decided to become a programmer in the first place, right? You like programming. The endorphins are there waiting for you -- all you have to do is put in enough energy to shake them loose.

They feel so good...

Posted by kimbly at 04:58 PM | Comments (1) | TrackBack

August 06, 2003

What are Refinements?

I've gotten a couple people asking me what exactly I mean by "refinements". So let me try to explain them more clearly. They're difficult to describe without an example, so let's use Tower Records Classical Music as an example. That link will open in a new window, so you can follow along.

Notice that on the left-hand side of that page you have a selection of several ways to "Refine" your search. You can refine by Genre, Price, Composer, Musical Period, etc. Suppose we click on Opera. Now we can click into sub-genres of opera like Aria, Arietta, etc. So there's an example of using hierarchy (Arietta is below Opera).

But suppose we don't want to just refine by the type of music; we also want to narrow down to cheap music. So click on Under $7. Notice that there are still several refinements we could choose, although the Format section now only has "Used CD" -- I guess the "Super Audio CDs" were all more than $7.

This is what I mean by refinements -- the way that the website offers up more and more categories that I can use to restrict my search. Notice that it doesn't suggest anything that would lead to a dead end -- that's why once I've chosen "Under $7", I don't get "Super Audio CD" as an option anymore.

Basically what the site is doing is going through the currently selected set of music, and seeing whether there are any subsets that might be of interest. Everytime I click a refinement, I'm limiting myself to a subset of my current selection. Opera was a subset of all classical music, and Under $7 was a subset of Opera music.

I could continue on like this until I got to a small enough number of CD's that I could actually browse through the list and choose one I might like. When we started, there were 56,836 cd's selected. After restricting to Opera, there were only 11,141. After Under $7, there were only 966. If I further restrict my search to "In Stock" and "Live Recordings", then there are only 29 left -- few enough that I can actually browse through them.

I want to emphasize that the point of refinements is that the user does not have to go to a search page in order to get them. They're simply sitting there on the left-hand side, waiting for the user to click. A search page requires the user to think like a programmer, while refinements just require them to act like a regular web surfer.

A list of articles related to this one is here.

Posted by kimbly at 10:50 AM | Comments (1) | TrackBack

August 05, 2003

Following Parrot

Here's a useful weekly summary of Perl 6 and Parrot, by Piers Cawley. I've put the link in my list of things to check every week or so.

I really, really hope Parrot works out. It would be great if all the open-source dynamic languages could pool their libraries. Hopefully it would also fuel language innovation, since you wouldn't need to rewrite all of your libraries from scratch.

Posted by kimbly at 07:44 PM | Comments (0) | TrackBack

August 04, 2003

Wikis Aren't Enough

In response to my post on a faceted classification web framework, Bill de Hóra pointed out that wikis can do classification already, via backlinks. But there are a couple of ways in which wikis don't live up to what I'm envisioning.

First, wikis don't suggest refinements (other categories which could be intersected with the current category in order to narrow the search). Second, wikis don't do hierarchical categories. The combination of both of these features enables a qualitatively different kind of site.

For example, imagine if someone said that wikis can do everything weblogs do, because you just have to use the RecentChanges page to get a chronological listing. Well, yes, that's kind of true in a sense, but it would be qualitatively different from a weblog.

Update: a list of articles related to this one is here.

Posted by kimbly at 07:47 PM | Comments (9) | TrackBack

Fuck You, Bush

Bush Hunts for Way to Doom Gay Marriages.

I cannot comprehend how anyone could fail to see that this kind of behavior is exactly analogous to the racial, sexual, and religious persecutions of the past. I'm willing to believe that Bush may also be racist and sexist, but at least he doesn't espouse those opinions in public. By what hateful, schizophrenic logic is it acceptable for the President to advocate discriminating against gays, considering that he'd be impeached if he tried it with black, jewish, or japanese people?

It is only because of the complacency of the people that this kind of excrement can be spoken publically without shame. Therefore if you, reader, think that there's anything reasonable or rational about a politician proclaiming that marriage needs to be "protected", or that gay adoption is "doing violence to children", then fuck you too. You are my persecutor. If you feel anything short of disgust at Bush's stance on homosexuality, then I find you personally repugnant.

Posted by kimbly at 06:34 PM | Comments (27) | TrackBack

Posted by kimbly at

Posted by kimbly at

Posted by kimbly at